For me, there are two main, long-term benefits of TDD (Test-Driven Development):
First, by using TDD (thus writing the tests first) you make sure that your code remains in a testable state all the time (even if you don’t write all the tests to cover all the edge cases) – As anybody working with legacy code can attest, adding unit tests to an existing code base is usually excruciatingly hard and takes a lot of time. It can be done – witness Working with Legacy Code, sure, but it’s a very long and thorny journey. You don’t want to go down this road with the new code you’re writing every day.
Second, by using TDD you always have a decent, highly decoupled design – not a perfect or insanely great design, but quite a usable design to go forward. More often than not, it will be a better design than you’re used to.
“Test-Driven Development” is actually “Test-Driven Design”.
- Learned a lot doing my "TDD for plug-in development" presentation last night. More code samples and a few more screenshots badly needed. #
- @ThoMo1969 Bin evtl. im Laufe des Jahres mal wieder in unsere Zentrale in Münster – K/DUS liegt ja quasi "auf dem Weg"… in reply to ThoMo1969 #
- @thecleancoders Just a notch. in reply to thecleancoders #
- . @FridayBruceFix gets up early to make sure we're covered – Bruce Springsteen, Ramrod http://t.co/Esqr3ncy #
- Very insightful posts on TDD for embedded systems – http://t.co/AuUA4HOJ – (via @unclebobmartin ) #yam #
- .@nilslofgren 's "Miss You Ray" – http://t.co/JT8IuwDS – Simply beautiful #
- The main benefits of TDD (Test-Driven Development) – http://t.co/B3lJWAIj #fb #
- Thanks to @marcphilipp and @leiderleider for ever so subtly reminding me to brush up my slides for tonight's talk… 😉 #
- On a totally unrelated topic, here's Snack Attack for the Apple II – If you think it's boring and slow, you should play Maze 35+ #fb #
- Those were the days… #
- @ThoMo1969 Wir warten mal ab was die Kollegen in Karlsruhe zu meinen Einlassungen sagen… in reply to ThoMo1969 #
- RT @FridayBruceFix Well you say you got no new dreams to touch, you feel like a stranger babe who knows too much http://t.co/Z8pR1cc3 #
- @FridayBruceFix Great News! Glad you got tickets. Will see all three German shows – First with wife & daughters – 2nd/3rd front of stage. in reply to FridayBruceFix #
I very much enjoyed @unclebobmartin‘s generous talk at the Java User Group Karlsruhe last night. In addition to covering rockets, linear accelerators and small nuclear bombs as a means to overcome the gravitational field of the earth, he gave a great introductory talk on TDD and professionalism. Always a pleasure to be reminded on why we are doing TDD in the first place.
One of the questions which came up during Q&A – I’m paraphrasing here – was:
“I tried TDD and was told not to design or think, just to write the tests and the code. The result was a mess”.
Bob Martin’s answer was along these lines:
If you’re a TDD newbie, you need to leave your old rationale of thinking things through upfront behind. So the recommendation is “Don’t think about the design or what’s next”, but to methodically follow the mantra “Write some failing test” – “Write some code just so the test is satisfied” – “Write some failing test” – “Write some code just so the test is satisfied” – …. As your start to grok the rhythm of TDD, you gradually let your design skills in.
I would like to humbly elaborate on this answer. The practice of TDD consists of three simple steps:
- Step 1 – “Red” – Write some failing test
- Step 2 – “Green” – Write some code just so the test is satisfied (implement the simplest thing that could possibly work (not sure who coined the term, probably Ward Cunningham))
- Step 3 – “Refactor” – Remove all duplication from both your production and your test code
Resist your urge to design upfront, to think through algorithmic solutions and alternatives. Just write a failing test. Then, write some code to make the test pass. Don’t write more code. Just the amount of code to make the test pass.
Now, turn to step 3. If you skip it, you will create a mess.
Step 3 is where your design skills are more than welcome. Apply your design skills to ruthlessly eliminate the duplication you created (and you did create some duplication because you did “the simplest thing that could possibly work” in step 2, didn’t you?) – Just keep in mind that you are not supposed to create a design which anticipates future requirement changes, you are supposed to ruthlessly eliminate duplication to create “the simplest design that could possibly work” for your current code base.
So there are a lot of design skills involved in TDD. It’s just that most of the design skills are applied “after the fact”. They are applied after you made the failing test pass.
There’s another place for design skills in TDD. Look at the first step – “Red”. You are supposed to write a failing test. You will probably need to instantiate an object (which, keep in mind, doesn’t exist yet). Or call a function or method (which don’t exist yet, either) on an existing object. You can apply your API design skills right there: What’s the best way to name the class or function? Which parameters do you need? How do you minimize the number of parameters? How do you make it easy for the test (and future users of the class / function) to accomplish the task at hand?
You aren’t convinced yet? You still need more places to apply your superior brain powers? Good news, there’s even more “thinking” involved. In step 1, you are supposed to write a failing test. This requires a lot of thinking:
- What do I test next?
- What’s the next logical step in the evolution of my method / class?
- What are the edge cases I need to test for?
- Which test will small enough in scope that I can cope with the implementation right away?
- Which test will bring me closer to the solution of the task i’m working on?
If you follow TDD and apply your thinking and design skills as described above, you will end up with a testable, highly decoupled design. It’s not a great design yet, but chances are it’ll be a much better and more usable design than the ones you’ve encountered so far.
You may wonder why I didn’t mention the long and hard thoughts you need to think in step 2 while writing the code to make the test pass. Two questions for you: You did write some failing test, just enough testing code so the test fails, correct? Then you did the simplest thing that could possibly work to make the test pass, correct? Nothing more? Good. Go figure.