Where the cuts fall: why complexity is decided before the code
You describe the use case to a machine, iterate with it for a while, and within minutes there is code that compiles, runs, and passes the tests. The act that for half a century sat at the center of the craft, typing the instructions, has been almost entirely automated. And yet anyone who has built something real with these tools knows the hard work did not go away. It moved. Now it is fought before the first line is written, deciding what to ask the machine for, and afterward, checking whether what it produced actually says what the business needed said.
That shift is the best evidence we have for an old thesis. If the difficulty of software had lived in writing the code, the machine that now writes it would have dissolved it. It did not. It left it exposed.
Where the cuts fall
In an earlier essay I argued that entanglement in code is real and can be pointed at, but that its cost does not exist until someone tries to understand it. A fold nobody reads costs nothing. That essay ended on an idea that now has to be pushed further. The whole craft, whether Parnas’s or Kay’s or Hickey’s, comes down to deciding where to place the cuts. Where one part ends and another begins, what stays hidden behind a boundary and what gets exposed.
The question left unanswered is what material those cuts are made of. The temptation is to answer that they are drawn in the code, between files, between classes, between modules. That is not where. When you decide that the discount and the tax are two separate things, or that the ledger entry is an indivisible unit, you are not drawing a line in the text of the program. You are drawing it in your understanding of the domain. The code, afterward, inherits it. It repeats in its structure a cut that already existed in the model.
If that is true, then the entanglement we see in the code was never born there. The code is the symptom. The origin sits upstream.
Naur and dead programs
Peter Naur had already said as much in 1985, in a short, overlooked essay that today reads like an early diagnosis. In “Programming as Theory Building,” he argues that programming does not consist of producing a text, but of building a theory. Writing a program, he says, “primarily must be the programmers’ building up knowledge of a certain kind, knowledge taken to be basically the programmers’ immediate possession, any documentation being an auxiliary, secondary product.” Code and documentation are the secondary product. What is primary is the understanding the programmer built of the problem, and of why the solution takes the shape it does.
Naur offers a proof that leaves no way out. A program, he says, can die. “The death of a program happens when the programmer team possessing its theory is dissolved. A dead program may continue to be used for execution in a computer and to produce useful results. The actual state of death becomes visible when demands for modifications of the program cannot be intelligently answered.” The text is still there, intact, running without a single character changed. And yet the program is dead, because no one can modify it intelligently. Its theory was lost, and no amount of editing the text will bring it back.
Think about what that implies. If complexity lived in the code, dead code would preserve it exactly as it preserves its syntax, and reading it carefully would be enough to cure it. It is not enough. The complete text, documentation included, turns out to be insufficient. What was lost with the team was not written down anywhere. It lived in the theory, in the model of the problem the team carried in its head. Complexity left with them because that is where it had been.
The theory is inherited by working
There is an obvious objection to Naur, and it is worth meeting head-on rather than sidestepping it. If the theory lives in the mind of whoever possesses it, it sounds like private knowledge, tacit, almost mystical. It sounds as though understanding were a mental state locked inside a skull, exactly the opposite of what I argued before when I said understanding is a public practice.
But Naur does not say that. He says something more precise. For a new programmer to come to possess a program’s theory, he writes, it is not enough to study the text and the documentation. “What is required is that the new programmer has the opportunity to work in close contact with the programmers who already possess the theory.” The theory is not transmitted by reading. It is inherited by working alongside whoever already holds it, taking part in the practice the theory lives in. Naur compares it to learning an instrument, something you do not learn by reading the score but by playing it under supervision.
That dissolves the objection. The theory is private as a state and public as a practice. It is built and transmitted in shared use, among people, over time. It is exactly what I elsewhere called ubiquitous language. When I wrote that ubiquitous language is not a glossary but the way a team thinks and models the problem, I was naming the same thing Naur calls theory. The domain model is not a document or a diagram. It is a shared language, and it dies out when the team that spoke it disperses. No one is left to carry it.
Entangled concepts, emergent systems
Naur was not alone. A year later, Fred Brooks published “No Silver Bullet” with a twin diagnosis. The essence of software, Brooks says, is “a construct of interlocking concepts: data sets, relationships among data items, algorithms, and invocations of functions.” Entangled concepts. The essential difficulty is not in the programming language or the tools, what Brooks calls accident, but in that conceptual construction. The code is the accident, and no tool that attacks the accident touches the essence.
Donella Meadows, in Thinking in Systems, adds the principle that explains why. “The behavior of a system cannot be known just by knowing the elements of which the system is made.” A system’s behavior cannot be deduced from its parts. It emerges from the structure of relationships between them. In software, the parts are lines of code. The structure is the model. Refactoring lines reorders the parts, and the system’s behavior, its complexity included, never lived in the parts. It lives in how they relate, which is a decision of the model, not of the text.
The anomaly
If complexity had always been in the model, an uncomfortable question remains. Why did it take us so long to see it? Thomas Kuhn, in The Structure of Scientific Revolutions, described how what a community is capable of seeing changes over time. A discipline operates under a paradigm, a set of achievements and assumptions that “for a time provide model problems and solutions to a community of practitioners.” While the paradigm holds, the community does what Kuhn calls normal science, solving problems within what the paradigm takes for granted, without questioning the frame. Software’s paradigm was, for decades, the one that puts code at the center. The difficulty was in writing it, reading it, maintaining it. Patterns, tools, refactoring practices were the problems solved within that frame.
Kuhn observes that change begins in a particular way. “Discovery commences with the awareness of anomaly,” with the recognition of a fact that violates the expectations the paradigm had installed. The AI that writes the code is that anomaly. Under the paradigm that puts code at the center, automating the writing should have reduced the difficulty. It did not. It pushed it upstream, toward the specification and the model. A fact the prevailing frame cannot explain, which is Kuhn’s own definition of anomaly.
And here is where my reading departs from Kuhn. For him, crossing into the new paradigm does not discover anything that was already there, because there is no neutral truth for the revolution to reveal. I cannot agree with that in this case. The truth had been written down since 1985. What changed with the anomaly of AI was not the fact, but our capacity to see it. Kuhn would reach for the gestalt example, the drawing where some see a duck and others a rabbit, looking at exactly the same thing. I keep the part where he admits that “what they look at has not changed,” that what was looked at did not change. What changed was the seeing. Complexity had always been in the model. AI only pulled back the veil that let it pass for a problem of code.
Mathias Verraes, in “Software Design in the Agentic Age,” picks up a line from Sam Ruby that says the same thing in the present tense, and without needing Kuhn at all. When the agent writes the code, “rigor doesn’t vanish when the agent writes the code — it migrates. Upstream into specifications, down into test suites treated as first-class artifacts, into type systems and constraints.” Rigor does not evaporate. It is conserved and moves upstream, toward the specification and the model. Which is another way of saying it never lived in the typing of the code to begin with.
The symptom matters too
One crooked reading remains to be closed off. Saying the code is the symptom is not the same as saying the code does not matter. In medicine, the symptom is precisely what makes diagnosis possible. It is what can be seen, what can be measured, where the severity of what is happening further in gets read. An entangled model manifests as entangled code, and that code is the only observable evidence that the model has a problem. Without the symptom, no one would know there was anything to cure.
What the thesis claims is something else. That treating only the symptom is palliative. Refactoring the code without touching the model relieves without curing, because the entanglement resurfaces as long as its origin remains standing. The cure is where complexity is born, in the program’s theory, in the domain model, in the language a team uses to think about its problem. That is where the work has to happen, and that is where the machine still cannot replace us, because building that theory is speaking a language, and a language only exists among those who use it.
Naur knew this when software still fit on tapes and no one dreamed of a machine that could write the program. It took the machine arriving and writing the code for the profession to finally look at the place where the difficulty had been all along.