Monday 19 August 2013

Legacy Code Retreat

I had the pleasure of attending a Legacy Code Retreat at the weekend organized by the Cambridge Software Craftsmanship group. Legacy code is a subject close to my heart. I've spent most of my working life immersed in it, and I'm been at least fairly successful is altering my point of view from "OMG THE CODE IS SHIT" to "what can I learn from this?".

The event was excellently co-facilitated by Alastair Smith and Erik Talboom and followed a familiar format of short sessions with tight constraints and retrospectives to discuss.

This was my first encounter of TDD as if you meant it which was certainly a challenging experience and one that I'll definitely try again.

I enjoyed the discipline of baby steps. We set a timer for a minute and either had to write a test, or perform a refactoring (but not both) within that minute. Failing to do that would reset the code and you'd start again. The object of this exercise was to judge the smallest steps you can work in. This is really interesting experiment to do; it forces you to think of your work as a series of smaller and smaller steps.

I also learnt the term "Golden Master", refering to a record of the working system. Working with Andrea, we were tasked with writing system level tests to capture the behaviour. We quickly hit upon the idea of simply capturing the entire output of the program as the simplest end-to-end test. This proved to be amazingly powerful; armed just with an end-to-end test we felt very confident about changing the code. We understood that the seeded randomness didn't cover every case, but we figured we could just capture more runs of the program to increase the confidence. Our simple measure of the confidence we had was that commenting out or changing a line of code in the program always seemed to result in that integration test failing.

The main take away for me was just that the discipline of focusing on a single thing is incredibly powerful. Instead of "fixing all the easy things", I'm going to try and take a step back and focus on something specific (be it renaming, simplifying conditionals, or just increasing test coverage).

Sunday 18 August 2013

Technical Debt and Legacy Code

It's time to ban the phrase "technical debt". It's a metaphor that's been stretched to mean too many things, from hand waving usages to make teams "go faster" to being a catch-all excuse for developers to write terrible code. I'd like to challenge you to avoid saying "technical debt" and instead try to define the actual problem. By stating the problem concretely, you're already closer to the solution.

Let's go right back to the beginning. Ward Cunningham introduced the metaphor of technical debt at OOPSLA 92 in "The Wycash Portfolio Management System" experience report. Let's look at what he says:

Another, more serious pitfall is the failure to consolidate. Although immature code may work fine and be completely acceptable to the customer, excess quantities will make a program unmasterable, leading to extreme specialization of programmers and finally an inflexible product. Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. Objects make the cost of this transaction tolerable. The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation, object- oriented or otherwise.

What Ward is saying here is that the build up of technical debt starts when you ship something with an incomplete understanding of the problem. It's the acknowledgement that we never ship the right thing first time. This isn't news to anyone! No matter what the customer says, the first time they get the new feature they want something slightly different. Technical debt starts to occur when you don't reflect that difference back to the underlying code.

The original definition of technical debt is nothing to do with quality of the code alone, it's simply an acknowledgement that once your code no longer models the problem, you're in trouble. Things aren't going to get better until you acknowledge that and fix things. I'm willing to bet that this definition of technical debt isn't the one you use.

Unfortunately, when I hear the term technical debt it's usually in the context of moaning about legacy code.

Most of us know what legacy code is. It's really hard to work with. It's difficult to like (though some might say there is Joy in Legacy Code), and progress is slow. Saying it's full of technical debt is almost certainly true, but it's not very helpful. You need to define that debt in meaningful ways so you can do something about it (or explain your woes concretely to the rest of the team so you can make time to tackle it as a team). In this context, technical debt is nothing but a lazy phrase to stop you concretely defining what the problems really are. As Bob Martin says "A Mess is Not Technical Debt" article.

Ever wonder why it's so hard to convince your boss to have time to tackle technical debt? You're fighting the wrong battle. You're describing the problem in terms of your domain, not the problem domain. What happens if you're not allowed to say "technical debt"? Now you're forced to describe the problem in concrete terms. How is the code mismatched against the customer requirements? Which one is the more compelling case to make to your boss?

So stop being lazy; define problems in concrete terms and don't use the dreaded phrase "technical debt".