My friend wanted to do a TDD session with me.I have experience of using TDD on couple of projects in my previous company.But, since one year I have been doing freelance work,and have not yet got chance to do TDD on a live project.I have been working on a legacy project,to which we have added unit and integration tests.So, which example to do for the session? I decided to go for bowling kata.We used C# with MBUnit framework.
It took just 5 minutes to go through the rules,as my pair was already familiar with the Bowling game.So, how to go about writing the first test?.My friend,wanted to know how to go about writing tests – I told to him to think himself as the user of the API.How would he like to use the class library?.Write the test for the simplest behavior you can think of.
From Mike Bria,
Keep yourself focused on writing tests for the desired behavior of your objects, rather than for the methods they contain.
Our first test – ScoreShouldBeZeroWhenGameBegins.We did not had any design discussion before we started.Then,when we reached the point where we had to take a design decision for passing the test –ScoreShouldBe24_WhenSpareIsFollowedByRegularThrow.How do we implement the “determination and calculation of spare”? My pair suggested,having a Frame object.But,I felt we can achieve the desired behavior using the BowlingKata class.We implemented,and the test passed.But,the code looked a bit ugly.Then, the next testcase was ScoreShouldBe39_When2SparesAreFollowedByARegularThrow.This led to a long design discussion,and we ended up with a Frame class.
A good advice from James Shore,
Don’t let design discussions turn into long, drawn-out disagreements. Follow the ten-minute rule: if you disagree on a design direction for ten minutes, try one and see how it works in practice. If you have a particularly strong disagreement, split up and try both as spike solutions. Nothing clarifies a design issue like working code.
My friend wanted to know if, when we ended up creating Frame class,we have to write test for this class.I did not feel we needed to.When we are writing tests,usually a class does not exist in isolation.A class achieves its purpose by collaborating with other classes.And,here our tests were good enough.
We ended our session in about 1.30 hours(the kata was not completed).I committed the code to github.Then,I spent some time looking at design,and did some refactoring.
Using the idea of Michael Feathers’ Class Splitting,below is the diagram of 2 classes –
Interesting notes from the 2 diagram(and some additional information)
1) In the Frame class, all the methods just use the instance variables,whereas in BowlingKata class,some methods use each other
2) Good Command Query Separation – all the methods of Frame Class are query based,except PinsFallen.All methods of BowlingKata are Command based.
3) All methods in the Frame class are public\internal.The BowlingKata has some private methods too.
Our session was very much incremental design,as mentioned here by James Shore,
This takes place in three parts:
start by creating the simplest design that could possibly work,
incrementally add to it as the needs of the software evolve,
and continuously improve the design by reflecting on its strengths and weaknesses.
We followed the rhythm of TDD – fail the test,write just enough code to pass the test, and refactor. The code is here – http://github.com/vishalsodani/LearningTDD
Note:A friend of mine told me that only tests don’t lead to good design.You can have a class with many small methods and tested, but maybe taking on many responsibilities.The SOLID principles are good guide during the implementation.I agree with him.As soon as you feel that a class is doing too much,apply SRP.