What the Software Ought to Do. What It Ought to Be. · Kevin Brown
I replaced my personal finance spreadsheet with a terminal app, wrote<br>none of the code, and used a stack I’d never touched. How well can an<br>engineer supervise an LLM exclusively authoring code in a language and<br>framework they don’t know?
I have a strong preference for upfront thinking. Not in the bureaucratic<br>sense – please, no, I’m deeply allergic – but my curiosity needs to know<br>my domain before I build. That means drawing a domain model, writing out<br>a site map, or just staring out the window contemplating how the average<br>user will interact with the system. Those of you reading who share a<br>similar disposition will recognize the satisfaction of finally moving<br>from “thought product” to “work product” and development unfolds<br>with minimal friction – the pieces snap together like building blocks.
Brooks famously made the distinction between essential and accidental<br>complexity [1]. Essential complexity lives in the software’s purpose,<br>its problem domain and its surrounding environment: the rules,<br>relationships and interfaces of the domain’s systems, social and<br>technical, that exist independently of whatever solution you implement.<br>Accidental complexity arises from the tooling and the intricacies of the<br>implementation itself. Discovering the essential complexity is a human<br>exploration and thought exercise. Expressing those thoughts in<br>documentation, diagrams, or working software, creates tangible<br>representations of that understanding. Inevitably, this work product is<br>an imperfect representation of the thought product, with each medium<br>introducing and shaping its own constraints and distortions – a key part<br>of the system’s accidental complexity.
This is why no single diagram, document, or code snippet fully captures<br>the essential complexity. As Brooks wrote about the invisibility of<br>software, “As soon as we attempt to diagram software structure, we find<br>it to constitute not one, but several, general directed graphs,<br>superimposed one upon another.” [1] Switching between modeling<br>modalities – domain models, wireframes, and documentation – keeps me<br>clear-eyed about the unfolding work in the same way printing a document<br>helps you catch errors you’d otherwise miss.
In this essay I show how AI is a natural fit for this domain-driven<br>custom software workflow. AI does not eliminate the essential complexity<br>– if it did, it wouldn’t be essential anymore. But it supports<br>structured thinking by providing a responsive surface against which<br>ideas can be expressed, challenged, and validated. With AI supporting<br>the requirements and design, those artefacts simultaneously become the<br>engineer’s written understanding of the essential complexity and a<br>central part of the AI’s “harness” [2], [3] to guide its unfolding<br>development. As we’ll see in the case study, I did not author any code<br>directly. I was, however, constantly reviewing its output as if the LLM<br>was my junior and I was a disgruntled tech lead.
Capturing the essential complexity allows you to define what the<br>software ought to do – its purpose. AI is capable of generating<br>working code to fulfill a purpose, but it doesn’t know what’s “good”:<br>what’s understandable by a human, and what’s possible to evolve and be<br>extended. The agent must also be directed toward what the software ought<br>to be – its constitution. This goes beyond a style guide: it’s the<br>architecture, structure, and the logic of the generated code. We<br>establish the purpose by understanding our domain so that the software<br>fulfills its intended function. We tend to the constitution with our<br>knowledge of the craft and engineering principles. Both require the<br>judgement to know what the system ought to do and ought to be.
About the Case Study
I’ve never encountered a personal finance application that fit just<br>right. I’m not disciplined enough to regularly enter my transactions,<br>and there are only a few metrics I’m interested in tracking. I created a<br>spreadsheet, refined over the years, that works for me: the least amount<br>of data entry to get to those metrics. I won’t get into the details of<br>my methodology – I’m not here to sell you on my own idiosyncratic<br>approach to personal finance. I will, however, use it as a case study<br>for spec-driven development with AI.
Converting an artefact like a spreadsheet to an application is an<br>exercise in separating the essence from the accident. The resulting<br>application will naturally differ from the source spreadsheet; but the<br>spreadsheet already captures the system’s purpose as a low-fidelity<br>specification.
The first step is to understand what the spreadsheet is doing. I began<br>by classifying the tabs into distinct modules and diagramming how they<br>interact as depicted in<br>Figure 1. The<br>remainder of the development divides the application into those modules.<br>At this point we haven’t used AI other than to assess clarity – we’re<br>still putting in the effort to discover our domain.
Figure 1: The coloured boxes are...