Emilio Carrión
Letting go of the wheel
Uncle Bob says he no longer reads the code his agents write. The debate that followed mixes four separate questions: what part of review can be automated, where the judgment behind it comes from, how much your system forgives, and what Bob is actually doing.
A few days ago, Robert C. Martin (Uncle Bob, the author of Clean Code) wrote on X that his strategy with AI agents is, in his own words, to "not read any of the code written by my agents". "That's the only way I can take advantage of their productivity," he says. What he does instead of reading is "surround the agents with extreme constraints": unit tests, Gherkin tests, QA procedures, quality metrics, mutation testing, coverage.
The tweet went viral, of course. Not for the argument, but for who was making it: the guy who spent twenty years telling us code gets read far more often than it gets written, and that we're responsible for every line we ship. Hearing him say his strategy is to not read any of the code his agents write lands hard. And like everything that lands hard on the internet, it produced two camps instantly: the ones who celebrated it as proof that the future is already here, and the ones who read it as a betrayal of everything he himself preached.
I've been following the debate for days and it looks to me like the two camps are talking about different things without noticing. At least four questions are getting mixed together, and they're worth answering separately: what part of review can be automated, where the judgment that feeds that automation comes from, how much the system you work on matters, and what Bob is actually saying. As long as they're argued as if they were one, the debate will keep producing more heat than light. So let's pull them apart. And to avoid arguing in the abstract, I'll start with a real case that hit us at Mercadona Tech the same week as the tweet.
The case of the cans
This summer, with the heat kicking in, some soda multipacks change format. Red Bull goes from a 6-pack to an 8-pack. The individual can keeps its product code, but each pack format has a different one. In our hives (the warehouses Mercadona Online fulfills orders from) that breaks something our stock control flows took for granted: that the relationship between parent and child product (the pack and the can inside it) is unique and stable.
It isn't anymore. During the transition the old parent and the new parent coexist, and to know how many cans you actually have you need to look at the product's whole family: the historical relationship, not just the current one. This is a new rule, not old debt: until this summer, the direct relationship was enough. So we needed a family resolver, and it had to be used at four different points in the system: reconciliations, withdrawals, transformations, and one more corner where stock gets reconciled.
The product family: what changed this summer
We implemented the change with AI. Two people, four pull requests in parallel. It worked on the first try. Tests passed. The behavior was correct.
And when we read the code we saw that the family resolution logic was duplicated, almost identically, in all four places.
What we did next is an obvious refactor to anyone who's been at this a while: family resolution became an application service in the transformations context, and the four call sites go through that abstraction. One source of truth for a business rule that, as we already know, is going to change again. Product formats change every year.
What the AI shipped vs. the refactor
That duplication was caught by reading. Without the read the picture was spotless: tests green, stock adding up, everyone happy. Until the day, six months or a year later, when someone had to change that logic and had to remember (or trust that the AI would find) that it lives in four places. The odds of missing one are high. And the resulting failure wouldn't be a compile error: it would be a silent stock discrepancy in production, probably in the middle of a demand peak.
The code was correct. Its sustainability had degraded. And no test tells those two apart.
And there's a second bill, harder to see, that my teammate Alejandro Capdevila pointed out to me when I told them about the case. The code agents generate doesn't sit still: it becomes the context the next agents work from. If those four copies had stayed where they were, the next agent to open the transformations context would have learned, from the repository itself, that family resolution is written by hand wherever it's needed. And it would have written the fifth.
That's why the degradation doesn't add up, it compounds. Every design decision you don't make becomes the example the next session copies. It matters enormously whether the base you start from is well put together or a landfill, and that difference gets amplified with every lap.
With the case on the table, let's take the four questions.
First question: what part of review can be automated?
Short answer: much more than the skeptical camp admits, and less than the enthusiastic camp believes.
The case for automating is solid and worth taking seriously. First, economics: if you have to review line by line everything the AI produces, you're the bottleneck, and a bottleneck eats the advantage of the machine sitting behind it. That's not an opinion, it's arithmetic. Second, because a good chunk of what we call "judgment" is really metrics: duplication, coupling, cyclomatic complexity, architecture violations. Bob doesn't even delegate that part to the AI: he builds deterministic tools that do the work, one per language, and he has them published on GitHub (dry4go, dry4java, dry4clj). And third, history: the set of automatable things only grows. Ten years ago, "formatting requires judgment" was a defensible opinion; today it's a linter. Betting against that trend is bad strategy.
Now let's apply all of that to the cans and see what would have happened.
A PR reviewer (human or AI, doesn't matter) works with the context of one PR. Inside each of our four, the code was fine: a clean, local implementation of family resolution, exactly where it was needed. Nothing to flag. The duplication only exists when you put the four side by side, and no process that works PR by PR ever sees that full picture. For the record, the AI didn't invent this: two humans on four parallel PRs without coordinating would have duplicated the logic in exactly the same way. It's the same old shared-context problem. What changes with AI is the scale: more code, faster, produced by something with even less of a whole-system view than a teammate who asks you in standup "hey, aren't you doing this too?". AI doesn't create the problem. It amplifies it.
What about a duplication detector running periodically over the whole codebase? That one would help: it would probably have caught this particular case within days, because our duplication was the easy kind, four near-identical copies. But look at what the detector does: it finds and it flags. It doesn't decide. And deciding is the hard part, because duplicated code isn't bad in itself. Sometimes two identical chunks only look alike by accident: they serve different business reasons, they'll evolve separately, and if you abstract them you create a coupling you'll pay dearly for. And sometimes they're the same business rule repeated, which has to change together or the system lies. Telling one case from the other requires knowing why each chunk exists and how the business is going to evolve. In ours, the answer was obvious to anyone who knows that pack formats change every season: domain rule, it's going to change, one place. But that clarity came from knowing the business, not from reading the code. It wasn't in any file an agent could look up.
"So write it down," someone will say, and fairly: that's what context files are for. But notice what we just did: for the agent to decide well, someone has to know what to write, realize it's relevant before it's needed, and keep it current when the business changes. Knowledge can be dumped into a file; knowing what to dump, when and why, cannot. That has a name, and it's the next question.
So, the first boundary: detection is automatable; the decision, today, isn't. And the practical consequence is worth drawing out, because it argues for the tools, not against them: a good detector doesn't replace reading, it tells you where to read. It turns "review all the code" into "judge twenty findings," which is work a human with judgment can absorb. The code was correct; what degraded was the price of the next change. And that bill doesn't show up at the merge: it arrives six months later, and it's paid by whoever has to touch the module.
Detection vs. decision
Second question: where does the judgment come from?
There's an argument structure that keeps showing up in this debate and is worth naming: "you don't need to read the code if you have enough guardrails." You offer a counterexample and the answer is "that proves you were missing a guardrail." Every failure, always, gets explained as insufficient configuration; never as a limit of the approach. An argument that can't lose should make us suspicious, not convinced.
But the underlying problem isn't rhetorical. It's this: where do the guardrails come from? Someone actually asked Bob that in his own thread, in Latin: quis custodiet ipsos custodes. Who writes the gauntlet, that obstacle course Bob sets up for his agents? If the constraints do the heavy lifting, the quality of those constraints becomes the real engineering problem. Someone has to decide which invariants to protect, which patterns to forbid, which metrics to watch and at what thresholds, what's acceptable in this context and what isn't. That decision is exactly the judgment the slogan says you no longer need. "I don't need judgment because I've moved it into constraints" needs the judgment to write the constraints, to keep them current when the business changes (and ours changes every summer), and to notice one is missing before its absence blows up in production.
Human review doesn't get eliminated. It moves one level up, where it's harder to see. And moving it can be an excellent move; often it is. But moving it and eliminating it are different things: the judgment work still exists, it just lives in the constraints now, and it has to be maintained with the same rigor the code used to be.
Enjoying what you read?
Join other engineers who receive reflections on career, leadership, and technology every week.
This newsletter is written in Spanish.
Third question: what system are you in?
This is the question almost nobody asks, and I suspect it explains most of the disagreement. A lot of the argument about how much autonomy to give AI is in disguise: underneath, people are arguing about domains. Everyone generalizes from their own feedback loop, and feedback loops look nothing alike.
It's not that some people work on hard software and others on easy software. It's that some systems forgive and some don't.
In a lot of digital products, an error is cheap and loud. The code fails, an exception fires, an alert catches it, you roll back and ship the fix in minutes. State lives in a database: if the code lied, you fix the code and migrate the data. The system itself tells you fast and lets you undo. In an environment like that, giving agents a lot of autonomy is pretty reasonable: the cost of being wrong is small and you find out right away.
With one caveat worth keeping: that fast feedback saves you from behavioral errors, not structural ones. The can duplication wouldn't have thrown exceptions in any domain; design decay is silent everywhere. The problem exists in every system; what changes is how much it costs when it finally bites. In a SaaS you pay in development speed; in logistics you pay in development speed and in cans that don't add up.
In a logistics system, state lives in the physical world. The truth isn't in the database: it's in the hive, in how many cans are really sitting in a location. And that changes everything. A failure doesn't throw exceptions: it puts stock out of balance, and the drift accumulates in silence. You don't find out in minutes: you find out days or weeks later, when an order can't be fulfilled or a manual reconciliation surfaces the gap. Fixing it is physical work, people counting cans. And there's no rollback for reality: the cans that got pulled by mistake are pulled. Add that the domain changes for reasons you don't control (the July heat, a supplier switching pack format) and you have a system where the error is expensive, silent, slow to detect and expensive to correct. All four at once.
How much a failure costs, how long it takes to detect, how much it costs to fix, and how often the business changes the rules on you: those four variables are what should set how much human judgment you put between the AI and production. At one end, the system supplies the discipline for you: it fails fast, it shouts, it undoes itself. At the other, you have to supply the discipline before the merge, because after that there's no net.
Does your system forgive?
Move the four variables that decide how much human judgment to put between the AI and production.
Your system half forgives
autonomy with a net underneath
the system supplies part of the discipline; you supply the rest before the merge
One point my teammate Sergio Revilla pointed out to me, and it corrects an overreach in this reasoning: the dial isn't only about the system, it's also about the task. Even if you work somewhere that doesn't forgive, not every change has the same blast radius, and you don't know every corner of the system equally well. A mechanical refactor well covered by tests and a migration of the payments flow live in the same repository and don't come close to asking for the same review.
So they're two chained questions, in this order: how much does my system forgive, and inside it, how much does this particular change forgive. The first sets the floor of review; the second says how far above that floor you go. Applying the maximum to everything is as poor a call as never applying it: you eat the cost of distrust without buying anything with it, and you end up going over a copy change with a magnifying glass while the one that throws stock out of balance goes by under the same distracted look.
So when someone tells you they no longer read their agents' code, the interesting question isn't how much they trust the AI. It's how fast and how cheaply their system tells them when the AI gets it wrong. I suspect a lot of people who think they disagree in this debate are just answering for different systems.
Fourth question: what is Bob actually saying?
This is the part I care about most, because the headline has traveled without the context holding it up.
If you read the full thread and what Bob has been describing these past months, his real process is this: he writes informal specifications by hand, an agent turns them into hard specifications broken into tasks, and he reviews those tasks himself. They then become Gherkin, in natural language, which is what defines the system's behavior. And he measures everything, from coverage to mutation testing. It's a textbook verification loop: external signals, not introspection. And when someone in the thread asks how much productivity is left after building that much scaffolding, he answers that the big manual spend sits in two places: the initial specification and the final testing. Everything in between, the code, he leaves to the AI.
What Bob actually does
There's another reply of his in the thread that I find the most revealing of all. Someone asks what gives him confidence that the agents will respect the guardrails, and he answers that they're about as reliable as people, so you watch them. That's the whole thing right there. The "I don't read the code" man watches his agents the way he'd watch a team. And when someone else accuses him of having stopped being an engineer, he replies that he's the engineer because he's the one accountable. Which is another way of saying the usual: no agent puts its name on the line for you.
So: Bob hasn't stopped reviewing. He's changed what he reviews. His eyes are no longer on syntax, they're one floor up. His judgment hasn't disappeared: it's encoded in which constraints he picked, which thresholds he set, and which specs he approves. It works full time, just where nobody sees it.
What Bob does is about as sensible as anything you can do today. The problem is the distance between that and what his headline invites people to do. The headline has reached thousands of people who don't have the hand-reviewed specs, the mutation testing, the custom-built tooling accumulated over a career. Most of the people applauding it have none of that underneath. They're going to let go of the wheel without having first built the road the car would drive itself on. And the rest of us get to maintain that code.
What to do with your agent's next PR
An analysis that doesn't change what you do on Monday is entertainment, so let's bring it down to the ground.
Let's start with the economics, because they decide everything else: if you're going to do this by hand every day, you are the bottleneck, and we've already said that isn't an opinion. Much of what you were going to check with your eyes (duplication, coupling, complexity, architecture violations) is a metric, and you don't look at a metric: you automate it and it tells you.
And you don't need the whole gauntlet to start. If you have nothing today, the first one isn't the most sophisticated: it's the one that automates something you're already checking by hand. Most of the time that's an architecture test, the "this context doesn't import from that one" kind, which takes an afternoon to write and has no false positives to triage. You build the next one when you start missing it. What matters is the direction: the better your gauntlet, the more changes land in high gear and the fewer times you have to shift down.
With that in place, place the change before you open the diff. You already set the floor in the third question, with how much your system forgives; what's left is the task. Two questions, thirty seconds: what happens if this is wrong and nobody notices for two weeks? And how much do I know about this part of the system? Blast radius and certainty. That's what picks the gear.
In high gear, small radius and familiar ground, you review the final diff and little else. Here the detector does the work and you sign off.
In low gear, big radius or new ground, you don't review the result: you step in earlier. You agree the abstraction before it gets written, you split the change into pieces you can judge one at a time, and you look at each one. Not because AI is unreliable, but because the cost of finding out late is the most expensive on the list.
In both gears, what you read is the same, and it isn't the syntax: it's the design. It's what the tests don't see and, worse, what the agent's next session will take as its example.
And every so often, look at the set instead of the change. The cans didn't show up in any single PR: they showed up when you put the four together. No gear saves you from that, because the problem wasn't inside any one change, it was between them. That's the question to ask the repository now and then: which business rule got written more than once this month, and which of those is going to change again.
And when you have to make a decision because the context wasn't written down anywhere, write it down. That's the work that's left. Every rule you manage to get out of your head and into the system is one you don't make again and one the agent no longer needs to ask you about. That's where you move up a level, and that's where this stops being an internet argument and becomes engineering work.
Raising the level we drive at
Put the four answers together and the debate sorts itself out.
Can review be automated? Detection yes, more every year; the design decision, not today. Does judgment disappear once you have guardrails? No: it moves into writing them and keeping them alive. Does it matter which system you're in? Very much: the cost and the speed of failure are the variables that should weigh most, and almost nobody mentions it. Has Bob let go of the wheel? No: he's driving one floor up, on top of a judgment infrastructure he's spent years building.
The practical conclusion for today is neither slogan. "I read all the code" doesn't pay off. "I read none of it" only works with years of judgment infrastructure underneath, and even then it leaves out the design decisions metrics can't see. The defensible position sits on a different axis: what you decide deserves your eyes, regardless of how much code goes past. I no longer read my agents' code line by line hunting for the bug; I read the abstractions that get created or fail to get created, the boundaries between contexts, the places where a business rule turns into structure. I read design, not syntax. And yes, clipped short, that sentence sounds exactly like Bob's: the difference is in what comes after the semicolon, and what comes after the semicolon takes up this entire article. Everything else I automate gladly, because spending human attention on what a machine verifies better is as irresponsible as not spending it on what a machine can't.
The judgment you build over years of watching code break isn't there to read faster than the AI. You're never going to read faster than the AI. It's there to know where to look. That's the difference today between a senior with agents and a junior with agents, and I suspect it will be the last skill in this profession to be automated. Not by magic: it's the one that decides what gets automated.
Next summer some pack format will change again. And the one after that. When it does, someone will have to touch that rule and will find it in one place, not four, because one July afternoon we stopped to read code that already worked and that no test had anything to say about. Nobody in the hive will notice. That's exactly the point: judgment work done well is never visible, it's only missed.
We haven't let go of the wheel. We've raised the level we drive at. And if someone tells you the car drives itself now, ask them first how many years they spent building the road.
P.S. Full disclosure: I have an interest in you caring about this topic, because I teach a workshop on exactly this: Before the LGTM: a protocol for reviewing AI-generated code in under 10 minutes per change (it's taught in Spanish). It won't give you the judgment: that comes from the years and from the discrepancies you've had to clean up. It will give you the protocol: what to delegate, in what order to look, and how to write a no. The argument above holds just the same if you never sign up. But if while reading it you thought "this is exactly what I don't know how to do when I approve my agent's PR," that's where it is.
Related articles
The seven unwritten engineering laws AI is making more expensive
This week I watched a teammate ship nine PRs in a single day. Solid work, AI-assisted. Speed is what we celebrate, but the unwritten rules of engineering, the ones you only learn by breaking them, now charge you sooner and bigger. The seven laws, and how AI changes the math on every one of them.
Discipline Doesn't Scale. Verification Needs Infrastructure.
Individual discipline as a quality system is a fragile design. Tests scaled because they became infrastructure. Verification needs to do the same.
Generating Is Easy. Verifying Is the Work.
Anthropic separated the agent that generates from the one that evaluates, and quality skyrocketed. That pattern describes the future of software engineering: generation is commodity. Verification is craft.
