· 6 min read ·

The What/How Gap Has Always Existed. LLMs Just Changed Who Crosses It.

Source: martinfowler

A conversation published on martinfowler.com in January 2026 between Unmesh Joshi, Rebecca Parsons, and Martin Fowler frames a familiar tension in software development in a new light: the gap between the what of a problem and the how of its implementation. Their argument, loosely, is that LLMs let developers stay at the “what” level longer, with the model handling more of the “how.” This framing is worth taking seriously, but it also has a history that the conversation doesn’t fully excavate.

The what/how distinction isn’t something LLMs introduced. It’s the axis along which every programming language abstraction in history has moved.

A Very Old Problem

In the early 1950s, programmers wrote machine instructions. There was almost no “what” layer; you described the how in excruciating detail. Assembly was a thin layer of symbolic convenience. FORTRAN, in 1957, was the first serious attempt to let a developer write something closer to mathematical intent and have the compiler figure out the implementation. The reaction from working programmers at the time was skeptical: many believed hand-written assembly would always outperform anything a compiler could produce. They were wrong, but the skepticism wasn’t irrational. Trusting an automated system with your “how” requires trust in its competence.

This cycle has repeated with every major abstraction layer. SQL lets you declare what you want from data and leaves the query planner to determine how to retrieve it. Prolog takes this further: you state logical relations and the inference engine decides execution order. Domain-Specific Languages like Terraform’s HCL or Kubernetes manifests are explicitly designed around the what, abstracting away the operational how. The 1980s and 1990s had their own version of this promise under the label “4GL” (fourth-generation languages), tools like PowerBuilder, Clipper, and later low-code platforms, that claimed to close the gap between business intent and working software.

Most of the 4GL wave didn’t survive contact with production complexity. The abstractions leaked. When the what you could express didn’t map cleanly onto the how the tool could generate, developers had to descend into the implementation layer anyway, often into undocumented or poorly-supported internals.

What’s Actually Different

The Fowler/Joshi/Parsons conversation is specifically about cognitive load, drawing on Sweller’s cognitive load theory as a lens. The argument is that building systems that survive change requires managing the mental overhead of holding both what and how in working memory simultaneously. Good abstractions reduce that overhead by letting developers reason at the level of intent without constantly tracking implementation details.

LLMs change this dynamic in a specific way: they shift the how-knowledge out of the developer’s working memory and into the model’s weights. You can write:

# Parse all ISO 8601 timestamps from a log file and return
# only those within the last 24 hours, handling timezone offsets
results = extract_recent_timestamps(log_file, hours=24)

And prompt an LLM to implement extract_recent_timestamps without the developer needing to hold in mind the edge cases of datetime, pytz, UTC offset arithmetic, or the precise regex for ISO 8601 variants. The model handles the how. The developer stays at the what.

This is genuinely different from the 4GL wave for one reason: generality. A 4GL was a domain-specific what-to-how translator. It worked within a narrow vertical. An LLM can bridge the what/how gap across an enormous range of domains simultaneously. When the abstraction leaks, you can often describe the leak in natural language and get a repair. The ceiling is much higher.

Cognitive Load Redistribution, Not Elimination

But the Fowler conversation is careful not to claim the problem is solved, and that care is worth expanding on. Cognitive load isn’t eliminated when an LLM handles the how; it’s redistributed. The developer now carries a different kind of load: the work of specifying the what precisely enough that the model’s how matches the actual intent.

This is harder than it sounds. Yann LeCun has argued that natural language is an imprecise medium for specification because it was designed for communication between humans who share vast amounts of implicit context. When that context isn’t shared with the model, the what description becomes a source of ambiguity rather than a reduction of it. The developer who hands a vague requirement to an LLM gets a confident, syntactically correct how that may quietly violate the actual intent.

This is a cognitive load problem of a different shape. Instead of tracking implementation details, the developer must now be more explicit about constraints, edge cases, and invariants than they might have been when writing the code themselves. Writing code is often a form of specification: the act of implementing something forces you to make implicit assumptions explicit. When you outsource the implementation, you lose that feedback loop.

The Abstraction Design Question

The most interesting part of the Fowler/Joshi/Parsons argument, at least from the excerpt available, is the claim that LLMs help us “shape the abstractions in our software.” This is worth sitting with.

Traditionally, abstraction design is one of the highest-skill activities in software engineering. The question of what a type, module, or service boundary should represent, what its public interface should look like, and what invariants it should enforce is genuinely hard. Bad abstractions are expensive; they make the codebase rigid, they leak their implementation details, and they resist change. Eric Evans’s Domain-Driven Design is largely a methodology for getting abstraction design right by grounding it in the domain’s own vocabulary.

What the conversation seems to gesture at is that LLMs can accelerate the exploration of abstraction candidates. You can describe a domain concept in natural language, ask the model to propose several ways to represent it in code, and evaluate those representations against your domain’s actual behavior. The iteration cycle is short enough that you can explore more of the design space before committing.

This is plausible, and it parallels how experienced developers use prototyping. The concern is whether the LLM’s proposals are grounded in the domain or grounded in common patterns from training data. Common patterns from training data are not always the right abstractions for a specific domain. The Strangler Fig pattern, for example, is an abstraction that emerges from a specific migration context; a model trained on typical CRUD applications might not propose it when it’s the right fit.

The Skill Erosion Question

There is a concern that the Fowler conversation doesn’t address directly but that deserves mention: what happens to a developer’s ability to design good whats when they spend years delegating the how to a model?

In traditional development, writing the how is often how you develop the intuition for good whats. The developer who has implemented several cache invalidation strategies has a richer vocabulary for describing caching requirements. The developer who has written a query optimizer has better instincts for what a database schema should look like. The craft of the how feeds back into the precision of the what.

If LLMs steadily absorb more of the how work, it’s reasonable to ask whether the next generation of developers will have a thinner basis for evaluating the model’s output. This isn’t a reason to avoid using LLMs, but it does suggest that the abstraction design skill the Fowler conversation values will require more deliberate cultivation, not less, in an LLM-assisted workflow.

What Hasn’t Changed

The fundamental challenge in building systems that survive change, which is how Fowler frames the problem, is not primarily a what/how problem. It’s a problem of keeping the what and the how aligned over time as requirements shift, teams change, and understanding deepens.

LLMs make the initial translation from what to how faster and cheaper. They don’t yet have a good answer for the accumulated distance between documented intent and running code that characterizes every long-lived system. The value of practices like continuous refactoring, architectural fitness functions as described in Building Evolutionary Architectures, and lightweight Architecture Decision Records comes precisely from keeping that distance small over time.

The Fowler/Joshi/Parsons conversation is a useful frame for thinking about where LLMs actually change the developer’s cognitive work. The what/how distinction gives you a vocabulary for that. But the history of abstraction in programming suggests treating any tool’s claim to close the what/how gap with careful attention to the seams it creates, and the skills it requires you to maintain to work around them.

Was this interesting?