Non-Functional Requirements
Introduction
"Inside every non-functional requirement, is a feature that matters to users."
-- Dave Farley
Non-functional requirements are constraints on the system that it must operate within. Things like performance, scalability, security, and maintainability are all non-functional requirements.
The limitations placed on a system can have a profound impact on the system's architecture. These non-functional requirements have to be considered early in the design process, otherwise, they can lead to significant rework later on. Functional requirements can usually be isolated and implemented independently, but non-functional requirements often requirement changes to the entire system. Failing to meet one can also result in the failure of the entire system. If you can't scale your system to meet the demand, it doesn't matter how well it meets the functional requirements.
Functional vs Non-Functional Requirements
The term non-functional requirements doesn't really capture the difference between these types of constraints and the functional requirements that describe the system's features.
Functional requirements tend to be:
- Local: They can be implemented independently.
- Atomic: They describe a single feature or function.
- User-facing: They are the features that the users interact with.
- Easily identified: They are usually obvious from the user stories or use cases.
Non-functional requirements tend to be:
- Cross-cutting: They can require changes to the entire system in order to meet.
- Interdependent: They can have cascading effects on other requirements.
- Hard to identify or estimate: They are often implicit in the requirements and need to be teased out through discussion and analysis.
Identifying Non-Functional Requirements
Identifying non-functional requirements early is critical to the success of a project, even more so than identifying functional requirements. These constraints can have a significant impact on the system's architecture and design. It is usually the responsibility of the product owner to identify requirements, but that rarely happens for non-functional requirements. The development team needs to be proactive in identifying these constraints and working with the stakeholders to understand their implications.
Failing to consider them can destroy a project. For example, if you don't consider the performance requirements of a system, you may find that it doesn't scale to meet the demand. If you don't consider the security requirements, you may find that the system is vulnerable to attack. These failures will either require significant rework to fix or may result in the project being abandoned.
Realistic Expectations
One of the biggest issues with non-functional requirements is that non-technical stakeholders often don't understand the implications of these requirements. They may ask for a system to be "fast" without understanding what that means. They may ask for a system to be "reliable" without understanding the trade-offs between reliability and cost.
If you ask a non-engineer if a system needs to be reliable, they will say yes. If you ask them how reliable, they might not have a good answer. A perfectly reliable system is impossible, so there is always a trade-off between reliability and cost. Many non-technical stakeholders don't understand this trade-off and will ask for the system to be "as reliable as possible" without understanding the implications of that requirement.
Sources of Non-Functional Requirements
Non-functional requirements can come from more than just the needs of the product. They can also come from the organization or external sources.
Product
The product itself will obviously have non-functional requirements that need to be met. Teasing out exactly what those requirements are is the responsibility of the product owner and the development team. Some common non-functional requirements that come from the product include:
- Performance: How fast does the system need to be? Do we need to focus on response time or throughput?
- Scalability: How many users does the system need to support? How will this number change over time? Do we need to scale horizontally or vertically?
- Security: What are the security requirements of the system? Do we need to comply with any regulations or standards?
- Usability: How easy does the system need to be to use? Do we need to support multiple languages or accessibility requirements?
- Reliability: How reliable does the system need to be? What is the cost of downtime?
Organizational
The size and resources of your organization will also impact the non-functional requirements of the system. Some common organizational constraints include:
- Cost: What is the budget for the system? What are the cost constraints?
- Maintainability: How easy does the system need to be to maintain? Do we need to support multiple environments or configurations?
- Time: What is the timeline for the system? What are the time constraints?
- Development: Is there a standard development process that needs to be followed? Are there any constraints on the technology stack?
- Operational: Is there a standard operational process that needs to be followed? Perhaps a specific monitoring or logging solution?
External
External constraints can also impact the non-functional requirements of the system. Some common external constraints include:
- Regulatory: Are there any regulations or standards that the system needs to comply with?
- Market: What are the expectations of the market? What are the competitors doing?
- Legislative: Are there any laws that the system needs to comply with? Perhaps data protection or privacy laws? What about safety regulations or export restrictions?
- Ethical: Are there any ethical considerations that need to be taken into account? Perhaps the system needs to be environmentally friendly or support diversity and inclusion?
Describing Non-Functional Requirements
Describing Non-Functional requirements is often more challenging than dealing with functional requirements. One of the issues with gathering non-functional requirements is that stakeholders will describe them in general terms. This leaves them open to interpretation by the developers, which results in disputes after implementation.
For example, a stakeholder who wants the system to be easy to use might write a requirement like this:
The system should be easy to use and should be organized in such a way that user errors are minimized.
The problem with this goal is that there is no way to tell if the requirement has actually been met. Requirements need to be testable. It must be possible to objectively verify that the system meets the requirement.
To make this requirement testable, we need to introduce some sort of metric for determining ease of use. For example, we could measure the number of hours of training required, or log the frequency of user errors, or perhaps the number of help screen accesses. These metrics can be used to determine if the system meets the requirement.
Measurable Requirements
The exact metric we use to measure a non-functional requirement will depend on the type of requirement. Each case will be different, but the key is to make sure that the requirement is testable and measurable. Some common metrics for non-functional requirements include:
- Performance: Response time, throughput, latency, transactions per second, screen refresh time etc.
- Scalability: Number of users, number of transactions, number of concurrent sessions etc.
- Security: Number of vulnerabilities, time to patch, time to detect a breach etc.
- Usability: Number of clicks, time to complete a task, time to learn the system etc.
- Reliability: Mean time between failures, mean time to repair, availability etc.
- Maintainability: Time to fix a bug, time to add a feature, time to deploy a change etc.
- Availability: Uptime, downtime, mean time to recovery etc.
Most companies will have a set of standard metrics that they use to measure these requirements. If you don't have a set of standard metrics, you should work with the stakeholders to define them.
Architectural Implications
When approaching a new system design, I prefer to start by identifying the non-functional requirements and considering how they will impact the overall structure of the system. If you are working with an existing system you need to make sure you understand the existing constraints and how they will impact any changes you make. Failing to consider these constraints can lead to significant rework later on.
Keep in mind that many non-functional requirements are incompatible with each other. In an ideal world, every system would be fast, secure, reliable, and easy to use. In reality, you will have to make trade-offs between these requirements. As you improve one, you may degrade another. For example, increasing the security of a system will often decrease its performance. You need to understand these trade-offs and make sure that the system meets the requirements that are most important to the stakeholders.
Design Considerations
We won't go into much detail here, but some common design considerations for each type of non-functional requirement include:
Security
Any system that handles personal data should put security at the top of the list of non-functional requirements. This includes things like encryption, access control, and auditing. The most secure systems might use a layered architecture with firewalls, intrusion detection systems, and regular security audits.
Such systems are usually slower and have worse availability than less secure systems. Redundancy is rarely a good idea in a secure system, as it can provide additional attack vectors. The trade-off between security and performance is a classic example of the trade-offs that need to be made when designing a system.
Performance
Maximizing performance requires you to minimize communication between components and localize critical operations. This often results in a system that is harder to maintain and scale. Every time we have to communicate between components, we introduce latency. This is why many high-performance systems are monolithic.
Availability
Building with high availability in mind requires redundancy and fault tolerance at every level. This means multiple servers, multiple data centers, and multiple network connections. It also requires careful management of state, since you can't rely on a single server to maintain it. You will also need some sort of management layer to distribute the load across the servers.
Performance tends to be less predictable in a highly available system, as the system may need to degrade gracefully under load. This can result in a system that is slower than a less available system under normal conditions.
Conclusion
Non-functional requirements are difficult to identify and describe, but they are critical to the success of a project. Stakeholders will often struggle to clearly articulate these requirements, so it's up to the development team to tease them out through discussion and analysis. These constraints can have a significant impact on the system's architecture and design, so they need to be considered early in the design process.