Code is Design vs The AI Shift
If Code is Design, What Happens When AI Drafts the Blueprint?
This is not another “AI will/won’t replace programmers” piece; it is about responsibility for design.
In 1992, Jack Reeves wrote an essay called What Is Software Design? His argument was simple, but it cut across the way many managers, clients, and even developers thought about software.
Source code, Reeves argued, is not the manufactured product.
Source code is the design.
The compiler is the factory.
That distinction matters. In traditional engineering, a bridge designer produces drawings, calculations, models, and specifications. Then somebody else builds the bridge. The blueprint is the design; the physical bridge is the manufactured artifact.
Software does not work that way.
When we write source code, we are not merely “building” something from a design that already exists. We are making the design itself. Every class, function, interface, database choice, error path, naming decision, and boundary between components is part of the real design of the system.
The compiled binary, the deployed service, the running application – that is the manufactured result.
This is one of the central arguments I made in my book, Code is Design. The software industry gets into trouble when it imports the wrong mental model from construction and manufacturing. It treats programming as if it were bricklaying, when in reality it is much closer to engineering design.
And now AI has arrived, with a rather awkward question.
If code is design, what happens when a machine can draft that design in seconds?
The Compiler Is No Longer the Only Machine in the Room
For decades, the compiler was the great automation engine in software.
A human being wrote the source code. The compiler converted that design into machine instructions. The manufacturing step was almost entirely automated.
That was already extraordinary. No civil engineer presses a button and gets a bridge. No architect clicks “compile” and receives an office tower. Software has always been different because the distance between design and manufactured artifact is so short.
But generative AI changes the machinery around the design step itself.
A large language model can now produce thousands of lines of plausible source code in seconds. It can create scaffolding, APIs, tests, configuration files, documentation, user interfaces, database schemas, and whole application skeletons with impressive speed.
At first glance, this looks like a massive productivity jump.
And sometimes it is.
But there is a trap here. Because the output looks like code, and because code is the design document, we can easily mistake generated code for a completed design.
It is not.
It is a draft. Often a useful draft. Sometimes a surprisingly good draft. But still a draft.
The machine has produced something that resembles a design document by drawing on patterns from the past. It has not understood the business pressures, the political constraints, the operational risks, the compromises already buried in the existing system, or the things nobody wrote down because “everyone knows that”.
Except, of course, everyone does not know that. Especially not the machine.
The Old Bottleneck Has Moved
In the old model, much of the cost of software sat in the act of expression.
A developer had to turn intent into code manually. That meant typing, structuring, naming, testing, correcting, and reshaping. The friction was real. It slowed us down, but it also forced thought.
You could not write a substantial module without making hundreds of small design decisions. Some were explicit. Many were almost subconscious. Where should the responsibility live? What does this object know? What happens when this service is unavailable? Is this condition exceptional, or is it part of the normal flow? Should this rule be enforced here, or nearer the boundary?
That thinking was embedded in the act of coding.
AI reduces the friction of generating the text of the design. That is powerful. But it also means the bottleneck moves.
The hard part is no longer always “Can we produce the code?”
Increasingly, the hard part is:
Does this code express the right intent?
Does it fit the system we already have?
Does it preserve the architectural boundaries?
Does it fail in ways we understand?
Can we maintain it six months from now?
Does anyone actually own the design?
We have automated a large part of design drafting.
We have not automated judgement.
The Reckless Junior Designer
I find it useful to think of AI as an extremely fast junior designer.
Not junior programmer. Junior designer. That distinction matters.
A junior programmer may make syntax mistakes, misuse a library, or need help with tooling. A junior designer may produce something that looks coherent but rests on the wrong assumptions.
That is more dangerous.
The code may compile. The tests may pass. The demo may work. The pull request may even look tidy.
But the assumptions may be wrong.
Perhaps the generated service bypasses an important domain boundary. Perhaps it duplicates logic that already exists elsewhere. Perhaps it handles the happy path beautifully and turns operational failure into a swamp. Perhaps it introduces a dependency that looks harmless but creates a long-term maintenance problem. Perhaps it solves the local problem while making the system harder to reason about.
These are not syntax errors. They are design errors.
And design errors are usually more expensive.
The Review Problem
There is another uncomfortable issue: reviewing generated code can be harder than writing code yourself.
When you write code carefully, you carry its reasoning in your head. You remember why you put the boundary there. You remember the alternative you rejected. You remember the ugly condition that exists because the billing system behaves strangely on the last day of the month. You know which part is clean and which part is a scar from an old production incident.
When AI generates the code, you inherit an alien blueprint.
It may be neat. It may be idiomatic. It may even be better than the first version you would have written.
But you did not travel the path that produced it.
So now you must reverse-engineer not only what the code does, but why it does it that way. And if the answer is merely “because this is a statistically likely shape for this kind of problem”, that is not much comfort.
Software rarely collapses because one line was misspelled.
It collapses because the wrong assumptions were allowed to harden into structure.
The more code we generate, the more discipline we need in reviewing the assumptions behind it. Otherwise, we are not accelerating development. We are accelerating architectural debt.
Accidental Complexity on Steroids
Fred Brooks gave us the useful distinction between essential and accidental complexity.
Essential complexity comes from the problem itself. A payroll system is complicated because employment law, awards, taxation, leave rules, and human arrangements are complicated. No tool removes that.
Accidental complexity comes from the way we choose to build the system: poor boundaries, bad naming, duplicated logic, unnecessary frameworks, tangled dependencies, and layers nobody understands anymore.
AI can help reduce accidental complexity when used well.
It can also multiply it at frightening speed.
The danger is not that AI produces bad code in the obvious sense. The more subtle danger is that it produces plausible code too easily. It fills gaps. It invents structure. It smooths over uncertainty. It gives us something that looks finished before we have done the harder work of deciding what “finished” should mean.
That is why the old “code is design” argument still matters.
In fact, it matters more now.
If source code is the design document, then flooding a project with generated source code is not a harmless act of production. It is a design intervention. Every generated module changes the shape of the system. Every generated abstraction becomes part of the architecture. Every generated test suite encodes an opinion about what matters.
The question is not “Did the AI write code?”
The question is “Who is responsible for the design?”
The Engineer Moves Up a Level
Does this mean AI is useless for serious software work?
No. That would be a silly conclusion.
Used well, AI is a remarkable tool. It can draft options, remove drudgery, explain unfamiliar code, generate test cases, translate between libraries, produce prototypes, and help explore approaches quickly. For experienced developers, it can act as a very fast assistant. For learners, it can provide examples and explanations on demand – though not always reliable ones.
But it does change the developer’s role.
The valuable engineer is no longer merely the person who can produce syntactically correct code. That was never enough, but it is now even less enough.
The valuable engineer is the person who can hold the system in their head.
The person who understands intent.
The person who can say:
This solution works locally but damages the architecture.
This abstraction is premature.
This duplication is acceptable for now.
This generated code hides an operational risk.
This test proves behaviour, but not the behaviour we actually care about.
This design will not survive the next requirement.
That is design work.
It always was.
AI does not remove that responsibility. It exposes it.
Code Is Still Design
So, does AI weaken the “code is design” argument?
I think it does the opposite.
If anything, it proves the point.
The reason generated code matters is precisely because code is not just mechanical output. It is the detailed design of the system. If AI were merely laying bricks, the risk would be lower. But it is drafting structural decisions, sometimes thousands of them, faster than we can comfortably inspect.
That changes the economics of software.
It does not change the nature of software.
The compiler still manufactures the running program. AI now helps draft the design document. But the design still needs intent, judgement, taste, constraint, context, and accountability.
Those are human responsibilities.
At least, they are if we still care whether the thing stands up.
The Real Shift
The real AI shift is not that developers are being replaced as designers.
It is that developers are being forced to become more explicit about design.
For years, much of software design happened invisibly inside the coding process. Good developers made good decisions while writing code. Bad decisions were often hidden behind estimates, deadlines, ticket systems, and the comforting fiction that programming was just implementation.
AI makes that fiction harder to maintain.
If a machine can generate the implementation, then the human contribution has to be clearer. Not more mystical. Not inflated. Just clearer.
What problem are we solving?
What constraints matter?
What must not break?
Where should the boundaries be?
What does this system need to become over time?
Those questions were always the real work. We just allowed the industry to confuse them with typing.
The future developer may write fewer lines by hand. But if they are doing the job properly, they will be thinking harder about the lines that enter the system.
Because code is still design.
And design still needs a designer.


