This article explores the fundamental distinction between specifications and code, arguing that a comprehensive specification represents a set of possible implementations while code is a single concrete implementation. The author examines how this distinction remains relevant even with the rise of LLMs and program synthesis technologies, and why keeping these concepts separate is crucial for effective software development.
In the evolving landscape of software development, a persistent philosophical question emerges: where does specification end and code begin? The recent article from Buttondown tackles this question head-on, challenging the notion that a 'comprehensive and precise spec' is equivalent to code. This distinction, while seemingly semantic, carries profound implications for how we approach software design, development, and the future of programming itself.
At its core, the argument rests on a simple yet powerful observation: a specification corresponds to a set of possible implementations, whereas code represents a single implementation within that set. As long as this set contains more than one element—a condition that holds true for virtually all non-trivial specifications—a fundamental separation exists between the abstract specification and its concrete realization.
Consider the example of a miles-to-kilometers conversion tool. At its most basic level, this requirement seems comprehensive enough to hand to an AI system like Claude Code and expect a functional program. Yet, as the article rightly points out, this specification leaves numerous critical decisions unaddressed: programming language, user interface, deployment model, conversion precision, and architectural approach. The resulting set of possible implementations includes solutions that would satisfy the business person's needs alongside many that would not.
This leads us to an important conceptual distinction: the difference between comprehensiveness and sufficiency. A specification need not be fully comprehensive to be sufficient. If the business person is satisfied with whatever implementation the AI generates, then their specification, despite its apparent lack of detail, was sufficiently precise for their purposes. This highlights a crucial insight about specifications—they exist in relation to the needs and expectations of their stakeholders.
The article correctly identifies that specifications are fundamentally abstractions. Every specification defines a set of programs that satisfy it, with more precise specifications corresponding to smaller sets. This relationship can be understood as a refinement process, where each successive specification narrows the space of possible implementations. A specification becomes 'sufficient' when it no longer requires refinement—when any implementation drawn from its remaining set would meet the stakeholder's requirements.

The persistence of this spec-code distinction holds important implications for the future of programming, particularly in an era increasingly dominated by AI-assisted development. The article references program synthesis, an active research field dedicated to automatically generating conformant programs from specifications. While LLMs have dramatically advanced our capabilities in this domain, they have not erased the fundamental difference between specifying what should be done and implementing how it should be done.
This distinction becomes particularly important when considering the role of formal specification languages. Technologies like TLA+, UML, and specialized domain-specific languages represent attempts to encode specifications in formal, machine-processable terms. Even test suites, which the article rightly identifies as specifications, serve to define acceptable behavior without prescribing implementation details.
The historical attempt to enable non-programmers to write specifications—epitomized by tools like Cucumber—highlights a crucial reality: encoding abstractions in formal languages requires a level of precision and systemic thinking that comes naturally to programmers but remains challenging for non-technical stakeholders. This suggests that while AI may lower the barrier to implementation, the craft of specification writing will likely remain a specialized skill.
The article includes a thoughtful comment that introduces an important counter-perspective regarding LLM non-determinism. When specifications are translated to code through generative AI, there's a critical distinction between 'every program generated so far' and 'every conceivable program' that meets the specification. A specification that happens to consistently produce satisfactory results through multiple generations may still contain implicit ambiguences that could lead to problematic implementations in future iterations.
This concern highlights a fundamental challenge in the AI-assisted development paradigm: the gap between specification intent and implementation reality. As the commenter notes, when people proclaim that 'we'll just write specifications and programs will write themselves,' they often overlook the potential variation in generated implementations. In domains where consistency and precision are paramount—such as safety-critical systems, financial applications, or infrastructure code—this non-determinism presents significant challenges.
The practical wisdom embedded in the original comic referenced in the article gains new relevance in this context. If you require consistent, predictable implementations rather than a range of functionally equivalent but potentially different solutions, then what you're really seeking is code, not just a specification. This distinction becomes particularly important when considering maintenance scenarios, where future developers must understand and modify existing implementations.
From a software engineering perspective, maintaining the spec-code distinction offers several practical benefits:
- Flexibility in Implementation: Specifications allow for technology evolution and optimization without changing the core requirements.
- Separation of Concerns: They enable clear separation between what a system should do and how it should do it.
- Multiple Implementation Strategies: The same specification can support different implementation approaches tailored to specific constraints.
- Better Communication: Specifications provide a common understanding between stakeholders with different levels of technical expertise.
- Quality Assurance: They enable systematic testing and verification against intended behavior rather than specific implementation details.
As we advance into an era where AI plays an increasingly prominent role in software development, this distinction becomes more important rather than less. While AI may handle implementation details with growing sophistication, the art and science of crafting precise, unambiguous specifications will remain a uniquely human endeavor. The most effective software development processes will likely involve humans focusing on the 'what' and 'why' while leveraging AI for the 'how'.
The article's conclusion resonates with this perspective: keeping 'code' and 'spec' as distinct concepts remains useful, perhaps even essential, for maintaining clarity in our thinking about software development. As program synthesis technologies continue to evolve, this conceptual framework will help us navigate the changing landscape while preserving the core principles of software engineering.
For those interested in exploring these ideas further, the field of formal methods offers rigorous approaches to specification, while program synthesis research continues to push the boundaries of automated code generation. The ongoing dialogue between human specification and machine implementation represents one of the most exciting frontiers in software development today.

Comments
Please log in or register to join the discussion