tdd

TDD process when you know the implementation of a new feature overlaps a previous one


I just solved this puzzle using TDD: https://adventofcode.com/2015/day/6

I started with turnOn function and implemented like this(F#):

let turnOn (startx, starty) (endx, endy) (grid: bool[,]) =
    for x in startx..endx do
        for y in starty..endy do
            grid.[x, y] <- true

Then I started implementing the turnOff. I added the first test for it:

[<Fact>]
let ``can turn off a light`` () =
    let grid = Array2D.create 1000 1000 true

    do grid |> LightsController.turnOff (0, 0) (0, 0)

    grid
    |> Array2D.iteri (fun x y status ->
        let expected = not (x = 0 && y = 0)

        Assert.Equal(expected, status))

it forced me to define the turnOff function.

let turnOff (startx, starty) (endx, endy) (grid: bool[,]) = grid.[0, 0] <- false

and then the next test:

[<Fact>]
let ``can turn off another light`` () =
    let grid = Array2D.create 1000 1000 true

    do grid |> LightsController.turnOff (1, 1) (1, 1)

    grid
    |> Array2D.iteri (fun x y status ->
        let expected = not (x = 1 && y = 1)

        Assert.Equal(expected, status))

at this point I see two options:

  1. follow the normal TDD way and write tests one by one and evolve the production code until it just looks like the turnOn function, then refactor the two functions and extract the core algorithm

  2. copy the turnOn code into the turnOff function and modify the related part (grid.[x, y] <- true) (because it is obvious that the two share the same algorithm) then copy all tests of turnOn for turnOff as well to make sure it works as expected. then refactor the two and extract the core algorithm

I prefer the second option because it's a lot faster and doesn't make me reinvent the wheel. but I feel something is wrong with copying and pasting!

please let me know what do you think about this situation?


Solution

  • I prefer the second option because it's a lot faster. but I feel something is wrong in it! please let me know what do you think about this situation?

    Very close.

    The copy paste of the code you already have is fine; especially when that's the fastest way (measured in wall clock time) to get from RED state to GREEN state.

    BUT...

    then copy all tests of turnOn for turnOff as well to make sure it works as expected. then refactor the two and extract the core algorithm

    This is probably backwards. Cleaning up the duplication you introduced to pass the test should normally happen before you add more tests.

    Quick green excuses all sins. But only for a moment.... Now that the system is behaving..., remove the duplication that you have introduced. -- Kent Beck, Test Driven Development by Example.

    The ideal that we are striving for is that we should have clean code that works before we introduce a new test.