Technical Debt

The notion of technical debt is not well understood, so let’s start there.

Agile is all about fast feedback loops—hours or, at most, a couple days. Deliberately lengthening your feedback loop in pursuit of the chimera of perfection destroys your agility. The cost of that delay is a real cost. It usually exceeds development costs by a large factor. Deliberately delaying a release as you pursue perfect knowledge is IMO irresponsible. It’s literally so expensive that it can destroy the company.

That’s where the notion of “Technical Debt” comes from.

We deliberately release code in order to learn…
Tech debt is based on the very Agile idea that it’s a good thing to get working code into the user’s hands to get feedback, essential in fact. We deliberately release minimally functional code—no bells and whistles—in order to learn because that’s the best way to learn. We know it doesn’t do everything. That’s okay. By definition, then, the code we release will be imperfect. Not buggy. Imperfect. There’s a difference. We know as a fact that some of what our code does will be wrong; we just don’t know exactly what will be wrong. That’s tech debt.

Paradoxically, trading perfection for fast feedback usually gets us closer to perfection (or, at least, very good) faster. By going into debt and then quickly paying that debt off by learning what’s wrong through feedback and then acting on that feedback, we get to a better place in less time.

Tech debt accrues naturally as you write your code. Managed correctly, it works like a credit card. You pay off the card every month. If you don’t do that, the debit increases to the point that you can’t pay it off. You are buried under the interest payments. In Agile, the equivalent of paying off your card is refactoring to incorporate the things you learned by releasing. When you see something that’s wrong based on what you know now, fix it. If you don’t “pay off the debt”—don’t eliminate the hard-to-work-on code that doesn’t do what our users need—you’ll be buried under the “interest.”

The key notion is: you learn as you work. You simply can’t know everything you need to know in advance.
The key notion is: you learn as you work. You simply can’t know everything you need to know in advance. Debt accrues because you don’t know things. It falls into the “seemed like a good idea at the time” category.

Once you learn, you pay off the debt. To quote Ward Cunningham, who invented the notion of technical debt, the team changed the code “so it looked like they knew what they were doing to begin with.”

Tech Debt does not stem from sloppiness or from a tolerance for bugs. You are delivering the best code that you can deliver, given what you know now. You are not deliberately ignoring things about how the code should work that you do know. The released code is (or, at least, should be) high quality, fully tested, zero-known-defect code. It’s wrong, though, because you don’t know something, and there’s no way to know exactly how it’s wrong. You don’t know what you don’t know. You learn what’s wrong by releasing and getting feedback, and by writing more code and building experience.

Let me repeat this because it’s important. There shouldn’t be any known bugs at release and you should fix other bugs the instant they appear. Tech debt is not sloppy, badly written code. There is never an excuse for that. It slows you down to the point that agility is impossible. You cannot move fast enough if you can’t trust your code. The notion that you have to write sloppy code to get it out the door faster is a costly myth (to borrow a phrase from Deming). A plethora of bugs is not “tech debt.” It’s incompetence. It destroys programmer effectiveness.

Also, not retiring your debt as soon as you can will eventually bury the company. Nokia died under the weight of its tech debt (a technical architecture that wouldn’t let their developers make changes fast enough). Tech debt leads to things like build times measured in days. Agility is not possible in that sort of environment.

So, it’s okay to deliver, knowing full well that you’ll learn over time, and that you will need to refactor the code to leverage the things you learn. That’s basic Agile thinking. Not refactoring—not paying off the debt—is an extreme form of dysfunction. It slows you down too much. That’s not Agile by any definition I know.

What about bugs? They are not tech debt, but the subject is obviously related. Bugs are code that doesn’t behave the way you expect, as compared to tech debt, where the code behaves exactly as you expect, but your expectations are incorrect.

It is technical debt to learn that you’re not using a newly-learned library the way it’s supposed to be used. That’s not a bug—the code works as you expect, just not as well as it could. That’s another sort of learning problem. Fix it like any other technical debt.

I’d strongly recommend learning more about tech debt by listening to Ward Cunningham, who invented the concept. Watch this video.


  1. Peter on December 16, 2019 at 11:04 am

    Can you give some examples of technical debt to sharpen your definition?

    • Allen Holub on December 16, 2019 at 5:17 pm

      Examples vary from trivial to huge. At the huge end, you may have an N-tier architecture that just doesn’t work in an Agile environment (google Conway’s Law) and the fix is going to a microservice architecture. At the smaller end, you may have gotten a detail of a story wrong, and when you sit down with your users to review the implementation, they either tell you or you see them struggle. Also included in the notion is something like code that works with a library to do something, and you’ve now learned that you’re not actually using the library properly and there’s a better way to do the same thing, so you refactor that code. It’s all about learning.

Leave a Comment