Requirements are pretty ubiquitous in the embedded world. They are used to define tasks, help coordinate large development efforts, and to communicate the behavior of the desired end product between the developers and the customer. When done right, requirements can be very useful. Unfortunately, if you spend much time working in the embedded world you quickly discover that there are a lot of bad requirements. And then when you try to go fix them, you quickly discover that writing good requirements is hard. Here are some tips that will hopefully make the process more clear:
At a high level, the purpose of requirements is to provide a useful description of the desired behavior of a blackbox system that is detailed enough that:
- An engineer can make an implementation of said system.
- A tester could verify that a given device satisfies the requirements (without talking to the engineer)
- The resulting system satisfies the desires of the end user.
Writing good requirements:
The basic rule of thumb is this: Requirements should be the simplest, most understandable description of a system that constrains the system to the intended behavior. If you aim for this, the rest of the important stuff (testability, avoiding internal detail, etc…) tends to fall into place by itself.
Often it’s helpful to have some more granular guidelines to go by. Here are a few steps to writing good requirements:
- Define the boundaries of the system. Where are you going to draw the blackbox
- Define the inputs and outputs. These should be your only view into the internals of the system.
- Write down an easy to understand description of the desired behavior of the system.
- Does your requirement reference a part of the system besides the input and output? If so, your requirement has unnecessarily detail. Refactor and simplify.
- Is your requirement too ambiguous? Add more specifics. Note: Some ambiguity is a good thing, as long as all the potential interpretations are still within the set of acceptable behaviors and you don’t need any additional information to test the requirement, then you’re good. You don’t need to (and you shouldn’t try to) fully constrain the behavior of the system.
- Is your requirement testable? (blackbox testable) If not, you most likely messed up step 4. If this is happening a lot you might have defined the box around your system poorly or you might need better tools for testing. In either case an untestable requirement is nearly worthless.
- Is your requirement easy to understand? If your requirements are hard to understand then you are doing it wrong and you’ll just cause pain to everyone who uses the requirement down the road. Go back to step 3
- Are you sure you didn’t violate rule 4? Are you SURE? Go make sure.
As an example, lets write requirements for a contrived embedded device that blinks an LED at different rates depending on a reading from a flex sensor.
Hey look! We’ve already done step 2 and 3!
- Input: Reading from flex sensor
- Output: LED
But we’ve skipped step 1:
- For our example we are going to draw our blackbox around the microprocessor on the device.
Lets move on,
Step 4: Do we reference a part of the system besides the input and output?
- The microprocessor doesn’t really care that we’re reading from a flex sensor, from it’s perspective we will be measuring the voltage on an ADC pin.
- And the LED will just be controlled by digital output pin.
So lets fix that:
Requirement Version 0:
- The device shall toggle a digital output pin at different rates depending on the voltage at an ADC pin.
Step 5: Is the requirement too ambiguous?
Hmmm, our description is quite ambiguous. How fast should the output be toggle? How does it relate to the voltage? What are the expected ranges of input voltage? Lets add some detail:
- The digital output pin shall be controlled by a free running timer
- The free running timer shall tigger at a maximum rate of 10 times a second and a minimum rate of once per second.
- The trigger rate of the free running timer shall vary linearly between the minimum and maximum rate, directly proportional to the input voltage on the ADC pin
- The input voltage on the ADC pin shall be read once every 100 milliseconds.
- When the input voltage on the ADC pin is read the register value controlling the free running timer cycle time will be updated.
- The valid range of input voltage on the ADC pin shall be between 0 an 1 volts
Step 6: Is your requirement testable?
- First of all, the free running timer doesn’t need to be mentioned here at all. It’s probably impossible to black box test, it is neither an input, or an output, and does a poor job of relating the two.
Lets use “The digital output pin shall be toggled at maximum rate of 10 times a second and a minimum rate of once per second.” instead.
- It might be tricky to test #4, lets use “The input voltage on the ADC pin shall be read at least once every 100 milliseconds” as it’s more obviously what the intended behavior is and what we’d need to test.
- #5 is also tricky. How do we check that the valid range is only between 0 and 1 volts? Give it 2 volts and see if it blows up?
How about: “The system shall accept the range of input voltages on the ADC pin be between 0 an 1 volts”. This is much easier test. Requirements should be positive. They should describe how the device should behave, not how the device shouldn’t behave, otherwise testing becomes impossible.
1. The digital output pin shall be toggled at maximum rate of 10 times a second and a minimum rate of once per second.
2. The toggle rate of the digital output pin shall vary linearly between the minimum and maximum rate, directly proportional to the input voltage on the ADC pin
3. The input voltage on the ADC pin shall be read at least once every 100 milliseconds.
4. The system shall accept the range of input voltages on the ADC pin between 0 an 1 volts
Step 7: Is your requirement easy to understand?
These requirements are much harder to read and comprehend than our original “blinks an LED at different rates depending on a reading from a flex sensor”
The easiest way I’ve found to make requirements more readable is to break the finer details out into terms and then define them separately:
The flex-sensor shall be read at least once every 100 milliseconds(see comments)
- LED-state shall toggle at a rate linearly proportional to the flex-sensor reading
- The number of LED-state toggles shall average 10 timers per second when the flex-sensor reading is 1 volt, and 1 toggle per second when the flex-sensor reading is 0 volts.
- flex-sensor : The input voltage on ADC pin X.
Voltages between 0 and 1 volts, shall be accepted.(see comments)
- LED-state : The state of digital output pin Y
These are much better (though not perfect). They are easy to read. They don’t specify any internals of the system. They are easy to test. They constrain the behavior of the system to what is desired, but not much further. (For example, the implementer is free to sample the flex sensor at a faster rate, and this is OK since it won’t cause undesired behavior).
Requirements are kinda like software for the human brain. Try to make them easy to execute.