I'd been learning a piece with a piano trainer whose approach worked really well for me, and nothing else did it the same way. Then it went iOS-only. So I described what I wanted to a coding agent, and a few minutes later I had my own.
I haven't read a single line of its code, and I don't feel guilty about it.
It has no ads and no annoying UI. It does exactly what I need and nothing else. It changes only should I wish it to. Is its architecture scalable? It will never have a million users. It barely has one: me.
A lot of software was complicated only because it had to be general. Mine doesn't have to be, so it can be gloriously simple.
The case for never reading agent code
The claim goes roughly like this: if you're reading agent code, you're the bottleneck. A recent video, Claude Ultracode is super intelligence by Less Bitter, makes the strongest version of it. It showed a spec of about 2,700 lines, itself written by Claude from a voice memo, turned into a working distributed feature over roughly seven hours of agent work, with critics and tests along the way. The author's conclusion: code quality doesn't matter anymore. Apply enough pressure and keep what survives, like evolution.
He isn't alone. Gergely Orosz has said he sees code reviews fading away (source). Santiago (svpino) wrote in August that he'd gone two weeks without reading any AI-generated code and now designs verification for the whole system instead (source). A recent piece argues that code is the new assembly: an intermediate representation nobody needs to read (source).
I want to give this its due. For my piano trainer, it's simply right. Reading its code would buy me nothing: if it breaks, I'm the only one affected, and I'm not trying to get better at building piano trainers.
But "you don't need to read this code" and "understanding the implementation no longer matters" are different claims.
What code quality actually is
"Code quality doesn't matter" depends on what you think quality was. If it means taste, then sure, an agent doesn't care. But most rules that get dismissed as taste are literal readings of principles, and the principles still matter. Short functions, for example, were never about looks: they're easier to test, and an agent changing those tests later makes fewer mistakes too.
Or take DRY. It was never "no repeated lines". Its original definition, in Hunt and Thomas's The Pragmatic Programmer (1999), is about knowledge: each piece of it should have one authoritative representation. People called DRY an antipattern long before AI, because they took it literally. Duplicating coincidental code is fine. Duplicating a business rule creates an invariant nobody enforces: these copies must stay equal. Agents break that the same way people do. They update the copy they're looking at and miss the one that drifted after the copy-paste.
Brevity was never the point either; clarity was. And naming isn't cosmetic. A name is a claim about meaning, and models lean on those claims heavily. Strip the names, and models get measurably worse, even on tasks that should depend only on structure (source). If anything, names matter more for agents: a human compensates for a bad name with a year of familiarity, while an agent reads the code cold every session.
So very little of code quality ever existed only for human readers. It was always information and structure, and every reasoner needs both. What AI changes is how its absence fails. A human slogs through bad code and gets slower. An agent reads it fast, misunderstands it confidently, and acts. Which leaves the question the rest of this piece is about: who notices?
Where judgement comes from
I didn't learn about race conditions from the definition. I learned when code I was sure was deterministic gave different results, and I spent hours finding out why. After a few of those, you don't just know about synchronization. You feel it. You look at innocent-looking code and think: this will race.
Same with injection. "Never trust user input" is a sentence. Someone breaking your shiny new homepage by messing with GET parameters is an experience. After that, name = request.args["name"] makes you flinch.
That flinch comes from accumulated failed predictions: moments when your mental model collided with reality and lost. It's also why experienced engineers can reject an AI answer before they can explain why. They've seen that movie.
So I've started to think "should we review the code?" is the wrong question. What I'd rather know is where these collisions happen now, and who's around when they do.
The standard reply: nobody reads the assembly their compiler emits, so why read what an LLM emits? The standard answer is that compilers are deterministic and LLMs aren't. Yes, but I find a different answer more useful: every abstraction moves where judgement forms, and what matters is how much it leaks.
Compilers almost never leak in ways you have to reason about. Not reading assembly cost us very little.
Frameworks leak at the edges, and we can already see what that costs. Modern web frameworks escape output and ORMs parameterize queries by default. That's mostly good. But it means many developers never get burned by injection, so they never form the reflex the burn would have taught. The real lesson was that input is hostile everywhere, not only where HTML gets rendered. Without that reflex, the same developer writes open(os.path.join(root, request.args["file"])) and walks straight out of the project root. Or builds an SSRF from a URL parameter, or an open redirect. The protection covered one case; the reflex would have covered all of them.
AI-generated code is an abstraction that can leak anywhere. The cost of never colliding with it scales accordingly.
Tests aren't the environment
The video's evolution metaphor is appealing: don't demand a beautiful genome, apply pressure and keep what survives. But in evolution, the organism doesn't write its environment. The world judges it, and the organism has no say in what counts as success.
When the same kind of model interprets the spec, writes the code, writes the tests and fixes the failures, that's not natural selection. It's an optimizer grading its own homework. Adding critic agents helps less than it seems: models from the same family can share blind spots, so their errors are correlated, not independent (source). And sometimes the easiest way to make a test pass is to weaken the test.
Green CI means the implementation satisfies the tests. It doesn't mean it satisfies reality. Ten thousand tests cover the hypotheses someone thought of, and nothing else. A person who's been burned by concurrency asks what happens if two events arrive in the opposite order, and then an agent can write five hundred tests for it. Without that question, you get five hundred sophisticated tests of the happy path.
There is a version of this that really is evolution: ship to production, let real users and attackers hit it, read the complaints, fix, repeat. That environment is independent. It's also the most expensive test suite there is.
In the video, the spec was written by AI too. So the pipeline is vague intent, then an AI spec, AI implementation, AI tests, AI critics, CI.
Where does engineering knowledge enter that system? In his case the answer is easy: he has it. He's built software for years, knows his product, and can tell whether the result is right. He's the oracle.
A junior asking for "something like Uber" gets a fluent spec too. Nothing tells them what it's missing, because they don't know what they don't know. AI increasingly removes the need to formulate a solution, but someone still has to judge whether the formulation describes the right problem. The method works because of years of exactly the experience it would deny the next generation.
Specs age
The video's example is a single pass: one spec goes in, and seven hours later one working feature comes out. Nobody has to change that spec afterwards. Real systems live through dozens of revisions.
An AI-written spec of a few thousand lines that nobody fully read is a second codebase nobody owns. When requirements change, someone has to know which parts were real invariants and which were incidental choices. Which tests protect something that matters, and which just pin behavior that happened to exist.
It gets worse. When the spec changes, the agent updates code and tests together. The environment doesn't just fail to be independent; it co-evolves with the organism, under the same author. Green CI at revision twelve says nothing about an invariant from revision three whose test was "updated to reflect the new requirements".
Then there's Hyrum's law: with enough users, every observable behavior gets relied upon. We usually discuss it for APIs, where you can argue that consumers shouldn't depend on undocumented behavior. Users of a product are different. They learn where the export button is, what order the list comes in, which filter remembers its value. To them, all observable behavior is the behavior, and you can't tell them they were wrong to rely on it.
A human changing familiar code tends to make a minimal diff, so incidental behavior stays put by default. An agent satisfying a revised spec is free to restructure. Each regeneration is a fresh sample from the implementations that pass the tests, and everything the tests don't pin can drift: ordering, defaults, wording, timing, edge cases. Not because anyone decided to change them, but because nothing held them in place. Multiply that by every release cycle, and watch your support queue.
Nobody debugs it either
One objection I take seriously: you don't need to write code to get burned by it, and engineers on call for systems they didn't build learn plenty. But that only works if someone actually does the debugging. When nobody knows the code, debugging it yourself is expensive, so handing the bug back to the agent is the rational choice. Every time. Each handoff keeps familiarity at zero, which makes the next handoff even more rational. Each choice is sensible on its own. Together, they guarantee that nobody ever gets to know the code.
Agents are best at bugs that are local and reproducible. They get stuck on emergent ones: timing across services, data-dependent corruption, failures that only appear under real load. Those are the formative bugs, and that's when humans get pulled back in. At the highest stakes, with the least familiarity.
None of this is new. In 1983, Lisanne Bainbridge described it in "Ironies of Automation": automation takes over the easy cases, leaves operators the hardest ones, and erodes the skills they need for them. Aviation learned this the hard way. I suspect software is about to run the same experiment.
Addy Osmani described one half of this well: agents made writing code almost free, while understanding it still costs what it always did (source). I'd add the other half. The expensive part also includes becoming someone who can understand systems at all, and that happens mostly through the collisions we're now automating away.
Building software is getting cheap much faster than becoming an engineer is. That gap makes judgement more valuable, not less. If you know concurrency is dangerous, you ask for tests that replay events in every hostile order, and an agent writes five hundred of them in minutes. If you don't know, nobody asks, and the agent happily tests the happy path.
The bottleneck moves from writing code to knowing what should exist, noticing when it's wrong, and knowing which failures matter. Those are exactly the abilities you get from software personally screwing you over.
Knowing what should exist is the one I've seen junior and even mid-level engineers struggle with most. Many times I've had to ask "why do you need this?" over and over, until they realized they didn't. An agent rarely asks that question. It builds what it's told, quickly and well, so the unnecessary thing now costs minutes instead of days, and nobody is forced to notice it was unnecessary.
What I actually do about it
I don't think the answer is reviewing every line. Three things seem to work better, at least for me, though none of them is a complete answer.
Stay in the reasoning loop. As far as I can tell, what builds intuition is being present when reality contradicts your model, more than typing or even reading the code. You can stay present with an agent: predict the cause before it tells you, refuse fixes you can't explain, and have a human write the root cause in the postmortem. None of this happens by default, because "fix it" is always faster than "explain it". It has to be a deliberate choice, for individuals and for teams.
Own the boundaries; let agents own the interiors. When I wanted another exercise in my piano trainer, my instinct was to build a separate app instead of growing the first one. That's the Unix way coming back. We drifted away from it partly because many small pieces meant many things to remember and maintain. Cheap generation removes most of that cost, and small pieces also keep each part within what an agent can hold in context. But pieces can only be disposable if the interfaces between them aren't. Unix worked because its contract was dumb and stable: lines of text. So I keep interfaces boring, and I decide them myself.
Use the agent to raise the bar. This part is optimistic. Atomic commits, real commit messages, test plans, small reviewable PRs, a quick first assessment of every incoming traceback, a short loop for the simple bugs: we always knew they were good, and deadlines always gave us an excuse to skip them. Agents make them almost free, so skipping them is now a choice. One caveat: these artifacts are claims about the work. An agent will write a confident test plan that was never run, or split commits that don't build on their own. In experienced hands that's easy to catch, and standards go up. In inexperienced hands you get history that looks exemplary and is subtly fictional.
My piano trainer exists because I practice piano. Nobody, me included, thinks an app could do the practicing for me. The app was easy to hand over. The hours at the keyboard weren't, because the hours are the point.
Software engineering is the same. Let the agent build the tool. But someone still has to practice: break things, be surprised, and come out understanding something they didn't before. If AI writes the code, the question isn't whether anyone reads it. It's who's going to learn from its bugs.
Top comments (0)