Tag Archives: Refactoring

Growing Legacy Code, Guided by Tests

In our weekly practise session at work, I recently ran a hands-on session that I had first experienced at the London Software Craftsmanship Community on Baby Steps.  In a nutshell, the exercise is to work in really small (2 minute) pomodori, in which you pair to write a failing test and then try to make it pass.  If the test is green within the 2 minutes you can commit, if it is still red, then you have to roll back.  The idea behind the exercise is to improve TDD skills by trying to learn to work in smaller steps, encouraging the smallest amount of change to progress the implementation.  We chose to use the Tennis Kata as our problem to solve, which involves writing some code to score a single game of tennis.

The experience of the pairs started out much as you would expect.  They struggled to do something small enough for the first few pomodori, but after a while started to get into the right rhythm.  Having said that, the pairs all embraced the roll-backs with good humor and persevered to reduce the scope of what they were attempting until they were able to start to make regular progress.

We discussed afterwards for why the earlier pomodori resulted in so many roll-backs and a couple of the symptoms were:

  1. Lack of focus on the name of the test and consequent lack of direction in the 2 minute period.

  2. Writing too much infrastructure for the first test and its implementation.  Lots of setup, fields and supporting structure in your classes are not needed. The first test is difficult in that you have to start from nothing. You really need to focus on getting it written and passing, foregoing all other niceties, there isn’t time for anything else. This chimes with what Keith Braithwaite is getting at in his TDD as if you meant it, and gives the lowest barrier to getting the first test passing. This is also a good illustration of lean principles (but maybe that’s for a future blog).

These were all good lessons learned and, as expected, the number of roll-backs decreased as the session continued.

However, after a good number of commits, something else started to happen…

Though it was not mentioned at the start, the pairs took the occasional pomodoro to refactor. This was interesting as it indicated that tech debt had managed to build up in their implementations in a matter of minutes. It also made a clear illustration of how tech debt prevented progress on delivering the next piece of working functionality. No failing test had been written and made to go green within that 2 minute period. Clearly this is evidence as to why we should keep our production code as well factored as possible.

However, even with a few refactoring pomodori, the pairs started to get bogged down at around the point where the tennis game goes to Deuce.  Insufficient refactoring had meant that it had become difficult to make progress and so the pomodori started to return to roll-backs rather than commits.

At this point in might be worth commenting that I was expecting something of this ilk as it was rather like my experience when I originally attempted the exercise.  Though the process was intended to encourage the participants to try to work in smaller steps, it probably also encouraged less that ideal TDD style.  It’s all too easy to take the 2 minute pomodori as encouragement to work quickly, and committing on green took the focus away from the refactoring step of the TDD cycle: Red, Green, Refactor.

This was not, however, an entirely negative activity.  When the pairs had encountered the problem for long enough we stopped and discussed our experience.  It was clear that something was wrong and the pairs were feeling the pain.  It was good to recognise this, identify that the code was giving feedback, which was that it was pleading to be refactored.  Hopefully the experience will allow the pairs to be more sensitive to this feedback when working on production code.

In my experience, refactoring is often the neglected step in TDD.  When I first experimented with TDD I would often produce ‘legacy solutions’ that just added more and more conditional statements and state variables as the implementation progressed.  For me, this feel like Growing Legacy Code, Guided By Tests.

Traditional legacy code often comes about by the code being modified at different times (often by different people) and as time passes its quality decays and it becomes brittle and resistant to change.  This process of adding one layer then another and another, without ensuring that all the layers sit well together, is also known as code rot.  However, using TDD badly, we seem to be able to make code rot in a matter of minutes!  The accelerated decay process seems to work by rapidly applying this layering effect and ends up with a similar result.  For the inexperienced TDD practitioner, it’s all too easy to skip the refactoring step; the ‘high’ of seeing the green bar can make you think all is OK, when actually your work is not yet complete.

It takes great discipline and sensitivity to the code being written to ensure it is as well-factored as possible at all stages.  Though I am aware of this I still make mistakes and leave refactoring later than I should, I have been trying for some time to improve my TDD skills this way. I have found this exercise very helpful in clarifying some of this, and allowing me to share that knowledge with others.

As for the team, we are now re-implementing the Tennis Kata, without the 2-minute pomodoro constraint (but still working in baby steps) with the focus on refactoring and ensuring the implementation does not get out of hand.  The code we are writing is much cleaner and simpler and gives a high contrast to the code written first time.  We are already much happier with the results.