The question
The claim is familiar now: if an LLM agent can inspect a codebase and explain the story in seconds, maybe much of what we used to call good code was only a crutch for human reading speed. Maybe code no longer needs to be as clean, as readable, or as carefully shaped, because the machine can narrate it back to us.
There is a real insight there. LLMs lower the cost of re-orienting inside unfamiliar code. They can summarize modules, trace call paths, infer intent, and produce a plausible explanation faster than a human scanning files by hand.
But the conclusion is wrong if it turns into: therefore good code is less important.
The mistake is that it treats maintainability as a comprehension problem. Historically, maintainability was never only about comprehension. It was about safe change.
Good software reduces future regret
The plain version is this: good software reduces future pain. It buys time later. It lowers cognitive load. It makes failure less mysterious. It lets new people contribute without needing a priesthood of tribal knowledge. It preserves optionality when requirements change.
That does not mean good software is always beautiful. It does not mean every function must be tiny. It does not mean every abstraction is virtuous. Good software is not code written to keep the author aesthetically entertained.
A sharper definition is:
Good code is code whose structure makes correct change the path of least resistance.
This definition is more durable than readable code, because readability is only one signal. A readable system can still be dangerous to change if its invariants are hidden, its boundaries are porous, or its failure modes are unclear.
What older traditions optimized for
The major software traditions from the 1970s through the 1990s did not converge on one style, but they did converge on a few pressures.
UNIX, C, and simplicity under constraint
Dennis Ritchie, Ken Thompson, Brian Kernighan, and Rob Pike worked in a world where memory, CPU time, and debugging feedback were expensive. The point of good software was not decorative clarity. It was simplicity strong enough to survive contact with real machines. Kernighan and Pike describe programming as more than writing code: it includes design trade-offs, debugging, testing, performance, compatibility, fault tolerance, reliability, and maintenance.
That tradition values small mechanisms, narrow interfaces, explicit costs, and code that a competent programmer can reason about without needing a full-system seance.
Kent Beck and change as the central fact
Kent Beck's world made a different pressure explicit: requirements change. The purpose of tests, refactoring, small steps, and feedback loops is not prettiness. It is to make change safe enough to do repeatedly. Design exists so that tomorrow's change does not require total rediscovery.
Erlang and failure as normal
Joe Armstrong's Erlang work starts from a harsher premise: software faults are unavoidable, especially in distributed and telecom systems. The right response is not to pretend perfection is possible, but to isolate failure, supervise processes, recover, and keep the system behaving reasonably in the presence of errors.
In that world, good code is not merely readable code. It is code embedded in a runtime and architecture that limit blast radius.
Linux and evolution under public pressure
Linux made another property visible: evolvability. A system worked on by many people needs boundaries, review, conventions, maintainers, and the ability to reject changes. Eric Raymond's famous analysis of Linux contrasted cathedral-style development with bazaar-style development and treated debugging and feedback as social and technical processes, not just private acts of code reading.
Robert C. Martin and professionalism
Robert C. Martin's Clean Code later moralized many of these concerns as professional discipline: keep code clean because mess compounds. The book is often remembered as a readability manifesto, but its deeper anxiety is entropy. Bad code slows change, spreads defects, and converts ordinary maintenance into breakdown maintenance.
Jim Coplien and coherence
James O. Coplien adds another important correction: a system can be locally tidy and globally incoherent. His work on organizational patterns and design integrity emphasizes that code structure, team structure, and communication structure are entangled. Maintainability is not only a property of files. It is a property of the whole system that produces and changes those files.
So is good code maintainable code?
Yes, if maintainable is understood strongly.
Maintainable code is code that can be changed safely, repeatedly, by different people, under uncertainty.
That definition includes readability, but it does not stop there. Maintainability rests on deeper properties:
- Stable boundaries: one change does not leak everywhere.
- Explicit invariants: the system makes illegal states difficult, obvious, or impossible.
- Local reasoning: a developer can predict the effect of a change without holding the entire system in memory.
- Controlled failure: defects are contained and diagnosable.
- Economic sanity: the cost of change does not explode as the system ages.
When people reduce maintainability to easy to read, they flatten the idea. Easy reading is useful. It is not sufficient.
Where the LLM-agent argument breaks
The tweet-like argument makes a substitution:
Maintainable code used to mean code I could understand quickly. Now agents can explain it quickly. Therefore maybe the code did not need to be good.
The first sentence is already too narrow. It defines maintainability as fast re-understanding: onboarding speed, context recovery, and narrative reconstruction. But maintenance is not just figuring out what the system does. Maintenance is changing what the system does without breaking what it already guarantees.
LLMs help with the first part. They do not automatically solve the second.
An agent can say "this module validates invoices." That is not the same as proving that a modification preserves rounding rules, tax constraints, idempotency, retry semantics, audit trails, and backwards compatibility with old records.
The agent can produce a story. The system still needs structure.
The testability pivot is half right
The strongest version of the LLM-era claim is that maintainable code should shift from being optimized for easy reading to being optimized for system-scale verification. That is directionally right.
But verification does not float above design. Tests are only as strong as the boundaries, seams, determinism, and invariants that let them observe meaningful behavior. A tightly coupled system with hidden state can have many tests and still be hard to change. A system test can catch regressions, but it rarely explains which invariant should exist, where it belongs, or which dependency boundary was violated.
Testing does not replace design. Testing assumes design.
LLMs change the interface to code, not the nature of code
LLMs change how developers enter a codebase. They can compress exploration time. They can translate unfamiliar idioms. They can draft refactors. They can generate tests. They can explain the likely reason a function exists.
But they do not remove coupling. They do not reveal every hidden invariant. They do not guarantee semantic preservation. They do not know which undocumented behavior customers rely on. They do not make a non-deterministic system deterministic. They do not make a bad boundary good.
In some cases, LLMs amplify bad maintainability because they increase the speed at which unsafe changes can be made. Messy code plus confident tooling can produce confident damage.
A stricter formulation
The old slogan was:
Good code is maintainable code.
The LLM-era version should be more explicit:
Good code is code that supports machine-assisted change without semantic drift.
That means the system has to expose its shape. It needs clear boundaries, executable tests, explicit contracts, obvious ownership, boring control flow, recoverable failure modes, and a design that makes wrong changes harder than right ones.
LLMs reduce the cost of explanation. They raise the value of verifiability. They do not make coherence optional.
Where this leaves maintainability
Good software was never merely software that humans could read later. That was always the shallow version.
The deeper version is older and more durable: good software controls complexity, preserves invariants, enables local reasoning, contains failure, and keeps the cost of change economically defensible.
Maintenance is where those properties are revealed. LLMs can help us navigate maintenance work, but they cannot replace the system properties that make maintenance safe.
The point of writing good software is still the same: to defend against time, scale, and human fallibility. LLMs are now part of that environment. They are not an escape from it.
Sources
- Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, Prentice Hall, 2008. Publisher sample: Pearson sample PDF.
- Brian W. Kernighan and Rob Pike, The Practice of Programming, Addison-Wesley, 1999. Google Books summary: The Practice of Programming.
- Joe Armstrong, Making Reliable Distributed Systems in the Presence of Software Errors, PhD thesis, 2003. Erlang thesis PDF.
- Eric S. Raymond, The Cathedral and the Bazaar, First Monday, 1998. First Monday article.
- James O. Coplien and Neil B. Harrison, Organizational Patterns of Agile Software Development, Prentice Hall, 2004.
- Kent Beck, Extreme Programming Explained: Embrace Change, Addison-Wesley, 1999.
- Dennis M. Ritchie, "The Development of the C Language," HOPL-II, 1993.