BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Technical Debt: A Repayment Plan

Technical Debt: A Repayment Plan

Bookmarks

What is Technical Debt?

Many teams struggle with technical debt, however, few teams actually devise a plan to get out from under it. To better understand how we can escape the debt we first have understand exactly what it is.

Technical debt is incurred by a team when they knowingly make a less than optimal technical decision in return for a short term gain in their project. For example, a team may decide to forgo writing as in-depth automated tests as they normally would for a tricky section of code in order to get a product to market sooner. Or, they may decide to build a project on an aging soon-to-be-deprecated framework rather than investing in purchasing an upgraded and better-supported version of that framework. Whatever the decision is, the key to recognizing true technical debt is that the team knowingly decides to incur long-term debt in favor of a short term gain.

This means that many things we commonly attribute to “technical debt” are not actually debt, at all. For example, normal bit rot that occurs as a system ages and a team fails to keep up with coding best practices is not debt. Or, a technical decision that a team willingly made and implemented that later turned out to be incorrect is not technical debt. In neither case did the team knowingly enter into a less-than-optimal long term decision in favor of a short term gain. This distinction is important because only after we’ve agreed on what exactly constitutes technical debt can we best decide how to eliminate it.

Its also important to consider the effect of debt we incur unintentionally in our codebase. However, since this debt wasn’t taken intentionally we’re unable to plan for how it will be addressed ahead of time. In these cases, we simply must prioritize and address this debt as we discover it…similar to how a team addresses newly discovered bugs.

A Financial Metaphor

We often compare technical debt to financial debt. But, is this a fair analogy? For example, would a bank actually lend us money without first establishing when and how it will be repaid? Likely not. Since we couldn’t actually borrow financial capital without first describing how it would be repaid then we shouldn’t treat technical capital in this way either.

The financial metaphor is actually a quite powerful one, so let’s take it to its full extent.

A Repayment Plan

Just like with financial debt, when taking on technical debt we need to establish two things: how it will be repaid and when it will be repaid.

How We’ll Repay It

Let’s take the case of the foregone automated tests that I mentioned above. If our team has willingly decided to forego writing automated tests for a tricky piece of code in order to get a feature into production sooner than we need to establish how we’ll correct that piece of debt. In this case, we’ll simply need to state that we’ll return to this piece of code in some point in the future and add the tests then. However, simply stating “we’ll add tests later” doesn’t do this problem justice. To help stakeholders fully appreciate the weight of our decision to incur technical debt we’ll need to specify, to the best of our abilities, exactly what the impact of waiting to add automated tests until later will be. For example, we’ll want to specify the sections of code that will need to have tests added to it. We’ll also need to call out that retrofitting automated tests on an already existing piece of code is always more difficult and expensive than simply adding the tests at the time of creation. This last point is important because it calls out that by deferring this work to a later time we’ll actually need to spend more money to do the work in the future then if we had we simply done it today. To put it another way...our debt accrues interest.

After discussing the options for repayment both a team and their stakeholders will likely realize that this problem goes deeper than simply whether or not they should write automated tests at the time the code is written. In fact, they may find that they have several options in between the two extremes that actually suit the overall project better. For example, they may decide that it makes the most sense to identify the most complex pieces of the new feature using a metric like Cyclomatic Complexity and immediately add test coverage to those areas while deferring the simpler areas for later. Or, they may decide that simpler but lower value types of automated testing such as unit tests can be added immediately but more difficult automated tests such as automated user acceptance tests will be deferred to a future sprint. Whatever the decision, the team and stakeholders would likely not have arrived at it had the discussion of technical debt not occurred in the first place.

When We’ll Repay It

In addition to specifying how we’ll repay the debt, we’ll also want specify by when we’ll repay it. Often times the sooner the debt will be repaid the better. For this reason it’s best to schedule the work to repay the debt at the time it’s incurred to better convey the impact of taking it on. For example, if you’re team is following a sprint-driven schedule then you may choose to schedule the work in the following sprint or, in the worst case, no more than a few sprints in the future.

Often time a team has the best intentions of repaying debt at the time its incurred but they just never seem to find the time to do so. Get your repayment deadline on the calendar when you take out your debt and stick to it.

What Happens If We Default?

The final piece of the puzzle for our financial metaphor is to capture what the result will be if we choose to default on our debt. In the financial sense, if I never repay my auto loan than the bank takes my car. The results of defaulting on our technical debt should be called out just as clearly.

Sticking with our automated tests example, if our team decides not to repay our technical debt than it will only become more difficult and more expensive to build new functionality on top of the existing untested functionality. We’ll likely see more bugs reported in production which means that our customers may have a diminished impression of the quality of our product. And we’ll be less able to rapidly respond to changes in the marketplace because a significant portion of our product will be either too difficult or too risky to change quickly.

Each of these points need to be made clear to our stakeholders to help stave off the temptation to simply default on our technical debt.

Dealing with Bit Rot

While all of our discussion so far has centered on planned technical debt that teams knowingly incur as part a normal project, we would be remiss if we did not discuss the unplanned technical debt that also plagues so many of our projects: bit rot.

As we’ve mentioned before bit rot differs from normal technical debt in the sense that as it’s not taken intentionally we can’t decide ahead of time how and when it should be paid back. However, just because we don’t know specifically what form bit rot will take on our project doesn’t mean that we can’t still plan for it.

Just as how we plan to pay back known technical debt we can also build into our project plan a buffer with which to address bit rot each sprint. Though the specific tasks that fill this buffer may not be known at the time, having the buffer there gives us a dedicated space with which we can payback those unplanned issues such as bugs, minor refactorings that must be handled immediately, or small pieces of system maintenance that make themselves known as our codebase naturally ages and decays.

But what about the larger issues that can’t be handled in a few hours of development time? Perhaps there are more systemic problems plaguing our system such as a failing infrastructure or aging architecture that no longer fits the shape of our business. While these issues are too large to be addressed easily we can use this buffer to identify and investigate these issues so we can give them the attention they truly deserve later in the project. For example, in the case of the failing infrastructure perhaps we identify the most common failing pieces of our infrastructure and add stories to our backlog to replace those pieces. We’ll then prioritize and schedule those stories alongside our normal development. Or, in the case of the aging architecture, we may spend time to determine the highest value changes that we can make to our architecture in-flight and then break those changes into stories that can be addressed piecewise over the coming sprints. Regardless of the problem, having the time to identify and plan for the issue means that it can be addressed just like any other technical problem.

A Budget

Now that we have a better understanding for the effects of incurring technical debt, how do we make sure it actually gets paid back? To get a feel for this we can expand our financial metaphor into yet another direction....budgeting.

Many of us draw a regular paycheck every few weeks. This pay check is a portion of our annual salary, distributed in even portions throughout the year. For example, if we draw an annual salary of $52,000 then we may receive that salary in $2,000 increments every two weeks...or 26 times per year.

However, while we are technically paid $2,000 dollars on each paycheck it’s quite unlikely that the full amount actually makes into our checking account. Instead, its more likely that only portion makes it to our checking account while other amounts are used either for long term investments or to pay down debt. For example, of our original $2,000 deposit our budgeted breakdown may actually look like this

  • $500 invested for the long term, such as contributed to our retirement account
  • $200 used to pay down short term debt, such as credit cards
  • $300 used to pay down long term debt, such as a mortgage or auto loan
  • $250 deducted directly to pay local or national taxes
  • $750 remaining and deposited into our checking account

Now, while no one is particularly thrilled about this arrangement few people question it. Rather, it’s simply the accepted as the norm. Since this arrangement is so widely accepted why not extend it to our project planning?

Imagine that we’re planning a sprint in story points and we’ve allotted 50 points to that sprint. While we’d like to spend all 50 points on new development it actually makes the most sense for us to budget some points to pay back our technical debt. For example, of our original 50 points we may decide to budget

  • 10 points to pay back technical debt
  • 5 points to ongoing codebase maintenance such as fixing bugs or addressing bit rot
  • 35 points for new development

Looking at our point budget we can see some obvious similarities to the financial budget we described above. Although we have 50 points to work with each sprint, not all of those points can be spent on new development. Rather, we must commit 10 of those points towards paying back our intentionally incurred technical debt just as we commit a portion of our paycheck to pay back both our long-term and short-term technical debt. In addition, we devote 5 points to simply keeping up with the ongoing maintenance of our codebase, just as we devote a portion of each paycheck to the taxes that help keep our communities running smoothly. The remaining points are ours to spend on any new development we like, just as the remaining dollars deposited into our checking account are ours to spend as we wish.

By budgeting our work in this manner we can ensure that we’re still moving the project forward without allowing it to crumble under the weight of our technical debt.

Of course, just like our personal budgets, this budget does have some leeway. For example, if we pay down our technical debt more quickly than expected then we’re left with more points to spend on new feature development. And, by the same token, if we find ourselves taking on a particularly high amount of technical debt then we may need to slow down new feature development a bit until its back to a more manageable amount.

Wrapping Up

By thinking of technical debt in terms of financial debt we can make more informed judgements as to when debt can be incurred for the betterment of our project. We can also better plan the impact of trying to pay the debt back as our project progresses.

And ≥by planning a regular budget for technical debt alongside our regular work we can better understand when our debt is manageable and when its becoming overwhelming.

About the Author

Jeremy Jarrell is a professional software developer and agile coach specializing in commercial application development for the private sector.  He is heavily involved in the local developer community, both as a highly rated speaker throughout the East Coast of the United States as well as a syndicated author whose articles and videos have appeared on sites such as Simple-Talk.com,DZone.com, Pluralsight.com, and ScrumAlliance.com. Jeremy loves to discuss all topics related to either software development or agile methodologies and can be reached by Twitter at @jeremyjarrell or at his website.

Rate this Article

Adoption
Style

Educational Content

BT