In Part 1 of this series, I presented a brief description of test driven development (TDD) and discussed how it differs from traditional approaches to software development. In this post I will share six key benefits of using TDD for your software project. In Part 3, I will take a closer look at some of the reasons TDD may not work for your project and suggest some critical questions to ask before deciding.
1. Better, More Detailed Requirements
In one of my previous projects, I was working on a portable ventilator that could be used in rescue helicopters. One important upcoming feature was detecting blockages in the breathing circuit. At the time, the customer requirement was:
The system shall detect blockages in the breathing circuit.
Imagine approaching this requirement using the traditional process:
The team gathers around the white board and comes up with a stellar design. They spend a week or two implementing it. The time comes to write the test. The test engineer looks at the requirement and scratches her head. “What do you mean by blockage?” she asks.
The software team looks around. “When there is no flow,” one of them says.
Fortunately, the Product Owner happens to be walking by at that moment. “That’s not right,” he says. “We must be able to detect even partial blockages!:
The team discusses it and comes up with a more specific quantifiable requirement. Sadly, the original design did not account for this and the time already expended on this feature has been lost. Had the Product Owner not happened along, even more time and development cost might have been wasted.
By writing the test first, we are forced to take a closer look at the requirements early on in the process.
The act of asking the “but, what if..” questions early does two things:
- It opens requirements-driven communication between the product owner, developers, and testers, helping all sides fully understand what needs to be done for each feature.
- It helps the team create thoughtful designs by anticipating challenges before time is spent on implementation.
2. “You Aren’t Going to Need it” TDD = Less Production Code
Sometime called YAGNI, “You Aren’t Going to Need It” is a programming principle that says developers should not add unnecessary functionality to a system. It is along the same lines as “Keep, It Simple, Stupid”, KISS, and Minimum Viable Product (MVP).
With TDD, we only write the code that is needed to pass the test. This yields less production code which has many downstream benefits as discussed below.
Let’s go back to the ventilator example. The vent needs to operate in a helicopter, so the team has been tasked with implementing a barometer feature that measures ambient pressure and altitude. The sensor is quite capable. It can be commanded through software to give pressure data in units of KPa, psi, mmHg, or altitude directly in feet. It can have a sample time of 2ms, or 4ms, 8ms, or 16ms.
Given the variety of options available from the sensor, it wouldn’t be uncommon for the developer to implement a communication architecture with commands to change the barometer’s sample time and commands to change the measurement units.
However, knowing that we are doing TDD, the software developer first writes a test based on the requirement, which is something along the lines of: the system must report altitude at least once per minute. Instead of the first approach, the team sets up the barometer to report altitude in feet every 16 ms. It passes the test and they are done.
Why do we want less code? In general, less code means:
- Fewer bugs
- Fewer features to test
- Fewer features to document
- Easier maintenance
- Less code to review
- Potentially lower hardware costs
For medical devices especially, less code often means less risk, and can result in a smaller, less complex regulatory application.
Imagine if the team had implemented the full communication system described above. As this is a medical, all of the software in the device must be tested, which means we must write additional functional tests and additional unit tests to cover each other different sample rates and pressure units. Further, regulatory documentation requires diagrams and descriptions of this more complex software architecture. When the development team runs regression tests, they must ensure that this additional functionality continues to work.
Test Driven Development can help development teams stay true to the YAGNI principle.
3. Design for Testability
Because developers will be writing the test first, using TDD will encourage them to design software with testability in mind. For example, it is much easier to test loosely coupled, modularized units of software, so developers will often write production code in this way. As a result, the release code will likely be more extensible and easier to maintain.
4. Smaller Units of Code = Find Bugs Faster
Design for testability will usually result in smaller, more focused units of code, because this makes writing the test easier. Because the software units are smaller, it is also easier to find and resolve software defects. As a result, we’re likely to have a fewer bugs on release. For medical devices and other safety-critical projects, defects in the release can lead to delayed regulatory approvals or a device recall.
5. Better Test Suites and Higher Code Coverage
Because TDD can instigate a greater level of rigor in testing, this process often leads to a more comprehensive suite of tests and higher test coverage. Both results are especially beneficial for projects in the medical device or other safety-critical systems. For FDA 510(k) applications, these test suites can be used to help prove equivalence with predicate devices. In both cases, the better the documentation included in your medical device’s Design History File, the better the chances of a smooth submission.
Regulatory clearance often requires demonstrating traceability between requirements, tests, and software artifacts. Test Driven Development helps us maintain this traceability throughout the development process.
By following TDD, we must write the test early and therefore it must be based on a specific requirement. This creates the traceable link between test and requirement. During the implementation step, we only write the code that is needed to pass the test. This creates an additional traceable link between the software artifact and the test. Combining this means that we will have full traceability between our requirements, test, and software artifacts.
Without discipline of TDD, we may write and run all of the tests at the end, after all code has been written. These tests may be based on requirements, but we will have to go back into the code to determine which software artifacts satisfy which tests.
Doing traceability at the end takes more time and can often reveal gaps that need to be filled late in the project lifecycle.
Together, these six benefits of Test Driven Development can help software teams quickly develop quality software, especially in safety-critical industries where code coverage and traceability are paramount.
But wait! Test Driven Development is not right for every project and every environment. In the final part of this series, I will look at some reasons that Test Driven Development may not be right for you and your project, and some critical questions to ask before you decide.
Comments are closed.