Friday, 23 October 2009

The “Unlegacy my Code” Kata

Daily TDD Kata

I’ve read a number of blog posts recommending doing a daily TDD ‘kata’ recently. For those unfamiliar with the concept, essentially you attempt to solve a simple programming task using TDD. The problems are often simple mathematical challenges, such as finding the prime factors of a number, or creating a calculator.

You limit yourself to 30 minutes to work on the problem. One of the goals of doing this is to speed up the way you work. For this reason, many people recommend doing the same kata many times, just like a musician would practice the same piece daily, gradually improving in speed, fluency and accuracy.

Benefits

There are several benefits to taking the time each day for a coding warm-up.

  • Learning the TDD way of working: red, green, refactor
  • Learning a unit testing or mocking framework
  • Stretching your brain to see if you can come up with an even more elegant solution than last time
  • Mouseless programming (learning to use keyboard shortcuts)
  • Solving a familiar problem in a new language
  • Learning how to apply a design pattern
A Possible Weakness?

While I think these benefits are great, I do think most of the kata examples I have seen suffer from a weakness. And that is that you are always testing something that is inherently easy to test. After all, what could be easier to write unit tests for than an Add method? This can mean that when you transition to attempting to write tests for your “real” code, you can fall at the first hurdle, as the “arrange” part of your test is horribly complicated, and you have no idea what to do for the “assert” part.

Introducing the “Unlegacy my code” Kata

Legacy code has been described as “code without tests”. Which means that unless your your development team is comprised of TDD champions, you likely have a lot of “legacy code”. Recently I decided I would try my own variation on a daily kata, that would go like this:

  1. Load up the source code of the application you are working on.
  2. Choose a class or method that is not covered by any existing unit tests (preferably something you are currently working on).
  3. Give yourself a maximum of 30 minutes to create a meaningful unit test.
  4. If it passes, check it in, and congratulations, you now have slightly less legacy code than before.
  5. If it fails, rollback and get on with your day’s work. Hopefully you learned something from the experience. You could write up a memo on what is wrong with the design of the class you tried to test. And you could always have another go at it tomorrow.
Problems you will run into

This kata will not necessarily be straightforward. Here’s the two main difficulties you will encounter:

1. Tight Coupling & Hidden Dependencies.

You may find that it is almost impossible to instantiate an instance of the class you want to test because of its dependencies (often hidden through the use of singletons). Sometimes your 30 minutes is up before you have even managed to successfully instantiate the class.

2. Multiple Responsibility Syndrome.

Classes that fail to adhere to the “Single Responsibility Principle” often fail spectacularly. They are responsible for everything from the printout of wage slips to the launching of nuclear warheads. They talk to the database, the file system, the network, the registry, and create a few background threads too. This means that they typically have dozens of dependencies unrelated to the behaviour you want to test. And when you call a single method you aren’t doing one thing, you are doing 100 additional things, one of which is bound to throw an exception. The best course of action is to extract a single, isolated responsibility and move it into its own testable class.

Give it a try

I’ve been doing this “unlegacy my code” kata for a couple of weeks now, and am (very) slowly seeing the unit test coverage rise. The fact that it is directly related to what you are working on also makes it much easier to justify the 30 minute daily investment to your manager.

2 comments:

Rob Cooper said...

Nice post - I too have been thinking of coming up with some Kata for daily practice. It seems like every time I feel like I make progress with TDD, I learn something new that makes me feel like a n00b again :)

I like the idea of the "unlegacy my code" most of my (and I expect most other developers) time is spent doing maintenance. I think you have accurately picked two of the worst problems with legacy code.

I would perhaps also suggest refactoring out code duplication. Often in (crappy) legacy code, other people have run into the same testability problems and rather than fix, they have just duped the code. As to how you would want to implement in a kata (e.g. code copied verbatim or very similar code) but I think it would be important to include in any code used as the "template" for the kata.

What are your thoughts on this? Any ideas on how you would like to see it in a kata (if at all)?

Unknown said...

hi Rob,

yes code duplication is a real issue in legacy systems. It is especially painful because the duplicates subtly diverge, leaving you with no idea which (if any) of the duplicates is "right".

But assuming they were genuine duplicates, extracting reusable class would be a very good exercise for a daily kata, and quite probably achievable in a 30 minute period.