· 5 min read ·

Every Abstraction Is a What/How Translation. LLMs Changed the Nature of the Guarantee.

Source: martinfowler

The first thing to recognize about Martin Fowler’s conversation with Unmesh Joshi and Rebecca Parsons is that the central challenge they describe, building systems that survive change by managing cognitive load through a clean separation of what and how, is the oldest problem in computing.

Every abstraction layer accumulated over seventy years of software development is a what/how translator. Fortran over assembly: specify mathematical intent, let the compiler produce machine instructions. SQL over record traversal: describe the data you want retrieved, let the query planner choose the execution path. CSS over DOM manipulation: declare the visual state, let the browser render it. Infrastructure as Code over raw provisioning API calls: describe the topology you need, let the tool sequence the calls.

-- What: give me active users sorted by signup date
SELECT id, name, created_at FROM users
WHERE status = 'active'
ORDER BY created_at DESC;

-- How: the query planner decides whether to use an index scan,
-- a sequential scan, or a hash join, based on table statistics.
-- The developer does not specify this, and generally should not.

The pattern is consistent. Each abstraction succeeded by hiding a class of “how” decisions below the line of concern for the developer working above. The value was cognitive: every detail you no longer have to manage frees capacity for the problem you actually care about. Miller’s Law, the constraint of roughly seven chunks in working memory at once, is the underlying reason any of this matters. Good abstractions are compression algorithms for human attention.

Where LLMs Fit in This History

The Fowler conversation positions LLMs as the newest layer in this sequence. When you describe a feature in natural language and an LLM generates a working implementation, the LLM is performing the same structural operation that a compiler or query planner performs: it translates your specification of what you want into a concrete realization of how it gets done.

This framing clarifies something that gets obscured in most discussions about AI coding tools. LLMs are not doing something categorically different from what Fortran’s compiler did in 1957. They are extending the same trajectory, moving more of the what-to-how translation work out of the developer’s hands and freeing up cognitive space for higher-level problem framing.

The difference is in mechanism. Compilers and query planners perform deterministic, formally specified translations. Given a valid SQL query, the database returns the correct result set. Given syntactically valid C, the compiler produces code with the specified behavior. The translation may be slow or suboptimal, but it is correct within the language’s formal semantics.

LLM translation is probabilistic. The same natural language prompt, issued twice, can produce two different implementations. Either implementation may contain subtle errors that look plausible on first read. The translation is not guaranteed to be correct even when it is fluent.

// Prompt: "add a method that returns the top 5 users by activity score"

// Generation A: sorts ascending (wrong direction)
const top5 = users.sort((a, b) => a.activityScore - b.activityScore).slice(0, 5);

// Generation B: sorts descending but operates on the wrong user pool
const top5 = allUsers
  .filter(u => u.role !== 'admin')
  .sort((a, b) => b.activityScore - a.activityScore)
  .slice(0, 5);

// Generation C: correct
const top5 = users.sort((a, b) => b.activityScore - a.activityScore).slice(0, 5);

In each case the specification was identical; the “how” varied in correctness.

This is the specific change the Fowler conversation is pointing at. The what/how loop has always required developers to understand both sides: you need to know enough about the “how” to write a precise “what”, and you need to evaluate the translation for correctness. With deterministic translators, the evaluation requirement was lightweight: if the code compiled and the tests passed, you could generally trust the translation. With probabilistic translators, that evaluation requirement is no longer lightweight. You need genuine understanding of the “how” to detect a plausible but incorrect translation.

The Learning Loop Is Load-Bearing

This is the concern Unmesh Joshi raised in The Learning Loop and LLMs, published in November 2025. His argument is that LLMs become counterproductive when used to shortcut the learning loop: the iterative cycle through which developers build genuine understanding of the “how” by working through it, hitting failures, and tracing the reasons.

The learning loop is how the “how” layer becomes internalized knowledge, and that internalized knowledge is precisely what makes evaluation of probabilistic translations possible. A developer who has implemented pagination from scratch, hit the N+1 query problem, debugged slow index scans, and read query plans has built a mental model of what the database is doing. When an LLM generates a paginated query, that developer can evaluate it. A developer who learned SQL entirely from LLM output has not built that model.

Structurally, if you never engage deeply with the “how”, you cannot build the evaluation capacity that makes probabilistic translation safe to rely on. The productivity gain is real in the short term; the professional development cost accretes silently.

Rebecca Parsons brings programming language theory to this analysis. In formal terms, the what/how separation corresponds to the distinction between a language’s semantics (what a program means) and its operational implementation (how those semantics get executed). Denotational semantics and operational semantics are the formal machinery for making this distinction precise. Parsons’ background makes her attentive to the conditions under which an abstraction actually holds: what it assumes, where it leaks, and what you need to know about the layer below in order to use the layer above safely.

The Loop Runs Both Ways

The “loop” in the conversation’s title refers to something important: the relationship between what and how is iterative rather than directional. When you encounter unexpected behavior at the “what” level, you reach into the “how” to diagnose it. That contact produces information that updates your mental model, which in turn sharpens your ability to write better specifications next time.

Every developer who has been surprised by SQL at scale has learned something that made their subsequent queries better. Every developer who has hit React’s reconciliation edge cases has built a model that makes their subsequent component design sharper. The “how” is a source of feedback that continuously improves your ability to work at the “what” level.

LLMs accelerate the what-to-how translation, but they do not change the direction of learning that flows back from the how to the what. If anything, they make that feedback loop more valuable. Because generation is cheap and mistakes are plentiful, the signal that distinguishes good specifications from bad ones becomes domain understanding, not implementation effort.

The abstraction ratchet has never eliminated the need to understand what lies below. Garbage collection moved memory management below the line, but developers who understand memory allocation write better-performing code under GC. SQL moved query planning below the line, but developers who understand indexes write faster queries. The layer below remains a source of leverage for those who have internalized it.

LLMs are the next click of that ratchet. Natural language specification moves more of the what-to-how translation below the line. Avoiding engagement with the “how” by relying entirely on LLM output trades short-term velocity for a foundation whose correctness has never been verified.

Was this interesting?