Building Something Useful
What do we need to build, and why?
These are the fundamental questions we try to answer by gathering, validating, and updating the requirements of a project. I trust the importance of requirements is self-evident. Its primary importance is corroborated by the formidable Guide to the Software Engineering Body of Knowledge (a.k.a. the SWEBOK, a.k.a. ISO/IEC TR 19759:2015), a multi-decade joint effort of the ISO and IEEE, which starts with a treatment of software requirements.
Example: User Stories
The ubiquitous form of the user story is one attempt to answer these questions by seeking to tie each incremental effort to a tangible, justifiable thing that a user can do.
Figure 1: User Story
As a camper, I can transport cold beverages, so that I can enjoy them well chilled and refreshing at my destination.
Implicitly, these sorts of requirements are almost always functional requirements. They describe a meaningful capability of the system “that contributes to the solution of some real-world problem.” This is laudable and also rather obvious.
But any project also comes with non-functional requirements, even when they are never explicitly stated. Non-functional requirements address pervasive qualities like performance, reliability, security, and maintainability. Getting them just as nailed down as the functional requirements are essential to avoid serious misunderstandings or outright project failure. Is the site acceptable when it responds within 2 seconds or 200 milliseconds? Must the store handle one transaction per minute or a thousand per second? How quickly must revocations of user access be effective? How much downtime is acceptable for a deployment? Making good design decisions and judging project success depends on articulating these non-functional requirements.
Figure 2: Systems fulfilling simple functional requirement: “Portable beverage cooler”
Perhaps we need to be more specific
In other words, non-functional requirements are essential for determining how to build a system. Take the example of choosing the data store or stores for a basic e-commerce site. The transaction processing backend requires full ACID transaction support and strict security, but may not need high throughput. The searching capabilities on the same site may have minimal requirements for integrity, consistency, or security, but have high expectations for response time and throughput. In both cases the functional requirements describe a prototypical data store — it can store data and then retrieve it according to arbitrary filters. But the dramatically different non-functional requirements may drive the selection of completely different systems. In fact, our team supports multiple e-commerce sites that store transactional and administrative data in a relational database but execute searching against Elasticsearch, a highly specialized search database. But even this choice reflects yet other non-functional requirements such as cost and maintainability. Depending on those requirements, it may be preferable to use full-text search within a relational database to avoid having to support multiple data stores and the integrations between them.
Finding the Questions
The first step in building and maintaining non-functional requirements is simply knowing which questions to ask. The good news is that many smart people have been thinking and writing about these concepts for decades, so there are rich and well-organized resources to guide such discussions and analyses. A great starting point is another ISO/IEEE publication, Systems and software Quality Requirements and Evaluation (a.k.a. SQuaRE, a.k.a. ISO/IEC 25010:2011). The foundation of that framework is a set of 8 primary characteristics and 31 secondary characteristics that describe product quality (source):
- Functional completeness
- Functional correctness
- Functional appropriateness
- Time behavior
- Resource utilization
- Appropriateness recognizability
- User error protection
- User interface aesthetics
- Fault tolerance
A summary of each of the above characteristics is included in the publicly accessible portions of ISO/IEC 25010:2011. The summaries include notes such as the subtle distinction that functional suitability addresses how well aligned the function is with the functional requirements but does not include the functional requirements themselves.
Figure 3: Functional appropriateness: “Hammers nails”
Clockwise from top left: Ancient Egyptian “pounder” (source), sledgehammer, semi-stiff vulcanized poultry, claw hammer.
The formidable and widely-cited Software Requirements by Karl Wiegers and Joy Beatty also groups these ‘ilities' into two categories:
— Execution qualities, which describe how a system behaves at is running. These include security, usability, reliability, and performance efficiency.
— Evolution qualities, which arise from how the system is structured. The umbrella of maintainability captures many of these.
This is a useful distinction, because end users are generally more aware of the execution qualities, while developers (and hopefully project managers) should also be keen on considering the evolution qualities. In my years I have ̶c̶o̶m̶m̶i̶t̶t̶e̶d̶ seen many instances where work to increase execution qualities — especially performance — came at great cost to evolution qualities such as analysability (can the team understand it?) and modifiability (can the team change it, preferably without breaking it?).
Questions in Context
While resources such as those cited above are helpful for informing professionals as we guide and document the requirements gathering process, they are likely too overwhelming to put in front of customers and clients as is. Rather, we can use these to formulate more tailored and in-context questions that can be discussed directly.
Here, for example, is a starting rubric for sussing out NFRs for a basic web application:
Availability — Are scheduled outages acceptable? During which times? — What amount of downtime is acceptable during deployments or upgrades
Data Consistency (relates to Fault tolerance, Recoverability, Functional correctness, and Functional completeness)
- Which data, if any, requires full ACID guarantees? E.g. financial transactions, user access
- Which data, if any, can forgo these guarantees? E.g. unstructured search data
- What browser versions and/or native platforms must be supported?
- Time behavior: How quickly should the site respond to (homepage / search queries / add to cart)?
- Resource utilization: What’s the monthly budget for infrastructure
- Capacity: What request volume is expected? At what level is performance degradation acceptable? How variable is usage throughout a day?
- Is there any sensitive, confidential, or regulated private information in the system?
- How quickly must access changes be effective? This directly impacts browser-based authentication and authorization mechanics. For example, can anonymous shareable links be created? How quickly should they expire?
- Analysability: What metrics are expected or needed? Does the client expect to have access to these?
- Modifiability: What aspects of the system should be modifiable or configurable by the user? What amount of subsequent feature changes are expected? What is the technical capacity of the team to work in a potential language or platform?
While general questions can be a helpful starting point, some non-functional requirements will be just as specific as the functional requirements for a given system. For better or worse, software design is not a thing that can be done by checklist.
~Joshua, Software Developer