# Vibe Coding Will Never Be Engineering

> Source: <https://phroneses.com/articles/build/notes/vibe-coding-is-not-engineering.html>
> Published: 2026-05-29 00:00:00+00:00

Engineering is a discipline. Vibe coding is the input.

If you want your AI-generated code to become a long-term product, there are software engineering topics that you will have to address. If you do not address them you will find that your progress stalls because features start to break each other, system state becomes unpredictable, managing your code becomes impossible, deployment becomes a barrier, error messages stop making sense, and simple features become hard to add. This leads to a collapse in confidence.

When engineers write code, they are not just typing. They are resolving ambiguity, defining boundaries, modelling behaviour, and deciding how the system should work under stress.

Most of this happens before a single line of code exists, and it is the reason human-authored software remains stable as it grows.

Vibe coding skips these steps because the AI will happily generate code without them. The system, however, still depends on those decisions having been made. If you do not resolve them upfront, you end up resolving them later under pressure, while cleaning up fragility you never planned for.

A system is more than the text that implements it. A system relies on invariants that must always be true, constraints, contracts, failure modes, and coupling and sequencing that do not appear in the prompt and do not exist in the LLM's internal world.

The topics below are not "enterprise ceremony". They are the questions and decisions every experienced engineer makes before they start typing, and they are the difference between a demo and a product.

If this resonates, the newsletter continues the work. [Subscribe](/pages/newsletter.html)

### Pre‑coding software engineering topics

| Topic | Description |
|---|---|
| Problem framing | Define the problem, the user, the constraints, and the intended outcome. |
| Requirements engineering | Elicit behaviours, invariants, edge cases, and acceptance criteria. |
| System modelling | State models, data flows, sequence diagrams, causal reasoning. |
| Architectural design | Boundaries, responsibilities, interfaces, failure modes, trade‑offs. |
| Non‑functional requirement definition | Performance, reliability, security, compliance, operability, cost. |
| Risk identification | Unknowns, dependencies, failure points, mitigations. |
| Feasibility analysis | Technical, organisational, and economic viability. |
| Interface and contract design | Define APIs, schemas, and behavioural guarantees. |
| Planning and sequencing | Break work into coherent, deliverable units. |
| Definition of done | Evidence required for completion: tests, documentation, review, performance, security. |

## A demo is easy; a product is not

A simple prompt was issued:

write python to "Add user accounts to a website so people can log in."

The model generated a small, working Flask and SQLite example. That is acceptable for a demo. It is not enough for a product. The engineering decisions that make software safe, stable, and evolvable must still be made, and an LLM cannot make or request them.

The AI did not ask about these five requirements:

- Should emails be unique
- Should accounts be verified
- Should users reset passwords
- Should roles exist
- What is the security model?

Any engineer would ask these questions about logging in users to a website. The AI did not ask because the prompt was to write code, so code was written.

Whether emails must be unique, accounts must be verified and whether roles
should exist are *business rules*. Different companies will make different
choices. And these choices are design inputs into code generation.

### The consequences of unasked questions

If emails are not unique, two people can sign up with the same email address. If this can happen, user login identity is ambiguous.

When a user logs in with a repeated email address, the check of that user’s registration from the database will contain multiple values. Any code built to check for a registered user will now have to take into account the possibility of multiple results.

A vibe coded implementation will not handle this case as the person requesting the code did not know to add this possibility to their prompt.

Such code will work initially when all of your users happen to use unique emails. However, as soon as a user signs up with a repeat, user login identity becomes ambiguous, your code starts to become less reliable, and your job becomes inexplicably more difficult.

The lack of unique‑email consideration means that if a user with a repeated
email resets their password, the vibe‑coded implementation will reset the
password for *all* users who share the same email. Chaos reigns. And if one
user deletes their account, multiple accounts will be deleted.

And no business can tolerate this.

Software engineers understand user identity requirements. LLMs do not.

## Why did the LLM not ask about the requirements

It cannot ask.

LLMs cannot detect missing requirements. They cannot detect ambiguity. LLMs cannot identify risks.

LLMs generate code that looks plausible without understanding:

- your domain
- its constraints
- the invariants (what must always be true, like email uniqueness)
- the failure modes
- the consequences

It is not that these points are not important so the LLM did not ask; LLMs cannot see the category of things that must be asked.

This is because LLMs do not build or maintain a model of your system, the domain, or the consequences of actions. They only predict the next plausible token.

Your code is a stream of tokens that happens to be computer code. But the LLM has no understanding of what that code means in the way an engineer understands meaning.

The LLM has generated code that breaks when email addresses are no longer unique. The LLM does not understand why unique emails are important for user identity and system safety.

Vibe coding produces code. The LLM does not do the understanding about that code for you.

## The misconception behind vibe coding

Vibe coding rests on an assumption: that the AI is "intelligent" in the way an engineer is intelligent. If that were true, then missing requirements, ambiguous rules, and hidden constraints would be caught automatically.

The LLM would ask questions. It would notice contradictions. It would flag risks. It would protect invariants.

An LLM does none of this. It does not reason about the system or build a model of your domain. It does not track consequences or understand the invariants that keep the system stable. It does not recognise what it has missed or what it cannot see. It produces text that looks like an answer without doing any of the thinking an engineer would do before writing any code.

The danger is not that the LLM is weak. The danger is that the output looks strong enough that people assume the thinking has been done.

They assume the requirements have been addressed because the code "works." They assume the system is coherent because the file runs.

They assume intelligence where there is only pattern continuation.

Vibe coding fails in production because the missing decisions reappear later as failures, inconsistencies, and fragility.

The model cannot see the category of things that needed to be asked. The human assumed the model had seen them.

And that gap is the entire problem.

Read next:

[The Big AI Gains Come From Teams, Not Individuals]

AI makes individuals faster, but the real gains are between groups of people.

## Related Articles

[Agents Cannot Maintain Systems](agents-cannot-maintain-systems.html)[What Software Engineers Need to Know About LLMs](software-engineers-need-to-know.html)[Latency Is Architectural](latecy-is-architectural.html)

**If this was useful**, you can get more pieces like it in the Phroneses newsletter.

I work with leaders and teams on clarity, capability, and momentum.
[Work with me →](/pages/services.html)
