What Once Was Abstract Is Now Concrete
Robert C. Martin posted that he’s stopped reading the code his AI agents write, and the quote-tweets wrote themselves. Uncle Bob had apparently stopped caring whether the code was any good. Clip it, dunk on it, move on.
But, I read the same post and came away with the opposite. He isn’t being careless about quality, he’s being precise about where it comes from. And (a little inconveniently) his answer matches something I’d argued myself into while building a code-generation framework of my own.
What he actually said
Here’s the post that lit the fuse:
I'm significantly older than you. I started coding in the late 60s. My current strategy is to not read any of the code written by my agents. That's the only way I can take advantage of their productivity. What I do instead is to surround the agents with extreme constraints. Unit tests, gherkin tests, QA procedures, quality metrics, mutation testing, test coverage, and a plethora of others. In the end, I have very high confidence in the code they produce because they've had to run the gauntlet of all of my constraints and tests.
What’s he actually claiming? Something narrower than the dunking assumed. He hasn’t lowered his standards, he’s moved where they get enforced: instead of reading each function, he wraps the agents in unit tests, gherkin specs, mutation testing, coverage floors, and other checks, then trusts whatever survives. He clarified later that he still looks at the structure, the module layout and the names, not the line-by-line implementation. The confidence rests on the gauntlet, not on his own eyes.
Two things we call “reading the code”
One phrase, “reading the code,” covers two activities with little in common. The first is reading an implementation: I open a function and decide whether it does what its name promised. The second is reading a structure: how the system is carved up, what the pieces are called, which are allowed to know the others exist. Martin kept the second and handed the first to the machine. The mockery assumed the first was the one that counted, and for most of my career it was. So what broke it? Well, a generator can now churn out competent implementations faster than any human can read them, which forces an uncomfortable question: was reading them ever where the value lived?
Boundaries are physical, and they point one way
Lately I’ve treated architectural boundaries as physical facts, not matters of taste. One module is allowed to call another, or forbidden from knowing it exists. Each class stays small enough to hold in one head. Treat those as style and you get a system nobody can change: the boundaries were quietly carrying load. Move one and the stress it held spreads to everything nearby. A function’s interior is a much lower level of consequence: I can rewrite it, and as long as the boundary held, the system behaves as before. What the critics read as laziness is triage: find the parts that bear weight, and spend your attention there.
Martin’s oldest example is the direction of dependencies. They should point inward, toward policy and away from detail: the business rules stay ignorant of the web framework, a use case never learns which database sits underneath. It’s closer to a law of the material than a preference. Honor it and you swap outer layers without disturbing the core. Ignore it and you weld policy to plumbing. And here’s what matters for me: a program can check this. Enforcing a direction on a dependency graph takes no craft, only the graph and the direction.
Tolerances the machine holds instead of me
The practical question nags: how do you keep the boundaries steady when you’re not the one typing? Every older engineering discipline solved this with tolerances. A machined part has to land within a thousandth of an inch, and a gauge decides whether it passed. Not a craftsman squinting down its length going, yeah, close enough.
Squeaky Clean, the framework I’ve been building, drags that idea into generated code. One class to a file. Each file under eighty lines. No class with more than five methods, no method more than two arguments. As advice, these are the style-guide bullets everyone nods at and ignores. As limits a tool applies to every file the agent emits, on every run, they harden into a fence it can’t casually wander over.
This is the half the dunk-tweets skipped. If I’m not reading every line, what stands between me and some quiet, load-bearing mistake? Not my vigilance, which doesn’t scale to thousands of lines I didn’t write. What holds the line is a body of checks that never tires: the unit tests, the coverage floor, the mutation runs, the structural rules. Each returns the same verdict every time, and the agent regenerates until not one comes back red. Martin’s stopping condition stops being “I looked, seemed fine” and becomes “the gauntlet ran, nothing failed.”
Measuring the shape, and writing it down
A gate only gives a yes or a no, and I wanted more gradations: how much architecture a run produced, so I could compare two runs and tell whether a change helped or just… reshuffled the numbers. So Squeaky Clean computes an Architectural Complexity Score for each system, built from the count of modules and classes, how tightly they couple, and how many constraints the problem handed down. It captures size and shape, and says nothing about quality. A big number doesn’t mean the code is good, only that there’s more architecture to track. It lets me read cost, speed, and correctness per unit of architecture, not as raw totals.
One more wrinkle. A person reads structure straight off the module tree and its names, but an agent handing work to a cheaper agent needs it in a form a program can validate. So Squeaky Clean makes the boundary explicit as a compact notation, on the order of two hundred characters per class: the class, the pattern it implements, its methods, its dependencies, nothing else. The architect tier emits it, a validator checks it before any implementation exists, and the tier writing the code never has to guess what the tier above it wanted. It’s Martin’s habit as a protocol: settle the structure, verify it, then let the implementation follow.
The shape the work wanted all along
Line those pieces up and the workflow stops looking reckless. What goes unread is the interior of small, bounded, well-named, well-tested functions, both the most replaceable material in the system and the least likely place for an architectural mistake to hide. Reviewing the structure and delegating the interior isn’t looking away from the code. It’s looking at the part that decides whether the system holds.
None of this is a workaround for the limits of today’s models. It’s the shape the work wants the moment a non-deterministic writer enters the loop. The way to make an unpredictable generator safe was never to trust it harder. It was to bound what it can produce, check the result against rules that don’t bend, then let it be as inventive as it likes inside those bounds.
Which returns me to the title. For most of software’s history the implementation was the concrete thing we pored over line by line, while the architecture was an abstraction we sketched on a whiteboard and hoped would hold. That has flipped. The implementation is becoming the disposable layer, poured by a machine and certified by a gauntlet, while the architecture, the boundaries and names and contracts, is the durable thing a person authors and defends. What once was abstract is now the most concrete part of the system. Letting go of the lines hasn’t felt like the end of caring about code so much as the start of caring about the part that was holding all the weight the whole time.