Tuesday, December 18, 2007

What's the APR on your technical debt?

Today we're going to discuss technical debt--what it is, what its impact is, and what to do about it.

One of the key tenets of scrum and other agile development methodologies is the idea of producing production-ready increments of work at the end of each iteration. Ken Schwaber calls this "sashimi" in the scrum framework--a slice of product. You may have also heard scrum practioners talk about the definition of "done", i.e. what steps have to be completed before we can consider a user story satisfactorily completed, which may include steps like:

  • code written!
  • unit tests written and passing, with a certain degree of code coverage
  • automated acceptance tests written and passing
  • code refactored
  • code documented/commented (e.g. javadoc)
  • product owner signoff
  • documentation updated (e.g. UML diagrams)
  • etc.

In general, the notion is that the definition of "done" should capture the degree of code quality the team and product owner mutually agree to.

Now, anyone who has tried to do this has probably run into this (as we have): a sprint gets started, and at some point through the sprint, you realize that you're not going to be able to finish all the user stories you signed up for by the end of the sprint. Or at least not get them all the way "done". So, you yield to the temptation and cut corners, just doing the implementation without all the rest of the supporting infrastructure, so that at the sprint review you can call this done. Oooh, it's so tempting! C'mon, the product owner isn't going to look at your CruiseControl outputs....

But now, what you've done is that you've incurred technical debt. All that code doesn't have automated test coverage or adequate documentation, and probably has more complexity than it needs because you didn't get a chance to clean it up and refactor it. Now it's going to be harder for someone else to work on it (including you, two months down the line!), because it's inadequately documented and complex, and it's even hard to refactor it without introducing bugs because you don't have the automated tests to help you know if you covered everything! Thus, future work on this codebase gets bogged down a little bit by all this cruft.

Now, technical debt works just like credit card debt: if you keep racking it up, it really starts to kill you. Because you are now working slower, you again find yourself behind the 8-ball of not being able to finish everything by the end of the sprint, and you rack up even more technical debt. Our product owner recently commented to me that he felt like we were getting less done than we used to at the beginning of the project with fewer people, and I'm starting to think it's all this accrued technical debt.

Unfortunately, getting out of technical debt is pretty similar to credit card debt, and is also probably psychologically just as hard. The first step is cut up the credit cards -- refuse to accrue any more technical debt from this time forward, and instead only demo things at the review that are really fully "done", even if this means you don't get to everything you thought you would. This takes a certain degree of courage, and is probably something to do right after a major release, rather than just in front of one....

Then, start paying down the debt. There are a number of ways of measuring this debt, many of them easily automated with Maven, such as:

  • Cobertura - unit test code coverage measurement
  • PMD - static analysis to identify unclean code patterns, including code complexity and design issues
  • Javadoc output - how many of your packages are missing documentation? how many classes don't have class documentation, and how many of the public/protected methods are missing javadocs? Do you have any javadoc warnings?

So the point is, you can measure all of these things, and come up with some numerical measure (pick some formula you like) of your technical debt. Furthermore, if you are tracking the user story velocities of your teams, you can actually start correlating your technical debt measurements at the beginning of a sprint with the story point velocity output by that sprint. In fact, you may even be able to figure out exactly how much drag your technical debt is putting on development, which means, based on your average cost for developer time, you can actually put a dollar amount on it. You can actually tell how much interest you're paying on your technical debt in real dollars.

Then see how the conversation with your product owner goes when you ask for some technical debt paydown to get prioritized on the product backlog....