Partial understanding is the best you can do
- YT :: https://www.youtube.com/watch?v=5KvY8CnBB3w
- Original title :: Stop Pretending You Understand Your Codebase
Theo reads Sean Goedecke's article "In defense of not understanding your codebase" and agrees with nearly all of it: in large systems nobody holds a correct theory of the program, and pretending otherwise is a cultural pose rather than an engineering standard. The value of a good codebase is not that everyone knows where everything is, it's that finding the right place for a change is fast. Agents make the point sharper because every new thread is a full team turnover.
The myth of the engineer who knows everything
The industry mythologises programmers who supposedly hold the whole system in their heads. What strong engineers actually have is intuition about where things should live, derived from a higher-level sense of how software is architected, plus the habit of moving code so that it ends up where it belongs — for themselves and for less familiar contributors.
Theo's own relationship with his codebases is now a wider spectrum than ever: some parts he understands better than he ever did, and more parts he understands not at all. He defends the second category.
Theo also notes he'd word Goedecke's thesis slightly differently: not "partial understanding", but that the depth of understanding should vary by location. You should know how the pieces fit together before changing your isolated corner, without pretending to know each piece's internals.
Against "programming is theory building"
Goedecke's target is Peter Naur's 1985 paper, whose core claim is that the code is a byproduct and the real product is the programmer's theory of the program — a theory only partially capturable in code or docs. Both Theo and Goedecke accept that part: a lot of what you know about a codebase (where it fails, why, what's load-bearing) genuinely cannot be written down. Anyone who has tried to set up a repo for agents already knows there is no prose file that contains everything needed.
Where Naur goes too far is the prescription: if the theory is lost, discard the program and let a fresh team rebuild. Goedecke's two objections:
- You can't rebuild large systems from scratch. Systems with users accumulate thousands of quirks and special cases that even the incumbent team couldn't reimplement. Theo endorses the related point that every successful rewrite actually proceeds by carving the old system into isolated chunks and replacing them one at a time — i.e. a rewrite is a long series of changes to the old system.
- Abandoned codebases are revived all the time. A few resignations or a year of neglect leaves code with no living expert, and engineers routinely adopt such code, learn one flow end to end, and branch out from there. Building a new theory is possible.
Naur's scale is also dated: his "large program" was 200k lines, and GCC in 1987 was ~100k lines against 14M+ in 2015. Rewriting 200k lines with reusable tests is plausible; rewriting millions of lines of user-facing behaviour is not, because you cannot end-to-end test for "users still get the same data in the same shape".
Theo's aside on rewrites: he is often the person arguing for one, but he always starts by working in the existing codebase first, and considers a core understanding a precondition for proposing a rewrite. The typical "I rewrote it in Rust" pitch comes from people who never diagnosed the original — he recounts a DM justifying a rewrite with a hallucinated LLM rant about Electron, ending in a plug for the sender's own alternative. Those people make credible rewrite proposals look worse by association.
Everyone's theory is wrong, and that's workable
In big enough codebases, everybody operates with an incorrect theory. Theo's illustration: one of the strongest full-stack engineers he ever worked with, years into Twitch, hit inexplicable client-side type errors — he had simply never run the GraphQL codegen step, because he'd never built both sides of a query at once. Everyone else assumed something deep was broken because of who was asking.
The upshot is that effectiveness requires not knowing everything, because the effort and working memory needed to know everything crowds out shipping. This is the same argument Theo used to make for TypeScript: offloading "did I pass the right type" to the compiler makes you introspect the code less, but frees enough of your brain that you ship faster with fewer bugs. Any mechanism — compiler, linter, type checker, AI reviewer — that takes tedium off your brain is worth it as long as your overall understanding doesn't drop.
For partial correctness you need a working method: don't wait for someone with perfect understanding to arrive: make your most educated guess, take a position with confidence, and deal with the consequences. New developers struggle here most, going from code they wrote every line of to a codebase older than their career.
Theory-building is one value among many
The claim that LLMs are bad because they impede theory building is too simplistic. LLMs are double-edged: they make a detailed mental theory harder to build, but they let you build a partial theory fast and leverage it better. Both Theo and Goedecke consider the trade-off unresolved.
More importantly, plenty of uncontroversially good things also degrade your theory of the codebase: other people committing to it, legally required features like accessibility and data protection, colleagues quitting or changing teams (and taking vacations), security upgrades, and every dependency you pull in. Nobody calls those bad. Maintaining a theory of the codebase is one value to be traded against speed, compliance, politics, or platform support — sometimes it wins, often it doesn't.
Theo adds the AI-optimistic note that agents have made ramping up on an unfamiliar codebase much easier: you can interrogate it and verify the answers. The agent lacks the departed team's historical knowledge but has their output, which is usually enough.
Pure vs impure engineering
Goedecke's earlier framing explains much of the online friction: pure engineering solves technical problems as perfectly as possible (libraries, engines, open source), while impure engineering solves real-world problems as efficiently as possible under a deadline (most paid work). Nearly all engineers, especially pure ones, prefer an accurate mental model — it's more fun, less stressful, and feels like "real engineering".
Theo calls this the contradiction he had felt for years without being able to word it: the work that feels like real engineering and the work that makes you worth employing barely overlap. That gap is why so much online discourse is people on the pure side dumping on people on the impure side. Wanting to keep an accurate theory is also why many engineers take small side projects — nothing wrong with that, but at work you're paid to adopt your employer's engineering values, the same way you sometimes have to ship slow code to hit a date.
On the comment sections: Goedecke's post was tagged "vibe coding" over a single paragraph, and Theo agrees it isn't an AI post. Against the sneer that Goedecke only writes "vocabulary explainers for people who want to know what their tech leads are talking about", Theo's position is blunt — understanding the people who hand you work is part of the job, and an engineer who can't work with their team and users to solve real problems is now outclassed by an LLM.
Where this goes
Theo closes with a quoted take he thinks is roughly right: as AI multiplies the volume of code, codebases become even less holdable in a head, so the engineer's skill becomes navigating a mental labyrinth on imperfect information. His live example is rewriting the T3 Code mobile app from React Native to SwiftUI — 60k+ lines of Swift he has not read a single line of. His steering comes entirely from observed failure cases plus his model of how the feature works in the system being mirrored; only one or two bugs (oddities like project selection for new threads) needed more than "mirror the other implementation".
Structural understanding of where things live and how data flows transfers; implementation details turn out not to be needed. Theo frames it as being a new developer again, and finds the balance between understanding more and understanding less the fun part of the current moment.