Richard Bucker

Just good enough or why TDD should be dead

Posted at — Nov 27, 2014

It’s Thanksgiving 2014 and we’ve returned home after a nice family Thanksgiving dinner. The icing on the cake was the recollection of the Vietnam era Soviet Union and how that story could have meaning on the modern view of TDD and other types of software testing and development. While the stories were wonderful to hear I cannot do the storytelling justice so I’ll limit my comments to the learnings except to say that the storyteller was an engineer which included working for the old Soviet space program and other agencies.

When we talked about the space program he verbalized something that UX designers already know. Keep is simple. But what UX designers don’t appreciate is that simple also means few moving parts or the second layer of simple in the actual implementation.  As he described it when you’re out there in space you do not have time to be distracted by bad interfaces. And things have to be simple to prevent the number of potential points of failure.

The conversation shifted to what I have always referred to as “good enough”. When US planes were shot down in Vietnam they would be recovered and reverse engineered by Russian engineers. Oddly enough they discovered that the planes were constructed to be “good enough”. It was said that US designers knew that the planes would eventually fail; either by stresses they were performing under or because the enemy would shoot them down.  In either case there was no point in over-engineering them for the long run. They had to be “good enough”. One specific example was the size of the bearings used on a particular component. In the US version the bearing was just a few mm and in the Soviet version they were much bigger. The smaller bearings were easier to manufacture but had a shorter life.

As I look back on my career I see moments when I was designing systems that I intended to live forever and others that were only going to run for a few years before they were replaced. One perfect example is a pair of payment gateways.  The first system was implemented in the erlang programming language. I had great hopes for the project based on the capabilities of the language and for the most part it has lived up to that potential, however, [a] it took a lot longer to write the gateway and [b] while gateway is bulletproof it’s been so long that I don’t think I could make changes to it if I wanted to. Having the maturity to know what is good enough is contrary to what we are taught in school and when we learn early in our careers. Making that right decisions is non-trivial. Most software is replaced after a few years so there is no point in write something that could live for years.

So what I’ve learned is that I/we need to keep things [i] simple, [ii] good enough, and [iii] that simple and good enough also means that the testing can also be limited to that which supports simple and good enough. So the next time you’re thinking of implement tens of thousands of test cases meant to produce 100% code coverage consider that your project might not need all of them and that simple things only need simple tests.