Signal 71signal

Product-led teams were vibe coding before the LLMs were

The worries about LLM-written code — decisions nobody made on purpose, a data model that fell out, architecture by accident — describe how product-led teams have treated engineering for a decade. LLMs hide those decisions further, and the cure is the rigor we sidelined.

By
Theo Zourzouvillys
Published
Est. reading time
Tags
llmculturearchitecturedesign
My Personal LLM Policy: Extract, not generate

The thinking is mine, whether it’s years old or from this week. What a model does is get it out of my head and onto the page — writing time I’d otherwise never spend, not substance I didn’t have. I read every line, I can defend any sentence, and the errors are mine: the same bar I hold everything here to, model or no model.

The shift I’m noticing

Listen to the worries about LLM-written code and the list is always the same. Nobody understands what was built. Design decisions are made implicitly, at generation time, by nobody in particular. The data model is whatever fell out of the first prompt that worked. The architecture is an accident that happened to pass the tests, and the tests assert what the code does rather than what it should do. It all works right up until the day it doesn’t, and then nobody can say why it is shaped the way it is.

I agree with every item on that list. But I keep noticing something uncomfortable about it: it is an accurate description of how a lot of product-led organizations have treated engineering for the last decade. Describe the outcome, accept whatever implementation produces it, and treat how it was built as somebody else’s problem. “Product doesn’t care how it’s implemented” is a prompt. The vibe codingVibe coding (Andrej Karpathy, February 2025)The post that named the practice: describe what you want to an LLM, accept what it produces without reading the diff, and keep going as long as it seems to work. Karpathy framed it as fine for throwaway weekend projects, which is the part that got lost as the term spread.x.com ↗ people are rightly alarmed by is that same stance, with a model in the seat that used to hold an engineering team.

The old balance

Saying product doesn’t care how something is engineered is exactly the same as engineering saying it doesn’t care how the product is marketed or sold. We would call the second one immature without a second thought. The first one has somehow become a respectable operating model.

It got there as a correction. Engineering-led development had real failures — products built for the people who built them, elegance nobody asked for, roadmaps set by what was interesting to implement. The move to product-led fixed some of that, and then overshot: engineering became a service function that takes tickets, and “how” became a detail product was allowed, even encouraged, not to hear about.

The trouble is that the how never stopped mattering. It just stopped being discussed. The clearest case is the data model. When you build a genuinely new capability, the model you build is not implementation detail — it decides which questions the product can ever answer, which states can exist, what can be undone, and what the product will be able to show. The UI is a view of the model. A screen cannot display a distinction the model never recorded, and a product can’t offer an undo the model can’t express.

So the constraints still arrived; they just arrived late and under other names. “Technical debt.” “Why does this take six weeks?” The feature that can’t ship because the model conflated two things three years ago. Product-led teams have always been engineering-constrained. Most just aren’t honest about it in their own development lifecycle.

What absorbed the gap was engineers who cared anyway. The ones who pushed back — “if we store it that way we can never answer X” — carried the model in their heads, and quietly did the architecture work the process didn’t ask for. That rigor was a subsidy, and because it was invisible, it was easy to believe it wasn’t necessary.

What changes

LLMs remove the subsidy. An agent does what the prompt describes, and prompts describe outcomes. Nobody in that loop is going to say “if we model it this way, you can never offer that.” The decisions still get made — about the model, the boundaries, the invariants, what’s reversible — but now they’re made implicitly, faster, in more places, and hidden a second time: not just from product, but from any engineer who might once have held them in their head.

And here is the irony. Look at the practices people now prescribe to make LLM-assisted development safe: write the spec before the code, design the data model first, review the interface rather than the implementation (ZFN-66Field Note · currentZFN-66 — Agonize over the interface, not the choice behind itRe-implementing a decision now costs hours. Changing an interface costs everyone standing on it. Spend deliberation at the boundary; hold the choice behind it loosely — on one condition: you know a decision was made, and where it lives. Unnoticed ones are the expensive kind.Open ZFN-66 →), keep decision records (ZFN-1Field Note · currentZFN-1 — Keep engineering decision recordsRecord significant engineering decisions as short, versioned markdown files — context, decision, consequences. Write one for cross-team contracts, directional principles, hard-to-reverse choices, and conventions others must follow. Cite them instead of re-arguing.Open ZFN-1 →), test invariants rather than behaviour, make the error contract explicit (ZFN-58Field Note · currentZFN-58 — Errors are part of the contractError paths are the half of your API clients depend on most, and usually the half nobody designed. Enumerate error codes in the schema like any other type: stable code, retryable-or-not, whose fault, structured params. Machines branch on codes — anyone parsing prose is broken.Open ZFN-58 →), design deletion on day one (ZFN-57Field Note · currentZFN-57 — Deletion is a feature: design it on day oneA deleted_at column is not deletion. Real deletion is a workflow with an SLA: it must reach every replica, projection, index, cache, log, and backup — and you must prove it ran. Partition by owner, propagate tombstones on the event rails, crypto-shred what you can't rewrite.Open ZFN-57 →). That isn’t new LLM hygiene. It is engineering rigor — the exact work product-led cultures discounted as overhead. Good practice for building with LLMs is just good practice, rediscovered with a new excuse. It was right before the models, and it would be right without them.

Brooks drew this line forty years ago: tools attack the accidental difficultyNo Silver Bullet — Essence and Accident in Software Engineering (Fred Brooks, 1986)Brooks separates the accidental difficulty of software (languages, tooling, the mechanics of writing code) from its essential difficulty: specifying, designing and conceptually modelling the thing being built. Tools attack the accidental part; the essential part does not get cheaper, because it is the work of deciding what the system is.en.wikipedia.org ↗ of software, the mechanics of writing it, and leave the essential difficulty — deciding what the system is — untouched. LLMs are the most powerful attack on the accidental part we’ve ever had. That makes the essential part more of the job, not less.

The hypothesis

When implementation gets cheap, engineering judgment — the model, the boundaries, the invariants, the irreversible decisions — becomes the scarce input, and it can’t stay invisible, because there’s no longer a team quietly absorbing it.

That doesn’t mean engineering should lead. It means the thing between product and engineering — the model, the spec, the contract — has to be owned by both. The useful test for where product has to care about “how” is reversibility: a decision that outlives the UI and is expensive to undo once data or callers depend on it is a product decision, whatever layer it lives in. Button placement isn’t. The data model almost always is.

My bet is that the organizations that already know how to talk about the data model with product will get enormous leverage from LLMs, and the ones that treat “how” as not-product will ship faster, straight into the walls they used to hit slowly. It’s the same pattern as ZFN-28Open problem · currentZFN-28 — Capability without understanding: brute-force LLM PRsAn open problem: people brute-force PRs with LLMs in domains they don't understand, taking on more than their knowledge supports — and the struggle that used to teach them is smoothed away. How do we stop un-understood code without killing learning or banning a good tool?Open ZFN-28 →, scaled up from a single engineer to a whole organization: capability without understanding, now at the level of the product.

What I’m watching for

  • Product specs that start to include the data model — the nouns, the states, what can be undone — rather than only the screens.
  • Teams’ LLM guidance documents that read like architecture documents, because that’s what they turn out to need.
  • Failures in LLM-built products that trace back to a modelling decision nobody knew had been made, rather than to a bug in the code.
  • Design and architecture work becoming a visible, named part of the lifecycle again, rather than something senior engineers do unasked.

Why I might be wrong

  • The models may learn to push back. An agent that asks “do you need to tell these two apart?” before it builds the model supplies the subsidy itself. Some already do, a little.
  • Rewrites are getting cheaper (ZFN-23Field Note · currentZFN-23 — Rewriting an implementation is fine — refactoring isn't always the answerRefactoring isn't always right. When the structure is wrong at the root, it's fine — often better — to rewrite an implementation from scratch. Clean interfaces and data models make the implementation disposable: stable contract, swappable internals. LLMs make it cheaper still.Open ZFN-23 →), so a wrong model costs less to replace. Code, though. The data already written in the wrong shape is the part that doesn’t get cheaper, and that’s most of what makes a model expensive to change.
  • Much product work really is shallow. For a lot of software the how genuinely doesn’t matter, and I’m generalizing from the kind of systems work where it does.
  • Nostalgia is a bias. The engineering-led era shipped its share of junk, and it’s easy to remember the rigor and forget the self-indulgence.
  • I have a stake in this. I’m an engineer arguing that engineering judgment is about to matter more. Discount accordingly.

References

  • ZFN-66Field Note · currentZFN-66 — Agonize over the interface, not the choice behind itRe-implementing a decision now costs hours. Changing an interface costs everyone standing on it. Spend deliberation at the boundary; hold the choice behind it loosely — on one condition: you know a decision was made, and where it lives. Unnoticed ones are the expensive kind.Open ZFN-66 → — spend the deliberation at the boundary; the data model is the boundary product sees.
  • ZFN-28Open problem · currentZFN-28 — Capability without understanding: brute-force LLM PRsAn open problem: people brute-force PRs with LLMs in domains they don't understand, taking on more than their knowledge supports — and the struggle that used to teach them is smoothed away. How do we stop un-understood code without killing learning or banning a good tool?Open ZFN-28 → — capability without understanding, the individual version of this signal.
  • ZFN-23Field Note · currentZFN-23 — Rewriting an implementation is fine — refactoring isn't always the answerRefactoring isn't always right. When the structure is wrong at the root, it's fine — often better — to rewrite an implementation from scratch. Clean interfaces and data models make the implementation disposable: stable contract, swappable internals. LLMs make it cheaper still.Open ZFN-23 → — stable models make implementations disposable; the counter-argument’s strongest form.
  • ZFN-57Field Note · currentZFN-57 — Deletion is a feature: design it on day oneA deleted_at column is not deletion. Real deletion is a workflow with an SLA: it must reach every replica, projection, index, cache, log, and backup — and you must prove it ran. Partition by owner, propagate tombstones on the event rails, crypto-shred what you can't rewrite.Open ZFN-57 →, ZFN-58Field Note · currentZFN-58 — Errors are part of the contractError paths are the half of your API clients depend on most, and usually the half nobody designed. Enumerate error codes in the schema like any other type: stable code, retryable-or-not, whose fault, structured params. Machines branch on codes — anyone parsing prose is broken.Open ZFN-58 → — two decisions that look like implementation detail and are product behaviour.
  • ZFN-1Field Note · currentZFN-1 — Keep engineering decision recordsRecord significant engineering decisions as short, versioned markdown files — context, decision, consequences. Write one for cross-team contracts, directional principles, hard-to-reverse choices, and conventions others must follow. Cite them instead of re-arguing.Open ZFN-1 → — making decisions visible so they can’t be made by nobody.

Changelog

  • 2026-09-25: Opened as a signal.