Stage 2 of 6 · Theory, pen ready · about 25 minutes
Requirements
Before a system can be built, someone has to say what it must do, precisely enough that two people reading the sentence build the same thing, and a third can test whether they succeeded. That sentence discipline is requirements writing, and it is a skill, learnable like soldering.
What a requirement is
A requirement is a statement about the what, not the how: an observable behaviour or measurable quality the finished system must have. It deliberately does not choose the implementation.
What · requirement territory
- "When the button is pressed while the LED is lit, the system shall report the reaction time."
- "The system shall restart the round after a false start."
- "Reported times shall be in milliseconds."
How · design territory
- "Use
when_pressedrather than polling." - "Store the start time in a variable named
t0." - "Keep the wait loop's sleep at 10 ms."
Keeping the two apart is not pedantry; it is what makes teamwork and testing possible. The what can be agreed with a client (or a teacher) who never reads Python; it stays stable while the how is redesigned; and every test is written against the what. When Assignment 2 arrives in Week 8, its brief is a what-list, and your grade is largely "how many of these are demonstrably true of your system". In industry the same idea scales up into formal documents; the standard that defines the practice is ISO/IEC/IEEE 29148, and the classic document it describes is the software requirements specification (SRS). This course uses a one-page version of the same discipline.
Two kinds: functional and non-functional
| Kind | Answers | Shape | Reaction-timer examples |
|---|---|---|---|
| Functional | What behaviours? | Given a situation, the system does a thing | Lights the LED after the delay; reports a time on a valid press; restarts on a false start |
| Non-functional | How well? Under what limits? | A measurable quality or constraint | Times accurate within 100 ms; runs over SSH on the Pi; stops cleanly with Ctrl+C |
Beginners write plenty of functional requirements and forget the non-functional ones, yet the non-functional ones decide whether the system is any good: a reaction timer that mismeasures by half a second meets every functional requirement and is still junk. Timing, accuracy, and platform constraints are where your instrumentation background gives you an advantage: you already think in tolerances. Non-functional requirements are tolerances for software.
What makes a requirement good
Five qualities, each checkable by asking a question of the sentence:
- Testable (verifiable). Could you write a concrete pass/fail check? "Shall be user-friendly" fails this instantly; "shall report the time within 1 s of the press" passes.
- Unambiguous. Would two readers picture the same behaviour? "Handle bad input" is a Rorschach test; "on a press before the LED lights, report FALSE START and restart the round" is a photograph.
- Atomic. One requirement, one obligation. "Shall light the LED and report the time and restart" is three requirements wearing one number; split them so each can pass or fail alone.
- Necessary. If it were deleted, would anything be lost? Requirements that snuck in as decoration ("shall use colourful output") dilute the spec.
- Feasible. Buildable with the kit, the time and the physics available. "Shall measure to the microsecond" is not, on a debounced mechanical button, and writing it would just guarantee a failed test.
Background: why "testable" is the load-bearing one
Every quality above serves the same end: a requirement exists so that, later, someone can check it. That is why professionals write the acceptance criterion, the concrete check, at the same time as the requirement. If the check is unwritable, the requirement is not vague, it is unfinished. In agile teams the pairing is explicit (a story is not "ready" without its acceptance tests); in this course, the design lab's verification table is where each of your requirements meets its check.
Anatomy of a written requirement
The course convention, a compact version of industry practice:
ID condition (when it applies) obligation ("shall") measurable part
R3. When the button is pressed while the LED is lit, the system shall report the elapsed time in ms.
Each requirement carries its acceptance criterion:
A3. Press ~1 s after the light: a time near 1000 ms is printed and the round ends.
- ID (R1, R2, ...). Numbers make requirements referable: in commits ("implement R4"), in tests, in the pair's division of labour, in the verification table.
- Condition first. "When X, the system shall Y" scopes the behaviour. Unconditional requirements ("the system shall never crash") are usually non-functional or need rewording.
- "Shall" for obligations. One modal verb, used consistently, so obligation is never confused with suggestion. (Industry reserves "should" for preferences and "may" for options; you can too.)
- A measurable tail. Units, thresholds, exact outputs. This is what the acceptance criterion grabs onto.
Repair shop: bad to good
| As first written | What is wrong | Repaired |
|---|---|---|
| "The game should be fast." | Untestable, ambiguous, wrong verb | R5. The system shall report the reaction time within 1 s of the button press. (Non-functional) |
| "Handle wrong presses properly." | "Wrong" and "properly" undefined | R4. When the button is pressed before the LED lights, the system shall print FALSE START and restart the round without reporting a time. |
| "The LED turns on after a delay and the time is measured and shown and the game restarts." | Not atomic: four obligations | Split into R2 (light after delay), R3 (report time on valid press), R6 (start a new round after each report). |
"Use time.monotonic() for timing." | A how, not a what | Move to the design notes. The requirement it serves is R5's accuracy; the design chooses the tool. |
| "Measure reaction time to the microsecond." | Infeasible on a debounced mechanical button | R5 as above, with a tolerance the hardware can honour (the lab discusses what is honest here). |
| "The code shall be clean." | Untestable as written | C1. The program, its requirements file and its pseudocode shall be committed to the team repository. (A constraint with a binary check) |
The reaction timer, specified
The worked example for the day. Read it as a whole: notice the IDs, the conditions, the split between functional (R1 to R4, R6), non-functional (R5), and constraints (C1, C2), and that every line could be checked by a stranger with a stopwatch and your repository.
| ID | Requirement | Acceptance criterion |
|---|---|---|
| R1 | At the start of each round, the system shall turn the LED off and print Get ready... | Observe both at every round start. |
| R2 | The system shall light the LED after a random delay of between 2.0 and 5.0 seconds from the round start. | Time 5 rounds by stopwatch: all delays within [2, 5] s, and not identical. |
| R3 | When the button is pressed while the LED is lit, the system shall turn the LED off and print the elapsed time since the LED lit, in milliseconds. | Deliberate ~1 s wait before pressing prints a value near 1000 ms. |
| R4 | When the button is pressed before the LED lights, the system shall print FALSE START and restart the round without reporting a time. | Press early: message appears, no time printed, a new round begins. |
| R5 | Reported times shall be accurate to within 100 ms of the true light-to-press interval. | Discussed in the lab: verification needs a plan, not just a claim. |
| R6 | After reporting a time or a false start, the system shall begin a new round automatically until stopped with Ctrl+C. | Play 3 rounds in a row without restarting the program; Ctrl+C exits. |
| C1 | The program shall run on the Raspberry Pi, over SSH, inside the Week 4 environment. | Demonstrated at the bench. |
| C2 | The requirements, pseudocode and code shall be committed to the repository (docs/ and the script). | git log shows them. |
This table is the day's contract. The next page designs against it, and the lab verifies against it, row by row.
Aside: user stories, the agile cousin
Modern agile teams often capture the same intent as user stories: "As a player, I want to see my reaction time after each press, so that I can try to beat it." The card-sized sentence is deliberately informal; the rigour returns as attached acceptance criteria ("conditions of satisfaction"), which are exactly our A-lines. Stories shine when needs are still being discovered; shall-requirements shine when behaviour must be nailed down, as in a control system or an assignment brief. Knowing both lets you read any team's documents. Mike Cohn's overview at mountaingoatsoftware.com/agile/user-stories is the standard short introduction, and the Wikipedia article covers the INVEST checklist, agile's version of the qualities above.