Technical debt: when to take it on and when not to
Technical debt isn't always bad. Like a loan, taken deliberately and with a repayment plan it can help a product move faster. How to tell good debt from bad, and how to pay it down without stopping delivery.
Technical debt is a term everyone uses and each person defines differently. For some, any code they dislike is technical debt. For others it is an excuse to rewrite everything.
A sharper definition: a future cost you accepted today in order to move faster.
The loan analogy
Technical debt works like a loan. A loan isn't bad in itself. If it buys something that creates value and you can make the payments, it was a good decision. It goes wrong in three ways:
- You don't know you borrowed.
- You have no plan to repay.
- The interest grows until it eats everything you earn.
In software, the interest is the gradual slowdown of every new change.
Two kinds of debt
Deliberate debt. You chose a simpler build to reach the market sooner, you know what you gave up, and you recorded it. For example: "reports are generated nightly for now, not live. If usage grows, we change that."
Accidental debt. It comes from carelessness, haste or missing design. Nobody decided anything; it just happened. This kind is dangerous because it stays invisible until it is expensive.
When taking on debt makes sense
- You don't yet know whether the product works. Spending weeks perfecting something that may be discarded is waste in its own right.
- The shortcut sits behind a proper boundary. If the simplified part can be replaced later without touching the rest, the debt is cheap.
- The deadline is real. Not imagined — an event or commitment that truly cannot move.
When not to borrow
Some debts carry very high interest and are almost never worth it:
- Security and user data. "We'll secure it later" means an incident is on its way. See security from day one.
- The core data model. Fixing data structures once real data has accumulated is painful and risky.
- System boundaries. Once modules tangle, separating them is a rewrite.
- No tests at all on critical logic. Without tests every later change is a gamble.
Write the debt down
Debt that isn't recorded becomes accidental debt. For each deliberate debt, record three things:
- What was simplified?
- What signal says it is time to fix it? For instance, "when concurrent users pass a given level."
- Roughly how much work is the fix?
The natural home for this is an architecture decision record.
Paying it down without stopping
A common mistake is asking for "two months to clear debt". That request is rarely granted, and when it is, the product stands still for two months.
A better approach:
- Fix along the way. Each time you work in an area, leave it a little cleaner.
- Reserve a fixed share. A set portion of each cycle goes to repayment.
- Pay the highest interest first. The part that changes most and slows you most comes first. Ugly code nobody touches can wait.
Signs the debt is out of control
- Estimates for simple work keep rising.
- Every change breaks something unrelated.
- People are afraid to touch parts of the code.
- New hires take months to become useful.
If you see these, debt has stopped being a technical topic. It is a business risk.
The takeaway
The goal isn't zero debt; it is known debt. Debt taken on deliberately, written down, with a clear trigger for repayment, is a tool for speed. Everything else is a cost growing quietly.
Related: swappable layers.