Followup to Technical Debt as a tool

A few months ago, I posted an article on technical debt. Jeff asked for more detail on when I use larger amounts of technical debt. I’ll explain that in more detail here.

As I wrote yesterday, technical debt can be used as a tool to provide leverage. Our decision on when to use technical debt is a function with four variables:

  • The value of early feedback
  • The cost of debt
  • The cost of errors
  • The likelihood of errors

Our ideal situation for using technical debt is when there is high value to early feedback, the thing we are building is relatively isolated from the rest of the system (making the cost of our debt low), the cost of errors is low (due to a small number of users or this feature being ancillary to the main product) and this code isn’t likely to cause many errors. There are a few cases we’ve found that consistently fit these criteria.

Speculative Features

On some projects, we have an idea for a feature that we think will be valuable for users. In these cases, we’re willing to live with technical debt to get the feature in the hands of users. This allows me to get feedback more quickly and at a lower cost. If the feature works out, then it will make sense to pay back the debt. If not, we can just remove the code and not worry about the debt we created.

For example, on our internal invoicing system, I built a quick and dirty data extraction feature. When you upload a PDF of an invoice, the system will pull out key fields such as client name, due date and total amount due. These fields are then pre-populated in the payment system. I think this feature will simplify payment requests for users.

The description sounds nice, but it’s abstract. When I described that feature to our prospective customers, everybody said it useful. That’s a great start, but talk is cheap. I wanted to actually see if people actually used it. To get feedback, I created a very simple implementation that uses regular expressions and is tuned to my data. It isn’t expandable, it isn’t tested, and it isn’t modular. I’m okay with that. It’s purpose is to decide whether or not this is a profitable direction to head down. If it is, then I’ll go through the time to build it right. If not, I’ve only lost a few hours.

Entering New Markets

The other time I’m willing to take on large amounts of technical debt is when I’m working with a client who is entering a new market. We tend to work with startups who have non-technical founders. They have an idea for a web based products, but likely haven’t built one before. Our goal in the first round of development is to get something out there that helps them prove out their business model.

For these initial prototypes, we view them as learning models. We fully expect to evolve the product significantly over time and know that our first attempt likely won’t be the ideal long term solution. Because of this, we know that we are likely to throw away a large portion of the code, and with it the debt.

In general, I’m more interested in a quick and dirty solution to the right problem instead of a clean solution to the wrong problem.

Some Guideline

All of this isn’t to say you have a license to just hack things together. Taking on technical debt needs to be a conscious decision. As Kent Beck says:

When deciding to use technical debt we look at the above four variables. First, is there value to getting early feedback? If we’re building a feature we think users will value, we’re likely to consider taking on debt. If we know that it will be an important feature, than we get no value from the option to abandon our code. If we know a feature is valuable but there is uncertainty about the best implementation, we still might take on debt.

Next, we consider the cost of the debt. We’re unlikely to add a hack that requires touching large amounts of code. We prefer to keep our high debt code isolated. We also want to make sure we can easily remove the code if necessary. Something that requires a new database schema is unlikely to be worth taking on debt for.

Next, we look at how likely this code is to cause an error. If we’re looking at a feature like a product recommender, we could easily trap errors and recommend popular products. If the feature is very simple, we might be willing to take a risk on incomplete test coverage. If what we’re building is critical and complex with many real world edge cases, we’re less likely to take on debt.

Lastly, we want to look at the cost of the error. If we’re building a new payment processor or a realtime trading platform, we’re unlikely to want to take on debt. We’re also more likely to risk errors early in the life of a product when the customers tend to be those that get the most value. A site outage with 100 beta customers isn’t nearly as big a problem as it is when you’ve got 100,000 paying customers.

In summary, there are some cases where taking on larger amounts of technical debt can make sense. It’s important to understand the variables that go into the decision to not take unnecessary risks.

There are considerations beyond just the technical which I will look at in a future post.