Special thanks to Dan Pasette for his insights into how an engineering team like 10gen’s manages technical debt in their issue tracker.
If you work on software, you most likely use a bug tracker to track defects, manage development tasks, and plan releases. The collection of tickets, open and closed, is a data set that doubles as a repository of institutional memory about your software: what components have been the most complex (i.e., have spawned the most bugs)? Who worked on what, when? What issues did the developers grapple with over the course of delivering on a requirement or resolving a defect? What compromises did the team decide to make (or, worse, what were they forced to make) to hit a deadline? What’s never been fixed, left to fester in a dark corner?
You may have other documentation sources for your software: end-user docs, developer handoff docs, long and tortuous email chains, wiki pages, and inline documentation in the code base itself. But, if consistently used, a bug tracker can show the underbelly of the development process in remarkable detail. It is here where teams can probe their work history to uncover decisions and issues that we can categorize as technical debt. (Example: Open the longest-active project in your issue tracker, and find the oldest unresolved bug. Behold.)
And once we have classified bugs as technical debt, that can be its own component—a component we should consider as first-class, along with mission-critical and user-facing components. Unlike other components, which must be maintained and improved, technical debt must be managed. It is an emergent component that we should assume will always be present in a system.
This kind of emergent debt is what happens when we gain insight into the longstanding problems in a system, when we start to trace one problem back to a past decision, well-considered or otherwise. We can find the areas where we have built workarounds over the compromise and complexity we originally injected into the system.
And the status of these issues as bugs means that we have already filtered out most non-harmful technical debt (I am squarely in the “not all technical debt is bad” camp): if the team implemented a shortcut that never caused or registered as a problem, it’s not in the bug tracker to begin with.
Just as importantly, in some situations we can choose to split these bugs into actionable sub-tickets, and cast off the rest. If, for instance, an old bug has to do with a component that has architectural flaws, but which is used more and more rarely, we can choose just to address the surface problems, knowing that the underlying debt in this instance will get zeroed out when we finally sunset this component completely (this must be a real plan, of course, such as a replatforming project in the not-too-distant future). So we break out the surface problems into discrete bugs, and then we can close the hairy old bug and pat ourselves on the back.
For example: an e-commerce system has a year-old bug on the books concerning user feedback in the checkout flow. The underlying problem has to do with the poor integration of the payment gateway. You, the tech lead, are fresh from a meeting where the business owners agreed to a payment processor with a much cleaner integration. The transition is a few months away still, but all the bug-spawning cruft of the old integration is now scheduled to disappear. You can now split this bug into some constituent sub-bugs that make cosmetic changes sufficient to address the symptoms of the original bug report. You can also close out the year-old bug with references to the cosmetic bugs and the impending payment system change. Were a new payment system not in the works, this band-aid approach might seem an irresponsible way to manage the technical debt underlying the original bug; in the new reality, though, you’ve decided to acquire short-term debt that has a definite lifespan.
(Side note: this example highlights the breakdown in the strict financial debt analogy. Technical debt can, in some cases, just magically disappear. Don’t try this with your credit card.)
We can also use the bug tracker explicitly to expose and track technical debt as we take it on or discover it in a system. This is especially useful when a developer needs to surface and memorialize decisions, shortcuts, quandaries, and TODOs in order to implement a feature. Being able to enter bugs related to the development process, and to categorize them as debt and not feature bugs, allows the developer to stay focused on the implementation, while making the process more transparent and contributing to institutional memory.
I’ll explain by example. Let’s posit a developer: Cold cup of coffee perched dangerously on the edge of the desk, sitting back in an office chair, wearing overpriced headphones, perhaps sweating a bit, wrestling with the latest in a series of hairy performance problems near the end of a development cycle. The task at hand is to deal with a slow page load. In the process of tracing the execution chain, the developer runs into a run-on sentence of a method that cries out for refactoring. It’s also probable that some of this logic will be useful elsewhere, once it’s extracted from the monolithic method. It’s also clear, however, that this method is not impacting load time—for the purposes of the task at hand, it’s more of an itch to scratch.
Thanks to the GTD methodology, we know how to deal with these itches. The answer is not to lose focus on the task at hand, but rather to record the unrelated task and file it in a place where we can address it later. To do this, we need a simple filing method that allows us to categorize the new task efficiently, so that task creation is not itself a distracting activity.
Clearly, our developer needs to get this into the bug tracker. It takes thirty seconds to create a task called “Refactor Ai_Checkout_Helper::doThings().” The tech lead should provide a single, simple tag (or label, depending on your issue tracker’s terminology) for these debt-repaying tasks: shouldfix, refactor, or technicaldebt will work. The goal is to create a two-step method for recording technical debt-related bugs that developers find in the course of doing other work:
1. Enter minimal notes, including file and line reference.
2. Label as technical debt.
It would be fun to monitor activity logged against this label in the heat of a project (e.g., an RSS feed attached to the label), as you’d have an equivalent of the fantastic “WTFs per minute” quantification of technical debt.