When an AI builds software for us, the quality of the result depends almost entirely on the quality of the requirements we give it. Before an AI proposes a design or writes any code, the requirements have to be organized and checked for gaps and contradictions. Few people argue with that. The harder question comes next: what shape should those requirements take?
Software engineering has produced dozens of ways to represent requirements over the past fifty years. Almost all of them are caught in a tug-of-war between two readers with very different needs.
The first reader is the business: product owners, stakeholders and domain experts. Requirements start with them, and they rarely think in tables or pseudo-code. They think in stories about who is using the system and what they’re trying to get done. Hand them a dense wall of formal statements and, as Wiegers and Beatty note with some sympathy, their eyes glaze over [1].
The second reader is the engineer, human or AI, who has to check the requirements and turn them into code. For that job, everyday language is a weak tool. It relies on context and implication, so it’s naturally fuzzy, and it hides contradictions well. Leffingwell and Widrig point out that in some situations the ambiguity of natural language simply can’t be tolerated [2]. Try auditing a flowing narrative for missing database constraints, dead-end states or race conditions, and you’ll see why.
I know both readers well, because I am both of them. When the business brings me user stories, I read them in a minute and understand exactly what they want. Then I sit down to write precise instructions for the engineers and discover that I have no idea what happens when the discount is bigger than the cart. So I go back to the business for clarification. Then again. On a good day it’s twenty times, and by the afternoon my knock on the door is greeted with “What now?” rather than “Come in.” And when a development lead hands me a beautifully structured SRS, I’m asleep by the third paragraph. That isn’t because the document is bad. It’s because it’s good: precise, complete, and about as gripping as a home insurance policy.
That is the Requirements Paradox: the easier a specification is for the business to read, the harder it is to validate and implement, and the more rigorous it becomes, the harder it is for the business to read and approve.
Let’s look at the classic structures one at a time, see why even a well-written user story leaves a design wide open, and then look at a combination that gets the best of both worlds.
1. The Narrative Approach: Use Cases and User Stories
Use cases, introduced by Ivar Jacobson, and user stories, which came from Extreme Programming and were popularized by Mike Cohn, have dominated requirements practice for the last two decades [3]. The reason is simple: people are wired for stories. Nobody ever gathered around a campfire to hear “The system shall …”.
Both techniques describe a person trying to reach a goal. Use cases are relatively easy to write and read. They pull users into the requirements process, and they give requirements a natural order: what happens first, what happens next [4]. User stories compress the narrative into a single sentence. The best-known template, which came from a team at Connextra around 2001 and was spread by Cohn, goes:
As a
<type of user>, I want<some goal>so that<some reason>.
For a product owner this is effortless to read, prioritize and debate. It says who wants the feature, what they want and why.
The Trap: A Perfect Story Is Still Not a Specification
Stories were never meant to be enough to build from. Ron Jeffries described a story as three things: a card with a short description, a conversation where the details are worked out, and a confirmation in the form of acceptance tests[5]. The card is a reminder that the conversation has to happen, not a replacement for it. Wiegers and Beatty likewise warn that developers shouldn’t expect to learn everything they need from stories alone[6].
Humans hold that conversation naturally; in my case, about twenty times a day. An AI given only the card skips the conversation and fills the gaps with guesses. Two perfectly respectable stories show how much a card can leave out:
As a customer, I want to receive an email each time my order status changes, so that I always know where my order is.
Which status changes count? Does the customer really want separate emails when the warehouse moves the order from Picking to Packing thirty seconds apart? They wanted news about their parcel, not a running commentary from the warehouse. If the mail service is down, does the status change roll back, or does the email retry later? And what stops “Shipped” from landing in the inbox before “Confirmed”?
As a shopper, I want to enter a discount code in my cart so that I can reduce the price of my purchase.
Is the discount a percentage or a fixed amount? Apply a $25 code to a $15 cart and the total becomes $10. A coupon that pays customers to shop is certainly a marketing strategy, though rarely an intended one. Is tax calculated before or after the discount? And if a $10 code takes a $55 cart down to $45, does the customer lose “free shipping on orders over $50”?
Each story takes ten seconds to read and leaves a dozen decisions open. An AI will happily make every one of them for you, without mentioning it.
2. The Escalation of Formality: Hierarchies, Tables and EARS
Requirements methods responded to the fuzziness of stories with stricter structures. Each step toward formality moves the document closer to code. It gets easier to validate and harder for the business to read.
Functional Hierarchies (the Classic SRS)
A traditional Software Requirements Specification, based on IEEE 830 and its successor ISO/IEC/IEEE 29148, organizes requirements into numbered hierarchies with unique tags [7]:
Cart.01The website shall provide a shopping cart for selected products.Cart.Discount.01The shopping cart shall provide one field for a discount code.Cart.Discount.Error.01If the customer enters an invalid discount code, the website shall display an error message.
Unique IDs make traceability and testing straightforward. Across a whole application, though, this grows into hundreds of pages of “The system shall&”. Human short-term memory gives up long before the end, and the interactions between features become invisible [8].
Event-Response and Decision Tables
Tables remove much of the ambiguity of prose [8]:
| Event | Condition | System response |
|---|---|---|
| Customer clicks “Apply code” | Cart active; code valid and unexpired | Apply discount; recalculate subtotal |
| Customer clicks “Apply code” | Cart active; code expired | Reject code; show “Code expired” |
Tables are excellent for checking combinations, because a missing row is easy to spot. But they break the domain into fragments. A stakeholder facing eighty of them, each about as gripping as a phone book, struggles to see the product as a whole.
Constrained Grammars (EARS) and Pseudocode
At the far end of formal text sits EARS, the Easy Approach to Requirements Syntax. Alistair Mavin and colleagues developed it at Rolls-Royce to remove ambiguity from requirements for aero-engine control systems [9]. Every requirement follows one of a few fixed patterns:
- Event-driven:
WHEN the customer submits a payment, the system shall& - State-driven:
WHILE the account is frozen, the system shall& - Unwanted behavior:
IF the payment gateway times out, THEN the system shall&
For complex algorithmic or financial logic, teams sometimes go one step further, to pseudo code: natural language dressed up in the control structures of a programming language [2].
EARS and pseudo code are wonderful for automated checking and test generation. But to a product owner, five hundred EARS statements read like a legal contract written by a compiler. The validation problem is solved by losing the business reader.
3. Why Domain-Driven Design Hits the Sweet Spot
Now consider a fifth option: organizing the requirements with Domain-Driven Design (DDD), introduced by Eric Evans [10]. The specification is divided into domains and bounded contexts, and inside each context into aggregates, such as an Order, an Account or an Invoice. Each aggregate has explicit properties, lifecycle states, actions, calculated values and relationships.
DDD tackles what Leffingwell and Widrig call the problem of orthogonality. Requirements talk about real-world things, like engines and paychecks, while code talks about stacks, queues and algorithms, so there is no simple mapping between the two [11]. DDD narrows that gap on purpose. Evans’s central idea is that the code should mirror the domain model, so the model becomes the bridge [10].
Structuring a specification around aggregates has three benefits:
- A short path to design. An aggregate’s properties become columns, schema fields and object attributes. Its lifecycle states become state machines and transition rules. Its actions become API endpoints and service methods. Its bounded contexts suggest module or service boundaries [12]. The mapping isn’t always one-to-one, but it is close enough that the “translation” step stops being a leap of faith.
- Completeness by construction. Every aggregate has the same slots to fill: properties, states, actions, effects on other aggregates, and calculated values. A validator, human or AI, doesn’t have to guess what’s missing from a story. A property with no validation rule or a state with no way out stands out immediately as an empty slot.
- The business’s own vocabulary. DDD is built on a ubiquitous language: the same terms are used by the business, in the specification and in the code[13]. An Order or a Subscription is something stakeholders talk about every day. Reading the rules of the
Orderaggregate is far more natural for them than reading three hundred disconnected WHEN/WHILE/IF clauses.
A Fair Concern: Where DDD Strains Business Readers
DDD is not a perfect answer to readability, and two concerns deserve honesty:
- Nouns versus journeys. Business people think across time, following a customer from landing page to cart to payment to delivery. DDD slices the world by noun: the
Cartaggregate, thePaymentaggregate, theShipmentaggregate. With only a DDD specification, a stakeholder has to jump between three sections to follow one checkout. - Intimidating vocabulary. Even DDD’s advocates admit that “aggregate” is a slippery concept with many competing definitions[13]. Ask business owners to express their ideas in bounded contexts and aggregate roots, and they will, understandably, run for the door.
4. The Five Structures Side by Side
Here is how the five structures compare on the three things that matter most. Five stars is best.
| Structure | Business readability | Ease of validation | Mapping to code |
|---|---|---|---|
| User stories and use cases | ★★★★★ | ★★☆☆☆ | ★★☆☆☆ |
| Functional hierarchy (SRS) | ★★★☆☆ | ★★★☆☆ | ★★★☆☆ |
| Event-response and decision tables | ★★☆☆☆ | ★★★★☆ | ★★★★☆ |
| EARS / constrained syntax | ★★☆☆☆ | ★★★★☆ | ★★★☆☆ |
| Domain-Driven Design | ★★★★☆ | ★★★★★ | ★★★★☆ |
Each structure also has its own blind spot:
- User stories and use cases: large assumptions hide behind readable prose.
- Functional hierarchy: readers tire, and the interactions between features get lost.
- Event-response and decision tables: the overall model and the narrative disappear.
- EARS: stakeholders disengage, and there is no view of an entity’s lifecycle.
- Domain-Driven Design: end-to-end journeys are split across entities.
5. The Synthesis: Stories for People, DDD for Rigor
Look at the first and last rows of the table. Their strengths and blind spots are almost exact mirror images:
- User stories excel at narrative and business intent but fail at validation and technical mapping.
- DDD excels at validation and technical mapping but needs a narrative to keep end-to-end journeys visible.
The requirements literature has long recommended keeping these layers apart. User requirements describe what users need to accomplish, and a separate, detailed specification describes what the software must do, because different readers need different levels of detail [7]. Applied to AI-assisted development, that becomes a two-layer specification:
- Layer 1: raw requirements as stories and journeys. Stakeholders write what they want in the form most natural to them: user stories, short narratives and user journeys. No data types, state tables or rounding rules required.
- Layer 2: a formal specification in DDD form. An AI requirements agent translates the stories into a specification organized by domains, bounded contexts and aggregates. Along the way it surfaces everything the stories left out: missing properties, lifecycle states, cascades between aggregates and edge cases in formulas. That is exactly the kind of gap we found in the two stories above.
The Non-Negotiable Part: Traceability and a Decision Log
This only works if the formal specification never becomes disconnected from the stories it came from. Without traceability links, you can’t show that every customer need was met, or explain why a detailed rule exists at all [14]. So every item in the DDD specification carries two kinds of link:
- A reference to the raw requirement it implements. Every aggregate, action, property and acceptance criterion cites the ID of its source story (say,
RAW-014). When a stakeholder reads a surprising rule in theOrderaggregate and asks, “Where did this come from?”, the answer is one click away. - A reference to the decision that filled each gap. Stories always leave gaps, so the formal specification will contain dozens of rules nobody originally mentioned: negative cart totals, email retries, time-zone boundaries. Each of these cites an entry in a decision log (say,
DEC-042). The entry records the question that was asked, the option the product owner chose, and why.
Stories keep the business in the conversation. DDD gives validators and the AI the structure they need. Traceability and the decision log tie the two together. The paradox doesn’t disappear, but it stops being a trade-off: the business gets a specification it can read, and the engineering side, human or AI, gets one precise enough to build from with far fewer surprises.
Notes
- Wiegers and Beatty (2013), ch. 11, “Writing excellent requirements.” ↩
- Leffingwell and Widrig (2003), ch. 23, “On ambiguity and specificity,” and ch. 24, “Technical methods for specifying requirements.” ↩
- Jacobson et al. (1992); Beck (1999); Cohn (2004). On user stories in requirements practice, see Wiegers and Beatty (2013), chs. 8 and 20. ↩
- Leffingwell and Widrig (2003), ch. 14, “A use case primer.” ↩
- Jeffries (2001). ↩
- Wiegers and Beatty (2013), ch. 8, “Understanding user requirements.” ↩
- Wiegers and Beatty (2013), ch. 10, “Documenting the requirements”; IEEE (1998); ISO/IEC/IEEE (2018). ↩
- Wiegers and Beatty (2013), ch. 12, “A picture is worth 1024 words.” ↩
- Mavin et al. (2009). ↩
- Evans (2003); see also Vernon (2013). ↩
- Leffingwell and Widrig (2003), ch. 25, “From use cases to implementation.” ↩
- Richards and Ford (2025), on bounded contexts and architecture quanta; Ford et al. (2021), ch. 6, “Pulling apart operational data,” and ch. 13, “Contracts”; Wiegers and Beatty (2013), ch. 13, “Specifying data requirements.” ↩
- Newman (2021), ch. 2, “How to model microservices.” ↩
- Wiegers and Beatty (2013), ch. 29, “Links in the requirements chain.” ↩
Bibliography
- Beck, Kent. 1999. Extreme Programming Explained: Embrace Change. Reading, MA: Addison-Wesley.
- Cohn, Mike. 2004. User Stories Applied: For Agile Software Development. Boston: Addison-Wesley.
- Evans, Eric. 2003. Domain-Driven Design: Tackling Complexity in the Heart of Software. Boston: Addison-Wesley.
- Ford, Neal, Mark Richards, Pramod Sadalage, and Zhamak Dehghani. 2021. Software Architecture: The Hard Parts. Sebastopol, CA: O’Reilly Media.
- IEEE. 1998. IEEE Recommended Practice for Software Requirements Specifications (IEEE Std 830-1998).
- ISO/IEC/IEEE. 2018. Systems and Software Engineering: Life Cycle Processes, Requirements Engineering (ISO/IEC/IEEE 29148:2018).
- Jacobson, Ivar, Magnus Christerson, Patrik Jonsson, and Gunnar �vergaard. 1992. Object-Oriented Software Engineering: A Use Case Driven Approach. Reading, MA: Addison-Wesley.
- Jeffries, Ron. 2001. “Essential XP: Card, Conversation, Confirmation.” https://ronjeffries.com/xprog/articles/expcardconversationconfirmation/
- Leffingwell, Dean, and Don Widrig. 2003. Managing Software Requirements: A Use Case Approach, 2nd ed. Boston: Addison-Wesley.
- Mavin, Alistair, Philip Wilkinson, Adrian Harwood, and Mark Novak. 2009. “Easy Approach to Requirements Syntax (EARS).” 17th IEEE International Requirements Engineering Conference (RE ’09), 317322. https://doi.org/10.1109/RE.2009.9
- Newman, Sam. 2021. Building Microservices: Designing Fine-Grained Systems, 2nd ed. Sebastopol, CA: O’Reilly Media.
- Richards, Mark, and Neal Ford. 2025. Fundamentals of Software Architecture: An Engineering Approach, 2nd ed. Sebastopol, CA: O’Reilly Media.
- Vernon, Vaughn. 2013. Implementing Domain-Driven Design. Upper Saddle River, NJ: Addison-Wesley.
- Wiegers, Karl E., and Joy Beatty. 2013. Software Requirements, 3rd ed. Redmond, WA: Microsoft Press.