The Order of Tests
It’s been awhile since I’ve done much coding. That’s not my day job anymore, and I lose interest working by myself. In the past week, however, I’ve had a couple opportunities to mob program remotely with the Canton Coders. With the COVID-19 restrictions on gathering in person, people are much more likely to work with you virtually.
So last week I found myself mobbing on the Roman Numeral kata and today on the Zeckendorf kata, both on cyber-dojo. A lot of fun was had by all, and I rediscovered what I know about Test Driven Development with a bit more clarity.
Both of these katas involve converting base-10 numbers to some other representation. It’s a natural assumption to start with 1 and work your way upwards. This can make your work harder than it needs to be.
It becomes even harder if you start with an error condition. Looking for the Roman numeral equivalent of a
null did not help us move the code in the right direction. Handle the happy path first, to get the code designed for its utility, and then add the error conditions that make sense. We quickly decided it made more sense to use an integer parameter, which couldn’t be null, anyway.
Beyond that, ordering the test cases in numerical sequence of the calling parameter will ask you to take some bigger steps than is necessary. Bigger steps provide bigger windows for errors, and reduce your flow.
In the Roman Numeral kata, starting with inputs 1, 2, and 3 is OK. For 1, the simplest path to a green bar is to “
return 1.” The 2 case begs for an “
if” statement. The 3 strongly suggests refactoring to avoid a long list of “
if” statements. So far, so good.
The 4 case, however, takes a big leap. It introduces a new output symbol, “V,” and a new concept, out-of-order symbols to represent subtraction. That’s a lot to do all at once.
We skipped that for a moment, and did 5 and 6, first. The case of 6 develops the need to consume one character and then work on the next. Then we went back to 4. I think that was premature. We hadn’t yet developed looping on any symbol other than “I,” so generalizing that and using a table of symbols didn’t come naturally. In retrospect, I think it would be wiser to do 1, 2, 3, 5, 6, 10, 20 to advance the looping over one symbol to more than the “I” symbol. We might want to check things with something like 28, but that would drive the algorithm further. I’d rather continue with 4, 9, 14 to introduce the subtractive characteristic.
The key is to think about the next smallest step in developing the algorithm rather than the next smallest step in the input. Of course, if you get it wrong, things are not lost. It just takes a little longer.