Monday, January 31, 2011

Transforming the Bowling Kata Part 1

Recently Uncle Bob blogged on what he is calling The Transformation Priority Premise. The idea he is exploring, as I understand it, is that certain code changes should have a higher priority than others so as not to lead you to impasses or large code changes in your TDD cycles.

In this series of posts I'm going give Uncle Bob's ideas a shot on the bowling kata. For those not familiar with the kata it calls for scoring ten-pin bowling. Now Bob's premise calls for us to select tests that prefer changes higher on his list of transformations. The highest ranked transformation is
{} -> nil

for which we can write the following test

Given a gutter ball on the first bowl
When scoring
Then the total score is zero


[TestFixture()]

public class given_a_gutter_ball_on_the_first_bowl

    : ContextSpecification

{               

    [TestCase(0, 0, TestName = "then the score is zero")]

    public void when_scoring(int Bowl, int ExpectedTotal)

    {           

        var Game = new BowlingGame();

 

        Game.Bowl(Bowl);

 

        Assert.AreEqual(ExpectedTotal, Game.Score());

    }

}



I believe this is the simplest test that I can write for the transformation. However there is a more complex test that I could have written. The scoring of an an entire game of gutter balls. Now I immediately wonder, "Which test should I implement?" For the sake of exploring the premise I'll select the more complex of the two.

[TestFixture()]

public class given_a_game_of_gutter_balls

    : ContextSpecification

{               

    [TestCase(new[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0,

    TestName = "then the score is zero")]

    public void when_scoring(int[] Bowls, int ExpectedTotal)

    {           

        var Game = new BowlingGame();

 

        foreach (var Bowl in Bowls)

        {

            Game.Bowl(Bowl);   

        }

 

        Assert.AreEqual(ExpectedTotal, Game.Score());

    }

}



The {] -> nil transformation will cause a failing test and the
nil -> constant transformation will get us a passing test. Now for the implementation, which, no surprise, is simple.

public class BowlingGame

{

    public void Bowl(int Pins)

    {

 

    }

 

    public int Score()

    {

        return 0;

    }

}



I don't see anymore tests that can employ the {} -> nil transormation nor the nil -> constant transformation, but I can however select a test for the constant -> variable tranformation which is
Given one bowl that knocked down five pins
When scoring
Then the total score should be five


[TestFixture()]

public class given_one_bowl_that_knocked_down_five_pins

    : ContextSpecification

{

    [TestCase(5, 5,

    TestName = "then the score is five")]

    public void when_scoring(int Bowl, int ExpectedTotal)

    {

        var Game = new BowlingGame();

 

        Game.Bowl(Bowl);

 

        Assert.AreEqual(ExpectedTotal, Game.Score());

    }

}


In this case I see only one kind of test that is selected by the highest ranked transformation I think I can apply. The resulting implementation is

    public class BowlingGame

    {

        private int PinsKnockedDown;

 

        public void Bowl(int Pins)

        {

            PinsKnockedDown = Pins;

        }

 

        public int Score()

        {

            return PinsKnockedDown;

        }       

    }



After having only two tests and performing three transformations. I have a couple of observations and questions,

1. A given transformation could have multiple tests you could write. Which test does one select?

2. If I understand the premise correctly transformations are used as a basis for selecting the next failing test. In Uncle Bob's example he uses {} -> nil transformation to get a test to fail. Is this in the spirit of premise? Once a test has been selected writing the appropriate code to get it to fail seems like an orthogonal issue. If that's true then perhaps adding {} -> constant transformation is appropriate.

3. Interestingly the second test required not only a change in the BowlingGame.Score() method, but a parallel change in BowlingGame.Bowl(). Are these parallel transformations predictable in situations where the command-query seperation principle is being applied?


4. In order to apply the premise it appears we must be able to identify tests that require transformations that have a higher priority. Does this contradict one of the intents of TDD? That is to let the tests drive the code. Are we really thinking about design when we apply this premise?

5. Are all impasses a result of problems with test selection? What kinds of impasses are signs of conceptual modeling problems? Can TDD coding impasses even be interpreted in a way that can detect modeling issues?

In part 2, I'll move forward with the kata and hopefully come closer to answering some of these questions.

1 comment:

Rick said...

Hi Aeden,

I just read Uncle Bob's post and I had a question, but then after I posted I realized his post was already a year old, so it might not get answered. Yours is newer, so perhaps we can continue the discussion.

I am looking to understand (constant->constant+). It seems whenever he refers to (constant->constant+) in the article, he is talking about the TEST, moving to the next test employs (constant->constant+). Then the code uses another transformation to make the new test pass. It seems to me (constant->constant+) is not a code transformation, but rather a test transformation. Am I off base here?

Thanks
-- Rick