TDD is about Design, not Testing

Philip Borlin
4 min readFeb 23, 2018

--

Have you ever looked at your code six months later and wondered how in the world you wrote such terrible code? This could be a sign of your growth as a coder, or it could be you are just writing terrible code. Some attributes of terrible code are code with high cyclomatic complexity, fluff code that doesn’t contribute to the solution, code that other’s can’t understand, etc.

Surely there must be some way to get yourself out of this habitual bad code cycle.

One strategy is to spend a little more time designing your code. Make your code a little more intentional. By spending some time thinking about your destination you are much more likely to get where you want to be.

Design comes in may forms. There are larger scale system design, more fine grained component design, and what we are going to talk about about are little micro designs. Test Driven Development (TDD) is one such micro design tool. In fact, it is so good at micro design that it may be more appropriately called Test Driven Design.

The Premise

The premise is simple. Write a Test that fails. Write some code to make the test pass. Take some time to refactor your code. This virtuous cycle is affectionately referred to as Red Green Refactor. This comes from the convention that most test runners color failing tests with red and passing tests with green.

The key concept is that tests should drive your code. The testing phase is about writing a micro design that also contains a testable proof that you followed the design.

Micro is a relative term and provides no useful information on how comprehensive your test should be or how much time you should spend implementing the code to make the test pass. The guideline is that the test should be as small in scope as possible while still driving a useful evolution of the design.

Two Minute Drill

One exercise that can help you is the two minute exercise that is popular in Code Retreats. The first step is to get your version control into a stable committed state. Then set a timer for two minutes. You have two minutes to write a test, make it pass, and commit the code to version control (including the version control comment). If you aren’t committed when the timer goes off you need to roll back your workspace back to the previous state (effectively deleting the test and code you just wrote). If you commit within the two minutes then you reset the timer and repeat.

After a short 30 minute exercise you will have gone through the red green refactor cycle at least 15 times. After running this exercise a few times you should develop an intuitive sense about what a micro design looks like.

I don’t advocate that all TDD cycles should be 2 minutes long. When I work on distributed systems I run into many TDD cycles where I can’t do anything meaningful in 2 minutes. The exercise is to practice tightening up your design, not to constrain yourself to a practice that only works for trivial problems. It is useful for a season practitioner to come back to this exercise every so often just to keep their TDD cycles tight.

End State

By continually doing micro designs in the form of tests your code will stay razor focused on the solution. You are constantly reassessing how to complete your task in the simplest manner. By strictly practicing TDD your solutions will tend to be much simpler. Your code will also tend to be much tighter because you stayed focused the entire time. Your code will tend to be much more readable because of the tight focus and the simplicity.

TDD should not be your testing strategy. It is a design activity and should be in the context of a larger testing strategy which includes integration, acceptance, and other levels of testing. TDD produces unit tests during the design process and your code coverage tends to look AMAZING, but coverage can be a false sense of security if your acceptance criteria isn’t met.

Throwing Away Tests

After practicing TDD for awhile you will end up with a pile of tests that can sometimes become unwieldy. If you unit tests don’t run in under a second or two then you aren’t going to run them as often as you should. Tests exist to take away your fear of regression. If you have an area where you have a high degree of confidence (maybe you have good integration and acceptance tests) then feel free to throw away some of your unit tests.

Don’t forget the point of TDD is the design and not the tests. If your design changes then you should change your design documents. Think of the tests that came out of TDD as a design document. Don’t become a slave to your tests. If you had a major redesign you would throw away your design document and create a new one. Think of your tests the same way. It is ok to remove a large swath during a major redesign and start a fresh unencumbered TDD slate.

Conclusion

Test Driven Development is about design, not testing. It is a powerful tool for keeping your code tight and focused and can radically simplify your solutions. TDD complements your overall design strategy as a micro-design element. As with other design activities you should feel free to radically alter design and start fresh when necessary. You should also have a comprehensive testing strategy because TDD is not meant to meet your testing needs.

--

--