Diminishing business outcomes
It’s not just the development team who suffers from the effects of bad code. It’s bad for the entire business.
Our poor users end up paying for software that doesn’t work, or at least that doesn’t work properly. There are many ways that bad code can mess up a user’s day, whether as a result of lost data, unresponsive user interfaces, or any kind of intermittent fault. Each one of these can be caused by something as trivial as setting a variable at the wrong time or an off-by-one error in a conditional somewhere.
The users see neither any of that nor the thousands of lines of code that we got right. They just see their missed payment, their lost document that took 2 hours to type, or that fantastic last-chance ticket deal that simply never happened. Users have little patience for things like this. Defects of this kind can easily lose us a valuable customer.
If we are lucky, users will fill out a bug report. If we are really lucky, they will let us know what they were doing at the time and provide us with the right steps to reproduce the fault. But most users will just hit delete on our app. They’ll cancel future subscriptions and ask for refunds. They’ll go to review sites and let the world know just how useless our app and company are.
At this point, it isn’t merely bad code; it is a commercial liability. The failures and honest human errors in our code base are long forgotten. Instead, we were just a competitor business that came and went in a blaze of negativity.
Decreased revenue leads to decreased market share, a reduced Net Promoter Score®™ (NPS), disappointed shareholders, and all the other things that make your C-suite lose sleep at night. Our bad code has become a problem at the business level.
This isn’t hypothetical. There have been several incidents where software failures have cost the business. Security breaches for Equifax, Target, and even the Ashley Madison site all resulted in losses. The Ariane rocket resulted in the loss of both spacecraft and satellite payload, a total cost of billions of dollars! Even minor incidents resulting in downtime for e-commerce systems can soon have costs mounting, while consumer trust crashes down.
In each case, the failures may have been small errors in comparatively few lines of code. Certainly, they will have been avoidable in some way. We know that humans make mistakes, and that all software is built by humans, yet a little extra help may have been all it would have taken to stop these disasters from unfolding.
The advantage of finding failures early is shown in the following diagram:
Figure 1.4 – Costs of defect discovery
In the previous figure, the cost of the repair of a defect gets higher the later it is found:
- Found by a failing test before code:
The cheapest and fastest way to discover a defect is by writing a test for a feature before we write the production code. If we write the production code that we expect should make the test pass, but instead the test fails, we know there is a problem in our code.
- Found by a failing test after code:
If we write the production code for a feature, and then write a test afterward, we may find defects in our production code. This happens a little later in the development cycle. We will have wasted a little more time before discovering the defect.
- Found during manual QA:
Many teams include Quality Assurance (QA) engineers. After code has been written by a developer, the QA engineer will manually test the code. If a defect is found here, this means significant time has passed since the developer first wrote the code. Rework will have to be done.
- Found by the end user once code is in production:
This is as bad as it gets. The code has been shipped to production and end users are using it. An end user finds a bug. The bug has to be reported, triaged, a fix scheduled for development, then retested by QA then redeployed to production. This is the slowest and most expensive path to discovering a defect.
The earlier we find the fault, the less time and money we will have to spend on correcting it. The ideal is to have a failing test before we even write a line of code. This approach also helps us design our code. The later we leave it to find a mistake, the more trouble it causes for everyone.
We’ve seen how low-quality code gives rise to defects and is bad for business. The earlier we detect failures, the better it is for us. Leaving defects in production code is both difficult and expensive to fix, and negatively affects our business reputation.