My long-time girlfriend works as a Business Analyst for an IT company that does agile development. Recently, she asked me what I (as an engineer) look for in an ideal requirements document for a feature.
This hit home for me because I have seen plenty of poorly-defined features on projects I’ve worked on. Poor requirements usually lead to slower development times and features that are more likely to need rework. As an engineer, I have enough work to do in figuring out the best way to architect and implement a feature without having to frequently halt my work and chase down vague or incomplete requirements.
I did a lot of thinking and came up with a pretty comprehensive checklist of things I’d like to see in every feature request/user story/programming task.
1. Background and Business Value
When I get a feature request, I always want to understand the why. Primarily I want two pieces of information:
- How is this feature going to be used?
- What business value is this feature providing?
There are a number of techniques for expressing the answers to these two questions, including the use of personas, synthesizing feedback from user interviews, or asking a domain expert. Whatever way you go about it, it’s important to provide proper context for a story and to validate the business use case.
2. Wireframes for UI Changes
A picture is worth a thousand words, as the saying goes. I use the term wireframe rather loosely, but many programming features are going to involve a change in some type of UI. The easiest way to communicate these changes are with some type of mockup. This mockup may be very sophisticated, like a Photoshop rendering or an HTML prototype, but it could just as easily be something simple like a Microsoft paint file or an excel spreadsheet (or even a hand drawing).
The biggest concern here is to clearly communicate the before and after of the UI, highlighting all of the changes between the two. For example, which of these more clearly describes a UI change?
There needs to be a new field labeled “Tax Rate” below the existing “Cost” field on the invoice screen. The “Tax Rate” field should have a placeholder of “0.0”. There should be a “%” symbol after the field.
Of course the best approach is to combine the two — in most cases, a detailed description that annotates a wireframe makes UI changes very obvious.
3. Detailed Descriptions of Complex Logic
As a programmer, it’s very frustrating to run into complicated business logic that’s poorly explained. Since these bits of logic often form the heart of an individual feature, it’s very important they are clearly and accurately defined. Failure to do this will in the best case lead to a lot of unnecessary back and forth as the programmer tries to gather the requirements. At worst, the programmer will just make assumptions that are often faulty and lead to rework needing to be done. Either way this means lots of time wasted. Ways to avoid this include:
a. Clearly Defining Calculations and Conditions
The “Total Cost” is calculated by multiplying the “Price” field by the “Tax Rate” field and then adding the “Government Fees” field.
If the “End Date” is before the current date 2 years ago and the “Remaining Cost” field is greater than zero, then set the “defaulted” flag to true, otherwise set it to false.
b. Covering Edge Cases
Using the first example from above:
If the “Tax Rate” field is undefined or has a value of zero, then any government fees do not apply. In this case, the total cost is equal to the “Price Field”.
c. Providing Examples Where Possible
Using the second example from above:
Given the current date is 11/12/2013
End Date Remaining Cost Defaulted Explanation 11/11/2011 $73.00 TRUE The end date is more than 2 years ago and the remaining cost is greater than 0 9/8/2009 $0.00 FALSE The remaining cost is 0 11/13/2011 $73.00 FALSE The end date is less than 2 years ago 11/12/2011 $73.00 FALSE The end date is exactly 2 years ago, but not more than 2 years ago
Providing detailed descriptions has other benefits too like creating clear documentation of business logic for future team members to reference. It also gives your devs information they can translate directly into unit tests to verify the code.
4. Include Data Considerations
Data considerations is kind of a vague term. When I use it, I am thinking of two things: data constraints and expected value for data.
Data constraints are very important to a programmer. For example, if a numeric value can never be negative and must be less than 10, a programmer may use different ways to store and manipulate that value than they would for another value without such constraints. Data constraints may also bring about UI considerations, such as how a certain field should be input by a user or how an invalid value should be displayed.
Expected values are also very important to take into consideration and should be provided whenever possible. For example, say your system has the concept of an “order” that contains “items”. There may be no hard constraint on the number of items an order can have, however your data may show that the number of items realistically falls between 1 and 5 for 99% of the time and has never been recorded above 20. This data is important to an engineer because it can affect things like the data structures, algorithms, and overall architecture they use to implement a feature.
Something as simple as a table or spreadsheet can be a great way to define data considerations, for example:
|Must be greater than zero. Maximum of two decimal places.
|Generally in the range of 0.50 to 1000.00. Technically no upper limit, but realistically it has never been higher than 5000.00
|Must be greater than or equal to zero. Maximum of three decimal places. must be less than or equal to 100
|Generally in the range of 3.0 to 10.0
|Must be either blank, or one of the following values:
These aren’t a set of hard and fast rules. Projects and features within projects vary too wildly for these to work every single time. However, they are solid guidelines for helping you write story requirements that don’t make your engineers want to pull their hair out.
Getting requirements right can be challenging, but it’s always worth it. Bad requirements will mean lots of time lost to confusion and long conversations trying to clarify features between BA’s, Developers, QA’s, and other team members. Good requirements also reduce the amount of context switching team members have to do because they don’t have to stop what they are working on to clarify requirements.
What techniques do your teams use to define requirements?