Vibe coding produces code. Engineering produces systems because engineering defines those elements outside the generated code that keeps the solution running long-term in production.
This is not an argument against AI. It is an argument for engineering.
A model can generate a login system in seconds. It will not ask whether emails should be unique or not. If they should be unique, but the generated code does not enforce this, that single missing requirement can cause production downtime.
LLMs cannot see the category of questions that keep software safe.
What vibe coding gives you
Vibe coding is defined to be the automatic generation of code via prompts by a non-Software Engineer.
Vibe coding will give you code but it will not give you the coherence required to run code in production long-term.
Code is deployed into a run-time production system that forms the context of the running code. A large language model cannot know what that running system is so cannot offer code that is system aware.
In addition, the LLM has no sight of business requirements and so those will not be addresses in the generated code.
Without this business and runtime context awareness, missed requirements will cause failure.
Before any code exists, engineers make the decisions that keep systems safe.
| 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. |
| Interface and contract design | Define APIs, schemas, and behavioural guarantees. |
| Planning and sequencing | Break work into coherent, deliverable units. |
What engineering actually is
When engineers write code, they are not just typing. They are:
- resolving ambiguity
- defining boundaries
- modelling behaviour
- deciding how the system behaves under stress
Most of this happens before a single line of code exists. This is the work that keeps systems coherent.
The engineering work vibe coding skips
These parts of the engineering discipline are skipped by LLMs.
| Area | What engineers decide | What LLMs generate |
|---|---|---|
| Invariants | What must always be true | Code that assumes everything is fine |
| Identity & Uniqueness | What makes an entity "the same thing" | Code that treats everything as interchangeable |
| Constraints | What the system must never allow | Code that violates boundaries without noticing |
| Failure Modes | How the system behaves under stress | Code that only works in the happy path |
| Coupling & Sequencing | What depends on what, and in which order | Code that ignores ordering entirely |
| State & Transitions | How state changes and what triggers it | Code that mutates state without rules |
| Interfaces & Contracts | What each part promises to the rest | Code that exposes whatever the model invented |
| Boundaries | What the system does not do | Code that expands until it breaks |
| Error Handling | How the system recovers | Code that collapses on the first unexpected input |
This is the work that LLMs do not ask about, and without attention to this work, generated code will fail long-term.
A system is more than its text
This matters because long-term, system safety relies on:
- invariants that must always be true
- constraints that cannot be violated
- coupling and sequencing rules that shape business logic and user behaviour
The LLM has no appreciation of this.
Why AI‑generated code stalls and creates fragility
AI‑generated code stalls long-term because the engineering decisions were not made.
When such decisions are missing:
- features collide and break each other
- system state becomes unpredictable
- deployments become fragile and slow
- error messages start to lose meaning
- simple features become harder to add
Confidence in the system collapses.
The system is not the code you generate. It is the combination of that code running within an environment.
A demo is easy; a product is not
Given a simple prompt:
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 but it 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?
The solution is not to write a better prompt. A non-Software Engineer is unlikely to know that the above questions should be asked.
The consequences of unasked questions
If the code does not ensure that emails are unique, two people can sign up with the same email address. If they are logged in at the same time, user login identity is ambiguous. The code cannot tell the difference between them.
When a user logs in with a repeated email address, checking that user’s registration from the database will provide multiple values. Any code built to check for a registered user will now have to safely handle the possibility of multiple results.
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. This is not survivable in production. And if one user deletes their account, multiple accounts will be deleted. No production system can tolerate this.
The misconception behind vibe coding
Vibe coding assumes AI is "intelligent" in the way an engineer is intelligent. If that were true, missing requirements, ambiguous rules, and hidden constraints would be caught automatically.
But LLMs do none of this. They do not reason about your system. They do not build a model of your domain to assist with reasoning about your system. They do not track the consequence of change or ensure that invariants are not broken.
LLMs produce working code without doing any of the analysis required to use that code safely, long-term within your system.
Because the generated code solves the immediate problem, people assume the necessary analysis has been done. They assume the resulting system will be coherent because the code currently execeutes OK.
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 vibe-coding human assumed the model had seen them.
What to do instead
Before generating any code, decide:
- what must always be true (invariants)
- what makes something the "same" entity (identity rules)
- what the system must never allow (constraints)
- how the system behaves when things go wrong (failure modes)
LLMs generate code. They do not make engineering decisions. That work remains.
The bottom line
Vibe coding gets you a demo. This demo is disposable.
To take that demo forward into production requires engineering.
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
- What Software Engineers Need to Know About LLMs
- Latency Is Architectural
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 →