Test-Driven Development (TDD) is a fundamental programming skill in short supply today. TDD is a powerful design technique that improves the quality and reliability of software as unit tests are automated and run more frequently. One of the key concepts behind TDD is that the software become self-checking. As more people touch the code, they feel comfortable to make changes because if they introduce an error, ideally the software will tell them they made a mistake. This helps the code become more stable over time.
This becomes increasingly important as software begins to take over many functions of our day-to-day lives. Recently, the Tesla autopilot feature experienced a catastrophic failure. As it turns out, the software failed to recognize a truck as it turned in front of an oncoming Tesla and failed to apply the breaks. The driver was killed. When I heard this story, I wondered if Tesla had a unit test for that case? If not, did they update their unit tests after this failure to include this test case?
Teaching TDD is a lot like learning how to ski cross-country. The fundamentals (Red-Green-Refactor) are easy to learn and put into practice in a classroom setting for two, three or four days. After a few hours, novice cross-country skiers (or TDDers) will be gliding across the countryside enjoying themselves and having fun with their friends.
Eventually, some people will graduate to downhill skiing, which (as they will quickly learn) is nothing like cross-country skiing. One, the skis are wider and shorter. Two, skiers go a lot faster. Three, you have learn how to turn. For some people, knowing how to ski cross-country is disorienting and puts them at a disadvantage when downhill skiing. The same can be true of people applying what they learned about TDD in a classroom setting on production code. It is only a matter of time before the skier falls down, hits a tree or smashes into someone else.
So why is this transition so hard? In her keynote speech at Agile Portugal, Emily Bache identified the four design skills one has to master to use TDD effectively with production code.
- Driving development with test cases: this is probably the hardest step in the process; Emily’s recommendation – start practicing with coding katas.
- Designing test cases: when first starting with TDD, your test cases are going to be bad but will improve over time; Emily’s recommendation – practice writing test cases in pairs and review your test cases with a partner.
- Refactoring safely: refactoring is crucial because the first draft of your code (and test code) will not follow the Simple Design guidelines (wrongly identified as “Rules of Simplicity” on the Agile Alliance site); Emily’s recommendation – start where you are and use Legacy Code techniques defined by Michael Feathers.
- Designing clean code: clean code is any code that is easy to write, read and maintain. Learning how to do this takes time. Thankfully, Robert C Martin (“Uncle Bob”) wrote an entire book on this topic and this article explains what clean code looks like.