17
Apr 12

Where does “thinking” and “design” fit into the TDD picture?

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?

Conclusion

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.

Addendum

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.


18
Oct 11

Thoughtworks Event, Frankfurt

Last night, Thoughtworks was hosting an public event @ Japan Center, Frankfurt – right next to the EZB and Deutsche Bank headquarters (I sure hope that those buildings were filled with busy & smart people working on setting things straight with the Euro).

  • 18:45 – Welcome by Nick Ashley, MD of ThoughtWorks Deutschland
  • 19:00 – Wolf Schlegel: “Dos and don’ts of Continuous Integration and Delivery”
  • 19.20 – Erik Dörnenburg: “Lean for enterprise architecture
  • 19:45 – Martin Fowler: “Software Design in the 21st Century”
  • 20:30 – Networking – drinks and food

Unfortunately, I missed about half of Wolf Schlegel’s talk on Continous Delivery, but judging on the second half, I would have preferred more in-depth discussion of technologies and best practices. The talk seemed like a space-station’s eye view of the topic.

Erik Dörnenburg was next talking about Lean Enterprise Architecture. I very much liked his analogy of comparing the role of a Software Architect to that of a Gardener instead of a traditional Architect. Spot on. Quite a few interesting thoughts on how to causing change in an organisation / team, too.

Martin Fowler gave two short talks, on on “Domain Specific Languages” and one on “Nondeterministic Tests“.

I was quite keen on the Domain Specific Language part, as we’re currently moving away from a “home-grown” Domain Specific Language for NC-code templating & output to a Python-based solution as we found that our own language lacked the expressiveness we are looking for. My key take-away was that there are two ways to create a DSL, external & internal and that we’re migrating from an external DSL to an internal DSL. Looks like the DSL book is supposed to be on my reading list real soon now.

Martin’s thoughts on “Nondeterministic Tests” were especially interesting as I was attending a talk on “Unit Testing & Concurrency” right last week in Karlsruhe. Very interesting to see the different takes on the topic – Abstracting away the concurrency altogether for unit testing purposes whereas Martin was leaning towards integration & acceptance testing and giving very sound advice on how to deal with concurrency issues within the tests (polling, callbacks, test doubles).

As you might have imagined, I mostly skipped the Networking part due to my sociophobia.

Overall, a very worthwhile evening and I very much look forward to future Thoughtworks events.