November 26, 2009

FizzBuzz Java TDD Example Feedback

Just got a free moment before Zebedee tells me it's "time for bed" to post some feedback on my TDD illustration/example audition in Java/Eclipse:

I watched your presentation at http://www.parlezuml.com/tutorials/agilejava/fizzbuzz/fizzbuzz.html and here are some things that I found interesting about your style of TDD:

- The couple of mistakes you made (breaking test, infinite loop, 99 being Buzz) were useful to show how TDD finds problems, whether you made those mistakes deliberately or not. Having such things deliberately in a real presentation can be useful.

- It was refreshing to see the numberIsDivisibleBy method, because some time ago at StackOverflow I had done exactly the same and many people commented against it. :) See http://stackoverflow.com/questions/1060366/how-long-should-it-take-a-senior-developer-to-solve-fizzbuzz-during-an-interview/1060857#1060857 In my case, the code smell which triggered that refactoring was the additional parantheses in "if (number % (3 * 5) == 0)".

- I would not have created the *OneHundred method, since the parameterized method already expresses the intent and reads the same.

- Your style of writing tests is what I call "tests as examples" (or xUnit style). In order for somebody to find out what your FizzBuzz program does by reading the tests, he will need to read all the tests and reverse-engineer that why both 3 and 6 return Fizz (it becomes like an IQ test). The tests do not directly say that multiples of 3 will be Fizz.

The style of writing tests that I use, is what I call "tests as specification" (or BDD style). By reading just the names of the tests, it should be possible to understand the logic of the component under test. Even if somebody would give you only the test names ("the specification"), you could write the necessary test and implementation code and get the same result.

See the above StackOverflow link for how I named the tests for FizzBuzz. (Also I use underscores in the tests names for readability, as mentioned at http://www.infoq.com/presentations/10-Ways-to-Better-Code-Neal-Ford) For a non-trivial example of how I organize my tests, see http://github.com/orfjackal/tdd-tetris-tutorial (the "beyond" branch contains the most complete code).

-- Esko Luontola
www.orfjackal.net


Esko makes an interesting point about Behaviour-driven Development vs. vanilla TDD. The missing link here is triangulation. Namely that you may use more than one example to lead you towards a generalisation of a single behaviour. If you have more than one test for the same behaviour, you need a way to distinguish them in the test names.

You can also get into difficulties describing complex scenarios in abstract terms. I have some prior form in this, since I've applied formal specification techniques where we try to do exactly that. But people tend to understand things better from the bottom up, by wrapping their minds around a range of concrete examples, from which they can build a more abstract and sophisticated mental model.

Catalysis demonstrates this principle very powerfully in the modeling/UML world by using instance diagrams and filmstrips to explore examples before generalising to class models and the like.

Having done TDD and BDD, I have some personal insights into what works best for me. There's no right or wrong here. If you deliver better code and find BDD-style tests easier to follow, then fill your boots.





Posted 5 years, 4 months ago on November 26, 2009