Clean Code Isn't Dead: What a New Study Says About Coding Agents and Token Bills
A SonarSource minimal-pair study shows clean code doesn't change whether an agent finishes a task — but it cuts token usage 7-8% and file re-reads 34%. A .NET practitioner's take, with C# examples.
Jean-Pierre Broeders
Freelance .NET Developer
Every few months someone declares clean code dead. The latest version of that argument goes like this: if an AI agent writes and maintains the code, and no human ever reads it, then all our fussing about naming, small functions and low complexity is sentimental waste. Ship the mess. The machine doesn't care.
A paper that hit the Hacker News front page this week put that intuition to an actual test, and the result is more interesting than either camp expected. "Does Code Cleanliness Affect Coding Agents? A Controlled Minimal-Pair Study" by Priyansh Trivedi and Olivier Schmitt at SonarSource (arXiv) found that code cleanliness does not change whether an agent finishes a task — but it very much changes how expensive and how efficient getting there is.
As a freelance .NET developer who now runs coding agents against client codebases every single day, this is exactly the kind of evidence I've wanted. Not vibes, not manifestos — a controlled experiment. Let me unpack what they did, what the numbers actually mean, and what I'd change in a real C# codebase because of it.
What the study actually measured
The clever part of this study is its design. Arguing about clean code is usually hopeless because you're never comparing like with like — the clean repo and the messy repo solve different problems, so any difference could be the problem, not the cleanliness.
Trivedi and Schmitt sidestep that with a minimal-pair approach borrowed from linguistics. They built pairs of repositories that are architecturally identical but differ only in code quality. Crucially they constructed those pairs in both directions: some by degrading originally clean code, others by cleaning up originally messy code. That bidirectionality matters, because it controls for the possibility that "clean" repos are just easier for unrelated reasons.
On top of those pairs they authored 33 tasks across six repository pairs, graded with hidden tests, and ran them through Claude Code — 660 trials in total. Hidden tests are the honest way to grade an agent: you don't reward it for output that looks right, only for behaviour that is right.
The headline findings:
- Task completion rate was essentially unaffected by cleanliness. A capable agent finishes roughly as often in a messy repo as in a clean one.
- Cleaner code consumed 7–8% fewer tokens.
- Cleaner code produced a 34% reduction in file revisitations — the agent re-opened the same files far less often to re-orient itself.
Their conclusion is measured and, I think, correct: "traditional maintainability principles remain highly relevant in the era of AI-driven development." Cleanliness stops being about human comprehension alone and becomes about computational cost and navigational efficiency.
Why "same success, less cost" is the point, not a footnote
The internet reflex was predictable: "See? Cleanliness doesn't change the outcome, so it doesn't matter." That reads the result exactly backwards.
Task completion rate is a ceiling metric. On benchmark-shaped tasks with a strong model, a lot of things eventually complete. What separates a pleasant agent workflow from an infuriating one isn't whether it finishes — it's how much thrashing, backtracking and re-reading happens on the way, because that thrash is what you pay for in three currencies:
- Money. Tokens are literally billed. A 7–8% reduction across a team running agents all day is a real line item, and it compounds.
- Latency. Fewer file revisitations means less back-and-forth, which means faster loops. Agent productivity is dominated by wall-clock time per iteration.
- Context budget. This is the one people underrate. Every file the agent re-reads to re-orient itself burns context window. A 34% drop in revisitations means more of the finite context is spent on the actual problem rather than on re-establishing where things are. In long tasks, that's often the difference between the agent holding the thread and losing it entirely.
So the honest summary isn't "cleanliness doesn't matter." It's "cleanliness doesn't buy you correctness you couldn't otherwise get — it buys you correctness cheaper, faster, and more reliably at scale." For anyone paying the bill, that's the whole game.
What "clean" means to an agent (it's not what you'd guess)
Here's where I'll add my own take. When we say clean code helps a human, we usually mean readability, taste, naming. An agent reads differently. It navigates a repo by searching, opening files, and pattern-matching symbols. The things that reduce its file revisitations are the things that make local reasoning possible — being able to understand a unit without opening five other files.
Consider a very common C# pattern I still see constantly: behaviour smeared across partial classes, deep inheritance, and implicit conventions.
// "Messy" for an agent: to understand CalculateTotal you must open
// OrderBase, IDiscountStrategy, the DI registration, and a partial file.
public partial class Order : OrderBase
{
public decimal CalculateTotal()
{
var total = ComputeSubtotal(); // defined in Order.Calculations.cs
total = ApplyDiscounts(total); // resolved via injected strategy
total = ApplyRegionalTax(total); // defined in OrderBase
return total;
}
}
To modify CalculateTotal safely, the agent has to reconstruct the whole graph: where ComputeSubtotal lives, which IDiscountStrategy is wired up, what ApplyRegionalTax does in the base. Every one of those is a file open, and if it forgets, a re-open. That's precisely the revisitation cost the study measured.
Now the same logic written for local reasoning:
// "Clean" for an agent: everything needed to reason about the total is here.
public sealed class Order
{
private readonly IReadOnlyList<OrderLine> _lines;
private readonly IDiscountPolicy _discountPolicy;
private readonly TaxTable _taxTable;
public Order(IReadOnlyList<OrderLine> lines, IDiscountPolicy discountPolicy, TaxTable taxTable)
{
_lines = lines;
_discountPolicy = discountPolicy;
_taxTable = taxTable;
}
public Money CalculateTotal()
{
var subtotal = _lines.Aggregate(Money.Zero, (sum, line) => sum + line.Amount);
var discount = _discountPolicy.DiscountFor(subtotal, _lines);
var taxable = subtotal - discount;
var tax = _taxTable.TaxOn(taxable);
return taxable + tax;
}
}
Nothing here is novel clean-code advice — explicit dependencies, sealed, small composable steps, a value type for money. What's new is why it pays off. The second version lets an agent reason about CalculateTotal from a single screen. It doesn't need to reconstruct the class across partials or chase runtime DI wiring. Fewer opens, fewer re-opens, fewer tokens — the exact axes the study found move.
The refactoring trap: clean for the agent, not clean by dogma
There's a failure mode I want to flag, because I've watched teams sprint toward it. Reading "clean code makes agents cheaper," someone kicks off a giant refactor to satisfy every SonarQube rule at once. That's a mistake, for two reasons.
First, the study didn't find that maximum cleanliness wins; it found that clean-vs-messy pairs differ measurably. Diminishing returns are real. Second — and this is the practitioner's point — the cleanliness that helps agents most is structural locality, not cosmetic style. Renaming x to index is nice; it's not what saved 34% of revisitations. Collapsing a five-file dependency chase into a one-file read is.
So my priority order for an agent-friendly .NET codebase:
- Kill indirection that spans files. Prefer explicit constructor injection over service-locator lookups and static ambient state. An agent can read a constructor; it can't easily infer what
ServiceLocator.Resolve<IThing>()returns at runtime. - Keep units cohesive. Avoid partial classes that scatter one concept across files. If a human needs three files to understand a method, so does the agent — and it pays per file, twice.
- Make contracts obvious. Nullable reference types on, precise return types, no
objector stringly-typed payloads. Types are free documentation the agent doesn't have to re-derive. - Then worry about naming and formatting. It helps, but it's the cheap tier.
A concrete win: exceptions and control flow
One more example, because it's where I see the biggest agent-thrash in real .NET code: control flow buried in exceptions and side effects.
// Agent has to open the caller AND the logging config to know what happens.
public User GetUser(int id)
{
var user = _repo.Find(id);
if (user == null) throw new UserNotFoundException(id); // handled... somewhere
return user;
}
Whether this is "fine" depends entirely on a catch block the agent may not have in context. Compare an explicit result:
public Result<User> GetUser(int id)
=> _repo.Find(id) is { } user
? Result.Ok(user)
: Result.NotFound($"User {id} does not exist");
Now the outcome space is visible at the call site. The agent doesn't have to open the composition root to discover how a thrown exception is handled. This is exactly the kind of "reduce the files you must read to reason locally" change that the study's revisitation metric rewards — and, not coincidentally, it's better code for humans too.
What I'm taking away
The comment thread on Hacker News split, as these always do, between "clean code is dead" and "told you so." The paper supports neither slogan. The precise, useful reading is this: with a strong agent, cleanliness rarely decides whether the job gets done, but it consistently decides what it costs to get there — in tokens, in latency, and in the context budget that determines whether long tasks hold together.
For me that reframes the business case for maintainability rather than weakening it. I no longer have to argue that clean code prevents bugs a human would otherwise ship (a claim that was always partly faith). I can point at a controlled study and say: on the same task, the messy repo cost 7–8% more tokens and made the agent re-read files 34% more often. In a shop running agents at scale, that's money and time you're setting on fire for nothing.
Clean code was never really about pleasing a compiler or a linter. It was about making systems that are cheap to reason about locally. Turns out our new non-human colleagues have exactly the same preference — they just send you an itemised bill for ignoring it.
Source: Trivedi & Schmitt, "Does Code Cleanliness Affect Coding Agents? A Controlled Minimal-Pair Study" (SonarSource). Discussion on Hacker News.
