Last week I was teaching TDD to two groups of programmers. And in the first group, someone asked me “Why do you always want me to write wrong code?

I was thinking to myself: “You are wrong, I do not want you to write wrong code, I want you to write the right code!” Fortunately, I did not say that out loud. Instead I asked: “I think I don’t understand what you mean. Can you explain it to me?”

Then the whole question turned into a long discussion with the whole group. And it turned out that this is a really good question and describes a problem that I had too, when I started with TDD. And the group was able to find the answer on their own, with very little input from myself.

It turned out, I had asked them to write “wrong” code…

One Hour Earlier

In the second lab, I asked the group to implement the rules for the game hangman - The children’s game where a player has to guess a secret word by guessing it’s letters. They would do so together (“mob programming”), and I would intervene every time when I thought they could improve something.

When the game starts up, it displays a hint before even asking the user to do anything. And at first, this hint only shows blank characters, one for each letter in the word. So, for the word “driven” it would show “_ _ _ _ _ _”.

The group already had the first test for this functionality, which looked like:

@Test
public void hintIsSingleUnderscoreForSingleLetterWord() {
    String secretWord = "a";
    Hangman hangman = new Hangman(secretWord);

    String hint = hangman.getHint();

    assertThat(hint).isEqualTo("_");
}

And now they were arguing what was the simplest solution to implement this. When they were about to implement their solution, I said “Stop. That’s too complicated. Why don’t you just return a single underscore?

The Wrong Code

So, the production code now looked like this:

public String getHint() {
    return "_";
}

To me, this looked perfectly fine. But to one attendee, it was “wrong code”.

It was wrong to him because he had to change it 5 minutes later. It was arguably not code that could stay like it was under any circumstances.

Yes, when you work like that, you do a lot of extra work in the production code. And in the end, most of it will be gone - it will have been deleted or changed. After you write this second test, you will change the return in the production code to something completely different:

@Test
public void hintIsThreeUnderscoresForThreeLetterWord() {
    String secretWord = "the";
    Hangman hangman = new Hangman(secretWord);

    String hint = hangman.getHint();

    assertThat(hint).isEqualTo("_ _ _");
}

Why do We Write Code Like That?

Just because you will have to change the code again does not mean that it is useless. Even though I understand that it might feel like that. It is not useless because…

You made progress on the API. Before this test, you had no production code at all. Now, you have decided that you want a method getHint that returns a string.

You are designing the API of the Hangman class as you go. And you use your tests to drive that design. Some tests, like the first, drive only higher-level design - You can implement the method with return "_";. Other tests, like the second one, drive the implementation.

You made progress in your tests. Before this return "_";, you had zero green tests. Now you have one. One green test that will be there until you are “finished” (if you ever are). A test where you have to be careful that it stays green.

After the second test, you have two tests for the same functionality - rendering the initial hint - but for slightly different aspects of it.

By re-doing your production code over and over again, you are making progress in your tests. Your test suite gets better and better. And this test suite is your protection against regressions when you are refactoring and your executable documentation. So, you want it to be good.

You made smaller steps than in test-after. Having those fine-grained tests is important for us. This way of working forces us to take smaller steps. That helps us to write only the code that is necessary, and to write all the tests that are necessary. When testing after the fact, you would maybe only write the second test, and that might miss a subtle but important detail that is in the code.

The Difficulty: Taking Smaller Steps

I think that the question “Why do you want me to write the wrong code?” is part of a larger problem that I always see in my TDD workshops. TDD, when done right, forces you to take really small steps. And that is very hard when you have never done it before.

And that is why we practice so much in my workshops. I can explain the basics of TDD in 10 minutes (Yes, there are some subtleties. I will explain them on day two). But you have to experience it and practice it - Otherwise you will not even know that you want to ask questions like this.

If you liked this blog, you might be interested in some of my other posts in the category “TDD”:

Do you have any questions? Just send me an email!