Greetings. Today we’re happy to share an article by Karl Wiegers and Joy Beatty, authors of Software Requirements, Third Edition.
You can save 40% on this book right now at the Microsoft Press Store! Use code BESTDEV at checkout. Offer expires June 4, 2016.
So you’ve developed a set of requirements for some portion of your next systems development project. Now what? Experienced project managers and software developers understand the value of translating requirements into rational project plans and robust designs. These steps are necessary whether the next release represents 1 percent or 100 percent of the final product. As shown in Figure 1, requirements serve as the foundation for project plans, designs, code, and tests. In addition to these connections, there is a link between the requirements for the software to be built and other project and transition requirements. Those include data migrations, training design and delivery, business process and organizational changes, infrastructure modifications, and others.
Figure 1. Requirements drive project planning, design, coding, and testing activities.
All of these post-requirements activities demand ongoing collaboration between the project’s business analyst or product owner, project manager, architect, developers, and testers. This article, adapted from our book Software Requirements, Third Edition (Microsoft Press, 2013), presents some guidance for bridging the gap between requirements development and a successful product release through effective design.
From Requirements to Designs and Code
The boundary between requirements and design is not a sharp line but a gray, fuzzy area. Try to keep requirements free from implementation bias, except when there’s a compelling reason to intentionally constrain certain aspects of the design. Ideally, the descriptions of what the system is intended to do should not be slanted by design considerations. Practically speaking, though, projects often possess design constraints from prior products, product line standards, and user interface conventions. Because of this, a requirements specification almost always contains some design information. Include developers in requirements reviews to make sure the requirements can serve as a solid foundation for design.
Architecture and Allocation
A product’s functionality, quality attributes, and constraints drive its architecture design. Analyzing a proposed architecture helps the BA to verify the requirements and tune their precision, as does prototyping. Both methods use the following thought process: “If I understand the requirements correctly, this approach I’m reviewing is a good way to satisfy them. Now that I have a preliminary architecture [or a prototype] in hand, does it help me better understand the requirements and spot incorrect, missing, or conflicting requirements?”
Architecture is especially critical for systems that include both software and hardware components, for systems that interface to many other systems, and for complex software-only systems. An essential step is to allocate the high-level system requirements to the various subsystems and components. An analyst, system engineer, or architect decomposes the system requirements into functional requirements for both software and hardware subsystems. Requirements trace information lets the development team track where each requirement is addressed in the design.
Inappropriate allocation decisions can result in the software being expected to perform functions that should have been assigned to hardware components (or the reverse), in poor performance, or in the inability to replace one component easily with an improved version. On one project, the hardware engineer blatantly told my group that he expected our software to overcome all limitations of his hardware design! Although software is more malleable than hardware, engineers shouldn’t use that flexibility as a reason to skimp on hardware design. Take a systems engineering approach to decide which capabilities each system component should deliver.
Allocation of system capabilities to subsystems and components must be done from the top down. Consider a Blu-ray Disc player. As illustrated in Figure 2, it includes motors to open and close the disc tray and to spin the disc, an optical subsystem to read the data on the disc, an image-rendering subsystem, a multifunction remote control, and much more. These subsystems interact to control the behavior that results when, say, the user presses a button on the remote control to open the disc tray while the disc is playing. The system requirements drive the architecture design for such complex products, and the architecture influences the requirements allocation.
Figure 2. Complex products such as Blu-ray Disc players contain multiple software and hardware subsystems.
Software design receives short shrift on some projects, yet the time spent on design is an excellent investment. The requirements for most products can be satisfied with numerous software designs that will vary in their performance, efficiency, usability, robustness, and the technical methods employed. If you leap directly from requirements into code, you’re essentially designing the software mentally and on the fly. You come up with a design but not necessarily with an excellent design. Poorly structured software that’s not easy to modify is the likely result.
As with requirements, excellent designs result from iteration. Make multiple passes through the design to refine your initial concepts as you gain information and generate additional ideas. Shortcomings in design lead to products that are difficult to maintain and extend and that don’t satisfy the customer’s performance, usability, and reliability objectives.
You needn’t develop a complete, detailed design for the entire product before you begin implementation, but you should design each component before you code it. Formal design is of most benefit to particularly complex projects, projects involving systems with many internal component interfaces and interactions, and projects staffed with inexperienced developers. All projects, however, will benefit from the following strategies:
- Develop a solid architecture of subsystems and components that will permit enhancement over the product’s life.
- Identify the key functional modules or object classes you need to build, as well as defining their interfaces, responsibilities, and collaborations with other units.
- Ensure that the design accommodates all the functional requirements and doesn’t contain unnecessary functionality.
- Define each code unit’s intended functionality following the sound design principles of strong cohesion, loose coupling, and information hiding.
- Ensure that the design addresses exception conditions that can arise.
- Ensure that the design will achieve stated performance, security, and other quality goals.
- Identify any existing components that can be reused.
- Define—and respect—any limitations or constraints that have a significant impact on the design of the software components.
As developers translate requirements into designs and code, they’ll encounter points of ambiguity and confusion. Ideally, developers can route these issues back to customers or BAs for resolution through the project’s issue-tracking process. If an issue can’t be resolved immediately, any assumptions, guesses, or interpretations that a developer makes should be documented and reviewed with customer representatives.
User Interface Design
Your requirements explorations probably took at least tentative steps into user interface design. UI design is so closely related to requirements that you shouldn’t just push it downstream to be done without end-user engagement. Use cases can lead to dialog maps to show user navigation options, wireframes that sketch out screen layouts, prototypes that demonstrate interaction behaviors, and ultimately into detailed UI designs. Sometimes a simple sketch conveys enough information for the UI designer to build effective screens, working with user representatives to validate the design. Other situations will benefit from more detailed UI specifications.
A display-action-response (DAR) model is a useful tool for precisely documenting the UI elements that appear in screens and how the system responds to user actions. A DAR model combines visual screen layouts with tables that describe the elements on the screen and their behaviors under different conditions. Figure 3 shows a sample page from a website, and Figure 4 shows a corresponding DAR model. The DAR model contains enough details about the screen layout and behavior that a developer can implement it with confidence.
Figure 3. High-fidelity webpage design
Figure 4. Display-action-response (DAR) model for the webpage shown in Figure 3.
From Requirements to Success
The ultimate deliverable from a software development project isn’t a set of requirements—it’s a solution that meets the customers’ needs and expectations. Requirements are an essential step on the path from business need to satisfied customers. If you don’t base your project plans, designs, and acceptance and system tests on a foundation of high-quality requirements, you’re likely to waste a lot of effort trying to deliver a solid product. Strive for a sensible balance between off-the-top-of-the-head coding and rigorous specification that will reduce the risk of building the wrong product to an acceptable level.