Test-Driven Development and Continuous Refactoring
Test-driven development [Beck, TDD] and continuous refactoring, two of the many excellent XP practices, have dramatically improved the way I build software. I've found that these two practices have helped me and the organizations I've worked for spend less time over-engineering and under-engineering and more time creating high-quality, function-rich code, produced on time.
Test-driven development (TDD) and continuous refactoring enable the efficient evolution of working code by turning programming into a dialogue.
Ask: You ask a question of a system by writing a test.
Respond: You respond to the question by writing code to pass the test.
Refine: You refine your response by consolidating ideas, weeding out inessentials, and clarifying ambiguities.
Repeat: You keep the dialogue going by asking the next question.
This rhythm of programming put my head into a totally new place. By using TDD, instead of spending lots of time thinking about a design that would work for every nuance of a system, I now spend seconds or minutes making a primitive piece of behavior work correctly before refactoring and evolving it to the next necessary level of sophistication.
Kent Beck's mantra of TDD and continuous refactoring is "red, green, refactor." The colors refer to what you see when you write and run a test in a unit-testing tool (like JUnit). The process goes like this.
Red: You create a test that expresses what you expect your code to do. The test fails (turns red) because you haven't created code to make the test pass.
Green: You program whatever is expedient to make the test pass (turn green). You don't pain yourself to come up with a duplication-free, simple, clear design at this point. You'll drive towards such a design later, when your test is passing and you can comfortably experiment with better designs.
Refactor: You improve the design of the code that passed the test.
Simple as this sounds, TDD and continuous refactoring turn the world of programming upside down. The inexperienced programmer may think, "Write a test for code that doesn't exist? Write code that passes a test yet needs immediate refactoring? Is this a wasteful, haphazard approach to software development or what?"
Actually, it's just the opposite. TDD and continuous refactoring provide a lean, iterative, and disciplined style of programming that maximizes focus, relaxation, and productivity. "Rapid unhurriedness" is how Martin Fowler describes it [as quoted in Beck, TDD], while Ward Cunningham explains that it's more about continuous analysis and design than it is about testing.
Learning the right rhythm of TDD and continuous refactoring requires practice. Tony Mobley, a programmer I know, described this style of development as a paradigm shift as great, if not greater, than moving from structured programming to object-oriented programming. However long it takes you to get used to this style of development, once you do, you'll find that producing production code any other way feels odd, uncomfortable, even unprofessional. Many of us who program using TDD and continuous refactoring find that it helps us:
To learn the ins and outs of TDD, study Test-Driven Development [Beck, TDD] or Test-Driven Development: A Practical Guide [Astels]. For a taste of what it's like to do TDD, see the example sections from Replace Implicit Tree with Composite (178) and Encapsulate Composite with Builder (96). To learn how to continuously refactor, you'll want to study Refactoring [F] (particularly the first chapter) as well as the refactorings in this book.