An uncomfortable idea is spreading among programmers: perhaps we no longer need to understand every line of the code we produce.

Put that way, it sounds almost offensive. For decades we have associated engineering quality with depth of understanding. The good programmer seemed to be the person who could mentally traverse the system, explain its pieces, and know exactly where to look when something broke.

Two recent videos put that intuition under pressure. The Spanish-language video “Esto no va a parar nunca…” reacts to Theo Browne’s argument in “Stop Pretending You Understand Your Codebase”. Theo, in turn, builds on Sean Goedecke’s essay “In defense of not understanding your codebase”.

The chain is interesting because the discussion starts as a defense of partial understanding in large systems and ends up colliding directly with AI-assisted programming.

The resulting claim is not that engineers can stop understanding what they are doing.

It is more precise:

Not understanding all the code is not the same as not understanding the system.

As agents become capable of producing code far faster than humans can, that distinction may become one of the central ideas of software engineering.

The myth of the programmer who knows everything

Think about an operating system, PostgreSQL, a platform backend with hundreds of millions of lines, or infrastructure that has evolved for more than a decade.

Does one person really understand every function, dependency, edge case, deployment path, and historical behavior?

Probably not.

What looks like complete knowledge in an experienced engineer is usually something else: strong intuition about how the system is organized.

That engineer may not remember the exact file that contains a particular function, but can often predict:

  • which subsystem should own it;
  • what other components probably interact with it;
  • which invariants must not be broken;
  • where to look for evidence;
  • which tests to run;
  • which telemetry to inspect if something goes wrong.

That distinction matters.

A healthy codebase is not necessarily one where everybody knows every file. It is one where somebody who does not know a detail can find it, build enough context, and change it safely.

At scale, navigation matters more than memorization.

Peter Naur and the “theory of the program”

This debate is much older than LLMs.

In 1985, Peter Naur published “Programming as Theory Building”, a classic essay about what programming really is.

Naur argued that the most important output of software development is not simply the code. Programmers build a theory of the program: a mental model of the problem, why the system is built in a certain way, and how it should respond to change.

Code and documentation capture only part of that theory.

That remains a powerful insight. Anyone who has inherited an old system knows the difference between reading files and understanding why certain decisions exist.

But Sean Goedecke points out a problem: taken too far, that model does not fit modern large-scale systems very well.

If the theory lives only in the heads of the original team, what happens when that team disappears?

Large systems are not automatically discarded. Teams reorganize, engineers leave, ownership changes, and abandoned services are revived.

A workable theory can be reconstructed partially.

Teams usually do this by following one real flow end to end, understanding one region, making small changes, and expanding their map over time.

We do not need a perfect theory before we can act.

We need a theory that is good enough for the decision in front of us.

Everyone works with an incomplete model

This is probably the most important observation in Goedecke’s essay and Theo’s reaction.

In a sufficiently large system, everyone operates with an incomplete and partly incorrect theory of the program.

That is not necessarily incompetence. It is a consequence of scale.

One engineer may know a service deeply and only understand twenty neighboring services at a high level. Another may know the infrastructure but not the frontend. A third may understand the business domain deeply while only loosely understanding storage internals.

The system remains maintainable because we combine several forms of support:

partial mental model
        +
architecture and conventions
        +
navigation tools
        +
types and static analysis
        +
tests
        +
observability
        +
review and experience

Absolute certainty is replaced by accumulated evidence.

Professional engineering already worked this way long before ChatGPT, Claude, Codex, or Cursor.

We were already delegating understanding before LLMs

When we use a statically typed language, we do not manually inspect every value to confirm that it has the right shape.

We delegate part of that responsibility to the compiler or type checker.

A linter takes over another set of checks.

When we use a database, we do not memorize the exact internal implementation of every storage structure.

When we import a library, we accept an abstraction containing code we will probably never read in full.

When we consume an external API, we work from a contract without necessarily knowing its implementation.

Software engineering is built around not having to understand every layer simultaneously.

Abstractions are cognitive offloading mechanisms.

LLMs do not invent that delegation.

What they change is the magnitude.

Agents are repeated “100% turnover”

Theo offers an especially useful analogy for coding agents.

Every new agent conversation resembles bringing a new developer onto the project.

The model may be extremely capable. It may know Python, Rust, TypeScript, Kubernetes, and SQL better than many humans. But at the start of a fresh thread, it does not possess the specific history of our system.

It was not in the meeting where an odd exception was agreed on.

It does not remember the production incident from six months ago.

It does not know that an ugly-looking function exists to preserve compatibility with an old customer.

It has to reconstruct the theory from what it can inspect.

And with a new session, much of that context has to be reconstructed again.

Seen this way, a codebase prepared for agents has many of the same properties as a codebase designed for excellent human onboarding:

  • clear architectural boundaries;
  • predictable naming;
  • local, current documentation;
  • explicit contracts;
  • reliable tests;
  • reproducible commands;
  • visible failures;
  • accessible observability;
  • a short path from “I don’t know this” to “I know enough to change it.”

AI does not remove the need to design understandable software.

It may increase it.

The problem with magical rewrites

The same debate matters when people propose full rewrites.

From the outside, an old system can look absurdly complicated. An agent can inspect it and propose something far cleaner. In minutes it can generate thousands of convincing lines for a replacement.

But mature products contain something rarely captured completely in documentation: history.

Edge cases.

Compatibility with strange clients.

Legal requirements.

Workarounds for old failures.

User expectations that were never formalized as specifications.

Production itself becomes a kind of record of those compromises.

That is why successful rewrites usually move incrementally: isolate a boundary, reproduce behavior, migrate, measure, and continue.

LLM generation speed does not eliminate that reality.

We can generate the new system faster than ever while still failing to know which behaviors of the old system were essential.

Writing the replacement stops being the hard part.

Defining what “correct replacement” means becomes the hard part.

The real shift: we can produce more code than we can read

This is where AI introduces something qualitatively different.

Historically, human code-writing speed and human review capacity existed within roughly comparable orders of magnitude.

Agents break that symmetry.

A developer can describe a task for a few minutes and receive hundreds or thousands of changed lines. Multiple agents can work in parallel. A workflow can generate application code, tests, migrations, documentation, and infrastructure changes without a human manually typing every line.

OpenAI documented an extreme version of this in “Harness engineering: leveraging Codex in an agent-first world”: a small team built an internal product where application logic, tests, CI configuration, documentation, and other artifacts were generated by Codex. The team consequently spent less attention on writing code and more on making the environment legible to agents, building feedback loops, and turning system knowledge into repository-local, verifiable artifacts.

That suggests an important transformation.

If code production rises 10x, 100x, or more, requiring a human to read and memorize all generated implementation simply moves the bottleneck back to the same place.

The question changes from:

“Have I read all this code?”

To:

“Do I have enough evidence to trust this change?”

Those are not the same question.

The new unit of understanding

In an agentic workflow, the main unit of human understanding may stop being the function or even the file.

It may look more like this:

1. Intent

What problem are we solving?

What observable behavior should change?

2. Architecture

At which boundary should this behavior live?

Which components may depend on which others?

3. Invariants

What must remain true even if the implementation changes?

For example:

a payment cannot be processed twice
one tenant cannot read another tenant's data
a published episode cannot be duplicated
a failed deployment must be detectable

4. Contracts

What goes in and what comes out?

Which schemas, APIs, types, and protocols define the boundaries?

5. Evidence

Which tests prove that the change works?

Which evaluations cover difficult cases?

6. Production behavior

Which logs, metrics, traces, and alerts tell us what happened after deployment?

That knowledge can provide more control over a system than memorizing the implementation of 200 helper functions.

Not reading every line cannot mean abandoning judgment

There is an important limit here.

The argument can be pushed too far and become an excuse to accept whatever the model produces.

That would be a mistake.

An agent can generate syntactically correct code, pass an incomplete test suite, and still violate a business assumption.

It can copy an existing pattern that was already bad.

It can introduce unnecessary complexity.

It can solve the wrong problem perfectly.

Partial understanding works only when it is paired with mechanisms that reduce uncertainty.

The sensible evolution is not:

before: human understands the code
now: nobody understands anything

It is closer to:

before:
human writes + human inspects much of the implementation

now:
human specifies intent
        ↓
agent implements
        ↓
contracts + tests + analysis + review
        ↓
CI validates
        ↓
observability confirms real behavior
        ↓
human judgment handles what evidence cannot settle

Control does not disappear.

It moves up a layer.

From code review to system review

That may also change what software review means.

Traditional code review often asks:

  • is this method well written?;
  • is this name good?;
  • can these ten lines become five?;
  • is this abstraction elegant?

Those questions still matter, but with much higher change volume the more important ones may become:

  • does this solution respect the architecture?;
  • are contracts still compatible?;
  • what new behavior appears?;
  • which failure are we not testing?;
  • how will we know in production if it goes wrong?;
  • what evidence shows that the agent understood the task correctly?

Part of review shifts from the shape of the code toward the behavior of the system.

The real risk: epistemic debt

Technical debt is familiar: we take a shortcut today and pay complexity tomorrow.

Agents introduce another kind of debt we might call epistemic debt.

It appears when the system changes faster than our ability to reason about it.

For example:

+50,000 generated lines
+20 new modules
+7 new services
-0 new architecture maps
-0 documented invariants
-0 additional observability

The software may work today.

But the organization knows less and less about why it works.

That is a serious problem.

The answer does not have to be forcing one person to read all 50,000 lines.

It can be requiring code growth to be matched by growth in system legibility.

Updated architecture.

Behavioral tests.

Explicit interfaces.

Observability.

Decision history.

Tools for reconstructing context quickly.

Designing for humans and agents converges

There is a paradox here.

Optimizing a repository for agents may sound like making it less human.

Often the opposite happens.

An agent needs to find where a responsibility lives quickly.

So does a new employee.

An agent needs reproducible commands for tests.

So does a human.

An agent works better with explicit contracts.

So does a team.

An agent needs important rules to be discoverable instead of buried in old chat threads.

So does the next engineer who joins the project.

The pressure created by agents may force organizations to convert tribal knowledge into knowledge infrastructure.

That would be a genuine engineering improvement regardless of who writes the lines.

So what should a programmer understand?

There is no universal answer.

In small firmware or a critical library, understanding almost every line may remain both realistic and desirable.

In a huge distributed system, it never was.

Agents will push that boundary further.

But several forms of understanding are likely to become more valuable:

  1. the problem domain: what the user actually needs;
  2. the architecture: how responsibilities are separated;
  3. data flows: what enters, transforms, and leaves;
  4. failure modes: how the system can break;
  5. invariants: what must never happen;
  6. quality signals: tests, evaluations, analysis, and metrics;
  7. trade-offs: why one solution was accepted over another;
  8. actual production behavior.

It is possible not to know the exact implementation of a function generated yesterday and still retain deep control over all of those elements.

It is also possible to read every line and fail to understand the product being built.

Programming does not disappear; the location of thought changes

The debate raised by these videos should not collapse into “vibe coding good” or “vibe coding bad.”

The interesting question is where we want to spend scarce human attention.

For decades, a large share of that attention went into translating intent into syntax and maintaining implementation details in our heads.

Compilers, frameworks, types, linters, and libraries already moved some of that work into other layers.

Agents accelerate the process dramatically.

If the trend continues, the most valuable engineer may not be the person who can recite the largest amount of code from memory.

It may be the person who can enter a system nobody fully understands, rapidly build a useful model, formulate strong constraints, direct humans and agents, demand evidence, and detect when real behavior contradicts the current theory.

In that world, “I do not understand the whole codebase” stops being an embarrassing confession.

It becomes the starting point.

The critical skill is knowing what must be understood deeply, what can be delegated, and which mechanisms let us trust what we do not keep inside our own heads.

If agents keep multiplying the amount of software we can produce, that skill will only become more important.

Sources

Complementary resource