Benefits of Testability
Apart from shielding the developers and testers from immediate misery, testable software also has some other appealing qualities.
Its Functionality Can Be Verified
If the software is developed so that its behavior can be verified, it’s easy to confirm that it supports a certain feature, behaves correctly given a certain input, adheres to a specific contract, or fulfills some nonfunctional constraint. Resolving a bug becomes a matter of locating it, changing the code, and running some tests. The opposite of this rather mechanical and predictable procedure is playing the guessing game:
Charlie: Does business rule X apply in situation Y?
Kate: Not a clue! Wasn’t business rule X replaced by business rule Z in release 5.21 by the way?
Charlie: Dunno, but wasn’t release 5.2 scrapped altogether? I recall that it was too slow and buggy, and that we waited for 5.4 instead.
Kate: Got me there. Not a clue.
Such discussions take place if the software’s functionality isn’t verifiable and is expressed as guesses instead. Lack of testability makes confirming these guesses hard and time consuming. Therefore, there’s a strong probability that it won’t be done.
And because it won’t be done, some of the software’s features will only be found in the lore and telltales of the organization. Features may “get lost” and, even worse, features may get imagined and people will start expecting them to be there, even though they never were. All this leads to “this is not a bug, it’s a feature” type of arguments and blame games.
It Comes with Fewer Surprises
Irrespective of the methodology used to run a software project, at some point somebody will want to check on its progress. How much work has been done? How much remains? Such checks needn’t be very formal and don’t require a written report with milestones, toll gates, or Gantt charts. In agile teams, developers will be communicating their progress at least on a daily basis in standup meetings or their equivalents.
However, estimating progress for software that has no tests (because of poor testability) ranges between best guesses and wishful thinking. A developer who believes he is “95 percent finished” with a feature has virtually no way of telling what fraction of seemingly unrelated functionality he has broken along the way and how much time it’ll take to fix these regressions and the remaining “5 percent”. A suite of tests makes this situation more manageable. Again, if the feature is supposedly “95 percent finished” and all tests for the new functionality pass, as well as those that exercise the rest of the system, the estimate is much more credible. Now the uncertainty is reduced to potential surprises in the remaining work, not to random regressions that may pop up anywhere in the system. Needless to say, this assumes that the codebase is indeed covered by tests that would actually break had any regression issues taken place.2
It Can Be Changed
Software can always be changed. The trick is to do it safely and at a reasonable cost. Assuming that testable software implies tests, their presence allows making changes without having to worry that something—probably unrelated—will break as a side effect of that change.
Changing software that has no tests makes the average developer uncomfortable and afraid (and it should). Fear is easily observed in code. It manifests itself as duplication—the safe way to avoid breaking something that works. When doing code archaeology, we can sometimes find evidence of the following scenario:
At some point in time, the developer needed a certain feature. Alas, there wasn’t anything quite like it in the codebase. Instead of adapting an existing concept, by generalizing or parameterizing it, he took the safe route and created a parallel implementation, knowing that a bug in it would only affect the new functionality and leave the rest of the system unharmed.
This is but one form of duplication. In fact, the topic is intricate enough to deserve a chapter of its own.
Why Care about Testability
Ultimately, testable software is about money and happiness. Its stakeholders can roll out new features quickly, obtain accurate estimates from the developers, and sleep well at night, because they’re confident about the quality. As developers working with code every day, we, too, want to be able to feel productive, give good estimates, and be proud of the quality of our systems. We also want our job to feel fulfilling; we don’t want to get stuck in eternal code-fix cycles, and, above all, we don’t want our job to be repetitive and mind numbing. Unfortunately, unless our software is testable, we run that risk. Untestable software forces us to work more and harder instead of smarter.