Interest payments on technical debt

All of our decisions when creating software have pros and cons. Solution A might solve the problem well but lack flexibility. Solution B might have loads of flexibility and solve the problem just as well but be difficult to understand. A third solution, C, might be flexible and intuitive but involve a large upfront cost.

I remember when I first started developing software, I'd be presented with a problem and then I'd work at it until I solved it and then move on. It was certainly a simpler time! The issue now is that I see so many different ways of solving a problem it can be almost impossible to choose which one to go with.

There are several common themes I think about when evaluating the options:

  • Simplicity
  • Flexibility
  • Testability

However, aside from the technical considerations there's also the business concerns:

  • Deadline
  • Severity
  • Budget
It's these concerns which generally lead to technical debt. It's a great metaphor. Just as financial debt has positives and negatives so to do our technical decisions.

For example, I need a car to get to work to earn money. My car breaks and I can't afford the repair. I borrow some money (acquiring financial debt) which allows me to continue getting to work to earn money (positive!). However, over time that debt will accumulate interest that I will have to pay off in addition to the capital I borrowed (negative). 

The same is true in software. I have a product that I sell for money. It has a bug which is driving customers away. I need to fix it ASAP and technical considerations go out of the window in order to do it quickly. I write messy code which fixes the problem (negative) but customers are happy (positive). However, at some point that messy code is certainly going to make life difficult for me when I have to make a change (negative) - that extra time is my interest payment.

Fear not! Not all financial debt has the same interest rate attached to it - for example, I could have paid for the car repair on a 0% interest rated credit card. As long as I pay the debt off before the end of the deal I haven't actually lost out.

Just as not all financial debt is bad (as in the 0% credit card) not all technical debt is damaging. The key is evaluating when it's low interest and when it's high interest.

I'll often incur as much technical debt as necessary for an urgent bug fix - the customer won't directly benefit from the code quality of the bug fix at that point in time. But! The key is to make paying off that debt as soon as reasonable possible a priority.

A very contrived example of a feature that introduces technical debt in a bug tracking application:

From:    CEO
Subject: URGENT: FEATURE REQUEST
Body: Prospect J Smith needs conditional formatting on bugs based on the amount of time it's open before they'll sign off on the payment. It should only happen for Smith as we may make it chargeable later. If the bug has been opened for more than a week it should turn yellow, then red if it's still open after a month.

In a small company with limited cash flow this is likely to be absolutely critical. Let's solve this quickly to get the payment and then refactor it later:

var bugBackgroundColour = "white";

// todo - refactor
if (currentCustomer.Id == 42) // John Smith
{
    var timeOpen = DateTime.UtcNow - bug.SubmittedDate;
    bugBackgroundColour = GetBackgroundColourForTimeOpen(timeOpen);
}

someControl.BackgroundColor = bugBackgroundColour;

Phew! Solved in less than 5 minutes and the cash rolls in.

We've incurred some debt here - we're tied to a specific customer id, the rules are hard coded and not discoverable - i.e. they're burrowed deep in the code base. In fact, it may be hard to even discover this code exists!

A couple weeks roll by and another customer wants the same thing. Easy enough:

var bugBackgroundColour = "white";
var customersWithConditionalFormatting = new[] {42, 51 };
if (customersWithConditionalFormatting.Contains(currentCustomer.Id))
{
    var timeOpen = DateTime.UtcNow - bug.SubmittedDate;
    bugBackgroundColour = GetBackgroundColourForTimeOpen(timeOpen);
}

someControl.BackgroundColor = bugBackgroundColour;

Hopefully it's clear that this debt has a low interest payment at this point. It's ugly and horrible but it works and we can keep adding customers in based on their id. This might be 'fine' for a long time but sooner or later it's going to hurt. (I'm not advocating doing this but am saying that staying in business at the expense of code quality is sometimes a necessity).

In this hypothetical situation it's a matter of time until each customer needs their own set of rules. At this point it would be madness to keep adding messy code, we need to refactor and introduce proper abstractions!

It's at this point, when we do what we should have done from the beginning in an ideal world, that we pay back our technical debt. I now have to write the code to allow users to have a collection of formatting rules as well as removing this code and creating the rules for all of the customers that have been using this horrid code. I've increased my amount of work in the long run but saw short term benefits.

Comments

Popular posts from this blog

Trimming strings in action parameters in ASP.Net Web API

Full text search in Entity Framework 6 using command interception

Composing Expressions in C#