Wednesday, May 14, 2008
« How to Implement Software Security on an... | Main | Threat Modeling 101 - How to Create a Th... »
Definition: Technical Debt is a term that we in the Agile world use to describe things in the code that perhaps aren't engineered as well as they could (should) be. It can refer to many things, like areas in the code that we should probably refactor to make them more readable, poorly performing code, obsolete or clunky architecture, encapsulation abstraction, or other class problems, or the like. It's debt because we know about it, we "owe" it to be done, but are focusing on other things instead.

Technical debt is the avoidance of doing work that we would otherwise do in the course of doing our best practices in engineering. It's a fact of life that most every Agile team has to deal with, in my experience. I find that there are various means of "dealing with" technical debt, some of which I will discuss below as a matter of practicality. However, I see it really as a symptom of a deeper problem. The team isn't finding good engineering as valuable as completing stories could be the underlying problem.

Teams can be pressured to deliver more than they should (this is common), and as such, could be focused on delivering the current sprint's stories rather than fixing things they find that are not as they should be. The team also could be creating more technical debt for itself by not focusing on good engineering in the first place. When junior people design things, sometimes they don't address all the points of performance and code maintainability. Trade-offs are made that can end up causing lots of rework later.

The concept of Agile software development, is heavily based on refactoring. Sometimes I find that teams use refactoring with a little "r" when they should be Refactoring. They make small internal changes, but are reluctant to change overall design, even when it is truly warranted. When we add a new feature, sometimes the design needs to change to accommodate it. THIS IS EXPECTED behavior in an Agile development process. Yet, time after time I hear developers say "well, I don't want to change all that NOW..." when that's really exactly what they should be doing. The concept of iterative development should be allowing us to ship software at the end of every cycle, and we really can't consider the software shippable if it has these poor designs still left over from earlier days.

Refactoring the design shouldn't be catastrophic though. But, there is always some impact that is almost always fundamentally left out when planning. Imagine we have an apple, and we need to add some cherries to it in this sprint. We might just smash the cherries on the outside of it, and call it good. But that would leave us a lumpy ugly mess... Rather, we might take another approach, and put the apple and the cherries all in a blender, and pour the mix into a new shape mold and freeze it. The new shape will be smooth and round, yet it will encompass the new features of having both apple and cherry flavors. It's a dumb example, but you get the idea. Refactoring can take many forms.

Handling Technical Debt
Now, I have been on a few Agile teams and I am a realist. Technical debt is most certainly here to stay. We just aren't in an ideal world, and we can't always take the time we really need to make sure that the iteration's deliverable is as pristine as it should be. So, now how can we handle this debt in a practical way?

Here are some ways I have seen teams deal with Technical Debt:
  1. Ignore it.
    1. This don't work so good, in my opinion, but yes I have actually seen it done. It works, so we'll use it as-is.
  2. TODO it.
    1. //TODO in the code is a flag that there is something more that needs attention. Also, //FIXFIX and //BUGBUG are others I have seen. Some of the tools give us mechanisms to flag these as work items, but in my practical experience this is just about the same as #1. Nobody ever gets back to these things to fix them. They just lose visibility and get buried. Not very effective in my book.
  3. Backlog it.
    1. Create a backlog item called Technical Debt. Each instance where something needs attention is recorded as a task for this story. They can be estimated, and prioritized. Backlog items have visibility, so they don't get lost. Here is the problem - Technical debt now CAN be prioritized. And, it usually is - right to the bottom of the list. This really doesn't solve the issue either, unless you have a product owner who is savvy enough to know that good engineering means happier customers, developer, and management in the long run.
  4. Bug it.
    1. Log a bug for each Technical Debt item discovered. This is probably the most effective means I have yet seen for the actual reduction or elimination of technical debt. In reality, I think this is the most appropriate. The new story requires changes that just haven't been made. It's not really "done" until this is taken care of. Ongoing maintenance of code should have an appropriate stakeholder with a voice in the Product Owner's scope of attention.
  5. Job-Jar it.
    1. Put it into the bucket of things that need to be done but aren't on either the sprint or product backlogs. I think this is marginally effective, because nobody should technically ever have time to get to this stuff, they really should be pulling things off the product backlog onto the sprint backlog. But, I thought I'd mention this concept since someone brought it up.
Are there other ways to deal with Technical Debt? What ways have you had success? Please leave me a comment and let me know.
bugs | scrum