· 6 min read ·

The Code That Works but Has No Why

Source: hackernews

There are two different kinds of understanding that matter in software development, and the comfortable drift toward not understanding what you’re doing affects them at different rates.

The first kind is operational understanding: can you read this code and figure out what it does? Can you trace a call stack, interpret an error, follow the data flow? This is recoverable. Given time and a working system, a developer can reconstruct it by reading carefully. It is the kind of understanding that most drift debates focus on.

The second kind is design understanding: why is this code the way it is? What alternatives were considered? What constraints shaped the current structure? What does this component assume about the rest of the system, and what did the author think was likely to change versus stable? This knowledge lives almost entirely in the heads of whoever made the decisions. It rarely makes it into the code, the tests, or the commit messages.

When AI generates code, the second kind of understanding never forms in the first place.

The piece making rounds on Hacker News this week frames the core problem well: the threat is the comfortable drift toward not understanding what you’re doing. That framing is correct, and it applies harder to design understanding than to operational understanding, for reasons the discussion tends to gloss over.

The Decision Record That Wasn’t Made

When a developer writes a service, some version of the design alternatives lives in their head, even informally. They rejected three or four approaches before landing on this one. They chose between a polling model and an event-driven one based on expected usage patterns they understood at the time. They made the service synchronous or async based on constraints they had considered. This knowledge is rarely documented anywhere, but it exists, and it becomes available when someone later asks why the system works this way or whether it can safely be changed.

When an AI generates that same service, nobody made those trade-offs consciously. The model picked a reasonable default approach from the space of reasonable approaches it has encountered. The developer accepted it because it worked. The reasoning behind the structure was never built.

This matters because the most expensive decisions in software are not the ones you make initially. They are the ones you make later, when you need to extend or change something and have to figure out what is safe to touch. That decision requires knowing what assumptions the code encodes, what the original structure was optimized for, what the edge cases are that were not handled because they were considered unlikely at the time. Operational understanding tells you what the code does. Design understanding tells you what it was trying to do and what it was not trying to handle, which is the knowledge you need to change it safely.

If nobody built that model, the path to it is reverse-engineering from the code itself, and code is a poor guide to the reasoning that shaped it.

How This Surfaces Against Changing APIs

Building against external APIs makes this concrete. Discord’s bot platform has gone through several substantial changes: the gateway intents system that restricted which events bots could receive, the shift from message-based commands to slash commands, the interaction model that changed how responses work and what timing constraints apply. Each change required developers to understand not just what their code did but what it had been assuming about the API.

If you built the bot with genuine design understanding, adapting to a change is hard but navigable. You know what you were assuming. You know which parts of the code will break and roughly why they will break. You have a mental model of the architecture that tells you which assumptions are localized and which are load-bearing across the whole system.

If you built the bot with AI assistance and never formed that understanding, adapting to a capability change is a different class of problem. You have to reconstruct both the new API’s behavior and the existing code’s assumptions about the old behavior, simultaneously, without any reference to the original reasoning. The code works in the pre-change world, and navigating the change requires understanding that was never built.

This is the version of drift that the Ergosphere piece points toward without fully naming. The problem is not only that you might not understand the code you have. It is that the code might have been built in a way where the design reasoning has never existed and cannot be recovered, because there is no one to recover it from.

Why Code Review Misses This

Code review catches shallow operational understanding imperfectly and catches absent design understanding essentially not at all. When a reviewer evaluates AI-generated code, they are assessing whether it looks correct, handles the obvious cases, and follows conventions. They are not evaluating whether the author has a model of why this structure was chosen rather than alternatives, because the author often does not.

The absence does not show in the diff. The code looks the same either way. A reviewer reading AI-generated code and developer-understood code at the same level of correctness cannot tell from the code which one came with design understanding attached and which did not.

This is one of the mechanisms behind a pattern teams experience when they shift heavily toward AI-assisted development: a period of high output followed by increasing friction when structural changes are needed. The early work was fast and the code was fine. The structural changes are slow because the design understanding that would guide them was never built, and every change requires reconstructing that reasoning from scratch rather than building on an existing model.

What Inheritance Looks Like Without the Understanding

Individual design understanding erodes through inattention. Organizational design understanding erodes through turnover, but the erosion has a floor when the original developers built genuine models. New developers inherit an imperfect version through documentation, code review comments, pair programming, and the institutional memory that senior engineers carry.

When a system was built with AI assistance and the developers never formed design understanding, there is nothing to inherit. Documentation says what the system does. No one knows why it is structured this way rather than some other way. Every new developer reconstructs the reasoning from the observed behavior, and changes accumulate that seemed reasonable given the code as seen, without the constraint of knowing what the original structure was built to handle.

The coherence of a system’s design degrades faster under these conditions than under normal turnover, because normal turnover degrades an existing model while this starting condition means there was no model to degrade.

The Countermeasure That Addresses This Specifically

Writing architecture decision records is unfashionable partly because it is slow and partly because developers tend to document decisions they are confident in. The decisions worth documenting are the ones with real alternatives that were considered and rejected, particularly the ones where the rejected alternative looked plausible. That knowledge does not survive in code.

For AI-assisted development specifically, there is a practice that maintains design understanding without slowing down much: before accepting a generated implementation of anything structural, form the trade-off explicitly. Not necessarily in a document, but somewhere that has words attached. What would a different approach have looked like? Why does this structure make sense given how this will be used? What assumptions does this encode, and what would break them?

The AI can fill in the implementation. The reasoning about which implementation fits this particular system has to come from somewhere else, and if it comes from nowhere, the code will work until it needs to change.

The machines are fine. The specific risk the ergosphere.blog piece is pointing at is that they are making it comfortable to ship systems where the code runs but the understanding of why it was built this way lives nowhere, in no one’s head, and in no document, because it was never built at all.

Was this interesting?