PostHole
Compose Login
You are browsing us.zone2 in read-only mode. Log in to participate.
rss-bridge 2026-01-21T14:40:00+00:00

Conversation: LLMs and the what/how loop

A conversation between Unmesh Joshi, Rebecca
Parsons, and Martin Fowler on how LLMs help us
shape the abstractions in our software. We view our challenge as building
systems that survive change, requiring us to manage our cognitive load. We
can do this by mapping the “what” of we want our software to do into the
“how” of programming languages. This “what” and “how” are built up in a
feedback loop. TDD helps us operationalize that loop, and LLMs allow us to
explore that loop in an informal and more fluid manner.

more…


Conversation: LLMs and the what/how loop

*A conversation between Unmesh, Rebecca, and Martin on how LLMs help
us shape the abstractions in our software. We view our challenge as building
systems that survive change, requiring us to manage our cognitive load. We can
do this by mapping the “what” of we want our software to do into the “how” of programming
languages. This “what” and “how” are built up in a feedback loop. TDD helps us
operationalize that loop, and LLMs allow us to explore that loop in an
informal and more fluid manner.*

21 January 2026


Unmesh Joshi

Unmesh is a Distinguished Engineer at Thoughtworks, based in Pune,
India. He is the author of Patterns of Distributed Systems.

Rebecca Parsons

Rebecca is a Technology Strategy Consultant, board member and
co-author of Building Evolutionary Architectures

Martin Fowler

Martin is the host of martinfowler.com, the author of Refactoring, and the
Chief Scientist at Thoughtworks.

generative AI


Unmesh

The primary challenge of software development is to build systems that survive change.

People new to programming, and people who don't code for a living but hire those who do, often
think of programming as a linear translation of requirements into programming language syntax.
This view misguides people into either spending a lot of time getting the requirements or
specifications right, or gaining expertise in programming language syntax.

In the context of LLM usage, this view manifests in phrases like 'Human in the loop'. This terminology implies that the
primary work of translating requirements into code is performed by the LLM,
using the human only for cleanup when the machine fails.

But as any experienced programmer knows, the real challenge is not converting requirements to
code, but building systems that survive change.

What makes systems easier to manage as change happens?

Martin

To make things easier to change, we need to manage cognitive load.

One key to making things easier to change is managing cognitive load
for those who need to make the change. I might not be able to fit a
million lines of code into my head, but if the system is well structured
into modules, I might only need to understand a few hundred of those lines

  • then I can make progress.

Another key is when the code mirrors something that's already familiar
to me. If I'm working on a shipping system, and the code has elements like
ships, ports, and containers - and those elements behave in ways I expect
them to from my knowledge of the domain - then it helps me reason about
how the code works.

Rebecca

Managing cognitive load also requires understanding the domain at various levels of granularity.
This decomposition allows us to reason about properties through our abstractions without always
getting lost in the weeds. Like other aspects of the design process, getting the right abstraction levels is iterative.

Unmesh

At its core, the act of programming is mapping the “real”
domain (the What) onto a computational model (the How)

Cognitive load does not necessarily reduce if you need to deal with English-language prompts, or diagrams.
At its core, the act of programming is mapping the “real” domain (the What) onto a
computational model (the How). We must preserve the essence of the domain while translating it
into a form the machine can execute. Crucially, this is not a one-way street; it is a
continuous feedback loop where the “what” and “how” provide deep insights into each other.

Together, they uncover the stable parts of the system and the axes along which the system
might change in the future, allowing us to use programming paradigms to provide hooks for
these changes.

Martin

I've often heard folks use “what” and “how” to describe the difference
between requirements analysis and programming. Requirements are about
“what” and programming about “how”. But I've never liked that framing, it
tries to separate “what” and “how” into separate universes and I don't
think that's an effective way to think about the world.

Unmesh

The 'What' and 'How' are not separate universes but are intertwined.

I agree. On the surface it seems like that makes a good distinction.

We start with whiteboarding and high-level user journeys to discuss the system goals. We map
these to the implementation landscape—databases, services, and UI. But the “what” question
persists at every level:

  • System level: What is the user trying to achieve?
  • Class level: What is this component supposed to do?
  • Function level: What is this specific block for?

The impact: the answer to “what” determines the logical grouping and, most importantly, the
naming. Once the intent is named (and refined by our implementation insights), we face the mechanics
of execution. The decisions we make here shape the structure of the solution.

Rebecca

A crucial part of the “how” is choosing how we represent the
real domain in something a computer can execute

A crucial part of the “how” is choosing how we represent the real domain in something a
computer can execute. We often do this by mapping the domain onto a familiar computational
model—like a state machine, a table, a stream, or a log. This mapping is not neutral: using the
state machine as an example, if we
map something to a state we start reasoning about it differently than if we map it to a
transition.

The shape of this mapping is often where the structure of the solution starts to
emerge.
If we don't use a model that comes with built-in semantics
then we have to develop a mental model
(abstraction) that we can then represent in code.
At this point, our choice of language paradigm will matter a great deal, as there are
abstractions that are readily represented in a particular paradigm and others that are more
difficult. For example, an unbounded yet finite list is much easier to represent in a
functional style language.

Martin

This is why when we think about domain modeling, it's not just about
modeling the data structures, it's also about modeling how computation
works with those data structures. Object-oriented modeling took a step in
that direction by binding behavior to the data structures, but it's only an
initial step. When working with more complex domains you have to
design computation into the fabric of the model.

Unmesh

These decisions are not implementing a requirement to make it run;
they are about choosing the
right structure.

As we oscillate between these two modes, something important happens:

  • What → How: While refining the intent, the mechanism reveals itself. “Ah, these requests

are strictly prioritized based on delivery time. I can use a priority queue here.”

  • How → What: While implementing the mechanics, the true nature of the system reveals

itself. “Oh, looking at how we persist these events, we aren’t just saving data; we are
actually implementing a write-ahead log mechanism.”

Martin

Start with scenarios and use them to drive the abstractions
that link “how” and “what”

This raises the question of how we should best understand
how we understand and think about the higher-level “what”. We can't come
up with a broad, abstract, statement of requirements because we cannot
figure out how to talk about that abstract statement
without understanding the mechanism to implement it. The intertwining of
“what” and “how” traps us in circular dependencies.

The way forward that's always appealed to me is to start with concrete
examples of how people use a system. Take these scenarios/use-cases and
use them to drive the abstractions that support them.

Unmesh

And these scenarios operate at two levels:

[...]


Original source

Reply