Steve Berczuk speaks with Dan Wellman about the agile practice of test-driven development (TDD), including prerequisites to instituting TDD, the technical and cultural challenges to using it, and some ideal (and not-so-ideal) contexts for it.
Dan Wellman is director of technology at Cyrus Innovation, a consultancy that helps startups and enterprises craft custom software and implement process improvements. Dan knows a lot about the technical side of agile. He also understands how agile adoption involves both technical and cultural issues. I had the chance to ask Dan some questions about one of the agile practices that challenges developers' habits the most: test-driven development (TDD).
Steve Berczuk: What is TDD?
Dan Wellman: TDD is a core practice of Extreme Programming (XP). In a nutshell, TDD is the practice of writing automated tests for the production code before writing the code and using feedback from the tests to guide the program’s design. This includes the red-green-refactor cycle, which goes something like this: Write a failing test, see it fail (the test-runner progress bar will turn red), write just enough code to make the test pass (the bar will turn green), refactor the production and test code to improve the design, and repeat.
Steve Berczuk: Why is TDD useful in your work?
Dan Wellman: TDD is a tool that helps me improve the quality of my code and design. Because I write the tests before I write the production code, I'm likely to end up with a comprehensive test suite. It's a lot harder to skip the "make sure there's a test for this code" step if I write the test first! TDD offers another source of feedback on the design of my code. If the code is hard to test, it may indicate that there are some coupling or other design problems. By writing those tests first, I get a sense of these problems before (or as) the production code is written.
Steve Berczuk: Writing tests before you have code is a hard concept for some. Can you get some of the same benefits from having a discipline of testing before you commit changes, rather than strictly before writing code?
Dan Wellman: I suspect you can get some of the same benefits. It comes down to the values for me. I value having a suite of tests that I trust will tell me when I've introduced a mistake, and I value having a design that is easy to change. If I have those, then I don’t mind how the code was created. Following TDD makes it easier for me personally to satisfy my values, so I practice it.
I really like J. B. Rainsberger’s explanation of how TDD works. He mentions a distinction in terminology—"test-first" (writing the test code first, then the production code) versus "test-driven" (writing the tests first and using the feedback from the tests to change the design).
There's another variation—I’ve seen it informally called "test-last"—where the rhythm is: Write the production code first and the tests afterwards. I consider that different from TDD, as TDD implies that the tests are written first and the design is shaped as a result of the test and code cycle. Test-last can still deliver a full suite of tests for an application, though, and that provides safety and confidence when working with code. I find it harder to actually write those tests when trying to do test-last.
Steve Berczuk: Do you introduce TDD in all your coaching engagements?
Dan Wellman: For our coaching engagements, generally yes. In many cases, clients hire Cyrus Innovation because they want to learn how to apply the technical practices from XP to their agile project, which includes TDD as well as other practices like refactoring, simple design, continuous integration, and collective code ownership. So, in those cases, we do. Sometimes clients are already practicing TDD, and we help them improve their technique.