Testing, code coverage, test-driven development, TCD. We live in a world where these terms conjure up emotions of excitement and, more often than not, frustration. Everyone wants to live in a world where the software they write is bug-free, but we’ve all come to the realization that there’s no such thing as bug-free software.
In Robert C. Martin’s (Uncle Bob) talk on craftsmanship and ethics, he dives into the (almost morbid) idea that the software that’s written today will inevitably go horribly wrong. We as human beings, like no other time in history, coexist with software all around us. This is true not just of the phones we keep in our pockets but also down to the debit cards in our wallet or the exit signs in buildings. Every piece of hardware that exists requires some set of commands to be executed on it—software. Uncle Bob has predicted that at some point, something will go wrong with software on a massive scale. When this happens, bureaucrats will try to step in to “do something,” resulting in massive pieces of legislation that dictate how software engineers operate.
Uncle Bob’s premise, while insanely dark and depressing, comes with a hint of potential accuracy. We’ve already seen how autonomous cars have encountered software issues that have ultimately killed people. It’s not that big of a stretch to think that as we continue to develop software for the devices around us, bugs could mean tragedy. To Uncle Bob’s point, we may need to rethink our acceptance of the idea that bug-free is a pipe dream.
He goes on to discuss coding standards, clean code and refactoring. As anyone who’s familiar with his line of publications knows, Uncle Bob is an evangelist to the idea of clean, self-documented, SOLID code. Any code that doesn’t live up to these standards has a greater chance of “killing people” because of the lack of ability to maintain it, the lack of shared understanding across team members, and the lack of the ability to make changes without creating side effects. He encourages his audiences to imagine a world where developers have a little red button. Every time a developer presses this button, a light would turn green, indicating that the code is bug-free and ready to ship. That little red button should be a developer’s tests. If a developer scoffs at the idea of these tests acting as a red button that validates whether the code is doing anything worthwhile, Uncle Bob goes on to say that developers don’t have tests that are worth anything and that code is, for all intents and purposes, “not really covered.”
Code coverage is, unfortunately, misleading. To many developers, code coverage means that every line of code is covered by a unit test, and 100% code coverage is the metric that every developer struggles to attain. This can routinely lead to the acceptance of not having 100% code coverage, coinciding with the acceptance that no software is bug-free. The case can easily be made that developers who don’t strive for code coverage and bug-free software could potentially be liable for catastrophes that happen. Uncle Bob’s motivation is to end that cycle.
So, what can be done? Based on the above, it seems we’re missing the boat on something that can result in a doomsday scenario. While I can’t claim to have been handed the stone tablets and tasked with coming down the mountain to present them to the developers children of Israel, I can speak to some ideas that have been churning in my head for the past several years regarding testing.
Testing is a hot topic in the blogosphere and is a heavy point of contention among many developers. It’s easy to find blog articles in favor of unit testing along with many articles discussing how much unit testing is of a waste of time. While many of the articles in favor of unit testing cover the necessity of unit testing from a high level in order to sell the idea, I believe they come up short in terms of implementation details and examples. This leaves implementations to the developer who may or may not have any context on how to properly execute the practice—often resulting in poor tests, brittle tests, massively bloated tests against many different pieces of code, attempts to achieve a “coverage” metric, and tons of wasted time. It’s no wonder that people often venture down this dark and heavily wooded path with a flashlight and turn around before achieving anything that’s meaningful.
Before we get into what test-driven development (TDD) is, here’s what it’s not:
- A silver bullet
- Only a set of unit tests
- Only a set of integration or acceptance tests
- Tests that are only written at the beginning
- Tests that cover a certain percentage of code branches
- A solution for complicated code in fractured or bad patterns
We can’t be successful in TDD if we don’t understand this up front. But what TDD can bring you is value through:
- Making sure a set of behaviors remains in place until explicitly changed
- Ensuring code documentation
- Adherence to a coding pattern that’s simpler to maintain and easier to code against
- The chance to “shift left” and integrate a QA process into the front side of development
- Faster coding
- Faster deployments
- Stable releases
Yes, I said “faster coding” in that list above. Now, I’m sure this has your attention—because there’s no possible way that writing more code will make a person deliver faster . . . right?
Stick with me on this idea, and stay tuned for Part 2 that’ll go into more detail on TDD!
Are you looking for work that matters? Our Technology Teams are growing, and you can view open positions here. Not ready to apply, but interested in chatting with a team member informally to learn more? Request a virtual meeting here.