Thursday, May 20, 2010

Kata One: Red, Green, Refactor (or Next Test) in JavaScript

This is the first in a series of code katas prepared for an internal code dojo I host for the ASP.NET QA team. I share it hoping that others will practice it, and then share their own experiences in the comments. What's a code kata? I'll let Dave Thomas, who coined the term, explain its meaning.

As requested, I will target client-side JavaScript for our first few code katas, so that jQuery (or another JavaScript framework) may be used. While such a target is somewhat limiting, you can easily adapt this kata to other languages, frameworks, or environments.

The Preparation

Choose a JavaScript unit testing framework to use for this kata, such as jQuery's QUnit. Have the editor and browser of your choice ready to program client-side (i.e., browser-based) JavaScript.

The Form

Implement a JavaScript function that ordinalizes a number using test-driven development (TDD). Ordinalizing a number means converting it to its ordinal equivalent; e.g., 1 to 1st, 11 to 11th, 42 to 42nd. The function's specification and algorithm is less important than strictly adhering to the red, green, refactor (or next test)  continuous cycle of TDD. That cycle is:
  1. Write a failing test that specifies a single behavior of the unit you are developing.
  2. Write only enough code in the unit your are developing to make the test pass. Then ensure that all other tests still pass, as well.
  3. Examine all of the unit's code thus far written. Can it be improved? If so, make a single improvement and then run all of your tests again. Continue making improvements, one at a time, until you see no more need for improvement.
  4. Repeat the above steps for the unit's next behavior, starting with a new, failing test.
When I first started practicing TDD, I struggled to determine what tests to write first, or even at all. If you are struggling as I did, I suggest starting with these three tests:
  1. It will ordinalize 1 to 1st
  2. It will ordinalize 11 to 11th
  3. It will throw if the number argument is null
Keep adding tests, one at at time. The kata is complete when you feel you have completely specified (designed) the ordinalize function via unit tests, and all of those unit tests pass.

The Focus

In my early TDD days, I also struggled to write only enough code to satisfy the current unit test. For instance, imagine I am writing the code to make test #3 above pass. All that is required is: if (num === null) { throw "Number is null!"; }. But I can anticipate that, for instance, an array or string should throw an error, as well. So I'm tempted to write: if (typeof(num) !== 'number') { throw "num is not a number!"; }. This would make test #3 pass, but it might come at the expense of writing the other tests. And maybe I'm adding behaviors I won't actually need. (Of course, there comes a time where some generalization and anticipation makes sense, and learning when and how best to generalize is one aspect of mastering TDD.)

As you practice this kata's form, focus on writing only enough code to make the current unit test pass. Make the smallest change that makes sense. Also focus on completely specifying the ordinalize function's behavior. The first time I practiced this kata I ended with 7 tests; the last time, 18; and, the highest, nearly 30 (which I felt was over-specifying.) Find what works for you, keeping your focus on the quality of the behaviors, and be open to experimenting from repetition to repetition.

Repeating the Kata

Repeat this kata 3-5 times each time you practice it.

I suggest that you delete all the code you write, both the unit tests the ordinalize function, between each repetition of this kata. I know the temptation to save your work for reference is strong, but you'll benefit more from focusing on the form and the action of the kata, not the product. It's also much easier to walk a new road when the old road is out of sight, and one of the reasons we repeat katas is to vary the form (within its boundaries).

Deleting the code between repetitions doesn't mean you can't take notes. In fact, I've found that taking notes during the kata can be helpful (albeit sometimes distracting), and after finishing a kata, I usually examine the product after a 5-minute water-cooler break, noting what I liked, what I disliked, and what things I want to consider for future repetitions. Then, I issue the cleansing Cmd+A, Del.

Here are some other ideas to consider when repeating this kata:
  • Consider adding a time limit to a repetition, such as 10 or 15 minutes
  • Change the function to test, keeping the keen focus on the TDD cycle; for instance, instead of an ordinalize function, try an email validator (sans regular expression), a color name to hex converter that uses shortcuts (e.g., red to #f00), or a function that calculates the date of Easter using a Computus such as the Golden Number; try to choose something you could TDD in 15 minutes
  • Compare your unit tests with another programmer's before you delete the code; how do your tests compare? What can you learn from the differences? What can you learn from their unit tests?
  • Pair with another programmer, alternating who writes the test and who writes the code to make it pass; how do the unit tests produced while pairing differ from those produced alone?
  • Use a different unit testing framework, or perhaps a BDD framework; how do your tests differ? How was the experience different?
  • Don't use a unit test framework at all; this means you'll have to develop a way to run tests, define tests, and report the results; how does this experience compare to using a test framework? Do your tests look different?
Cheers,
Drew (twitter.com/anglicangeek)

If you practice this kata, please share your experience in the comments.

No comments:

Post a Comment