Skip to main content
InfromatinTechnologies
Engineering8 min read

Writing a specification that survives contact with the build

Specs fail because they describe screens rather than behaviours. A practical structure for acceptance criteria that outlive the first release.

Infromatin Technologies

Writing a specification that survives contact with the build

Specifications fail in a predictable way: they describe screens and fields rather than behaviours, so they read as complete and turn out to be untestable.

The test is simple. Pick any statement in the spec and ask how would we know this is done? If the answer requires a conversation, the spec has a gap in exactly the place that will be expensive.

Describe behaviour, not screens

Compare two statements:

The application displays the customer's loan applications in a table with a status column.

The user can list the loan applications they have permission to view, sorted by most recently updated, filtered by status, and open any one to see its decision history.

The first is a picture. The second states capability, and it can be tested.

Screens are an output of design, not the specification of behaviour. Pinning a spec to a layout means every design change requires a spec change, and the spec becomes a barrier rather than a shared reference.

Every requirement needs an observable outcome

The structure that works, repeated for each requirement:

  • Given a system in a known state
  • When a specific thing happens
  • Then a specific, observable result

The value is in the third clause. "The system processes the payment" is untestable. "The payment is recorded with a transaction identifier, the customer's balance is updated, and an entry appears in the day's reconciliation report" is testable, and it happens to surface three things nobody had considered — including the reconciliation requirement.

Requirements without an observable outcome are wishes. They cannot be signed off, which means acceptance happens on opinion, which means it happens late and expensively.

Specify the unhappy paths first

Happy paths are obvious. The specification is worth reading if it handles the cases nobody wants to talk about.

For anything moving money or deciding on a customer:

  • what happens when the downstream system is unavailable
  • what happens when the same request arrives twice
  • what happens when it succeeds and the confirmation is lost
  • what is recorded when a step fails halfway
  • who is told, and how quickly
  • what the user sees, and what they can retry

Each of these has a design answer, and none of them are answered by accident.

Separate the contract from the interface

The interface between systems should be specified as a contract — inputs, outputs, error modes, guarantees — and the design that implements it specified separately.

This matters most when integrating with something you do not control. A core banking platform's behaviour should be described in terms of what you are entitled to rely on, not what the vendor's documentation currently says.

Write down the guarantees you depend on explicitly. When they change, you find out from your own document rather than from an incident.

Put the data model in the specification

Most missed requirements are data requirements.

What is stored, what is the authoritative source for each field, what happens on conflict, who may correct it, and what happens to it at the end. Review, consent and retention all land here.

Teams routinely specify a user interface carefully and discover during build that there is no agreed answer on whether the customer address lives in the CRM or the account system. That is a specification failure with a three-week cost.

Let it be wrong early

The purpose of a specification is to be tested against reality as fast as possible, not to be right.

Review it with the people who will operate it — support, operations, compliance — not only with the delivery team. They find the requirements nobody considered, and they find them in an hour rather than during acceptance.

Then write the first release against it, and treat every difference as information about the specification rather than as a defect in the build.

The practical structure

One page per requirement. Behaviour, observable outcome, unhappy path, data implications, and an owner who confirms the outcome is what they expected.

That is more writing than most teams do, and considerably less than the cost of discovering a gap in month five with no agreed answer about what the system was supposed to do.

In this article

  • delivery
  • requirements
  • process

Working on something similar?

These articles come from real engagements. If the problem here sounds familiar, a 30-minute call is usually enough to tell you whether we can help.

Start a conversation

Related reading

Continue from here

Articles connected to the same delivery problems.

Have a related problem in front of you?

Send us the problem in whatever detail you have. A senior engineer replies within one business day, and you will get an honest read on whether we are the right partner for it.

We would like to use Google Analytics to understand how this website is used. No analytics are loaded unless you accept. Your choice is stored for six months.

See our Privacy Policy for details.