Technical debt is the future cost created by building software the quick way instead of the durable way. Like financial debt it carries interest: every later change takes longer. Pay it down when it slows work you do often, causes repeated failures, or blocks something the business needs. Leave it alone where code rarely changes.
We once ran a tool that assembled court filings from case data. Type a client name, choose a motion, download a formatted document. It worked. It also depended on five outside services to do it.
Leaning on outside services is a sensible way to get a tool working. It is also a debt: five things that could change or go down without asking us. When we built CaseCobra, our practice management product, we rebuilt that tool as a native part of it. The motion engine there leans on no outside services.
That is technical debt and its repayment, in one small story. The rest of this post is how to recognize it and when repaying it is worth the money.
What is technical debt?
Technical debt is the accumulated cost of shortcuts in software: decisions that made something faster to build and harder to change later. It is not the same as bugs. Software with technical debt can work correctly today. The cost appears when you try to modify, extend, or repair it.
The financial comparison is useful. Borrowing lets you have something now and pay later, with interest. A shortcut lets you ship now, and the interest is the extra time every future change takes because of it.
Like financial debt, it is not inherently bad. Borrowing to launch sooner and learn whether anyone wants the product is often the right call. The trouble comes from debt nobody chose and nobody is tracking.
Where does technical debt come from?
Technical debt comes from deliberate shortcuts taken to meet a deadline, from early decisions that stopped fitting as the product grew, from dependencies on outside services and libraries that age, and from knowledge that was never written down. Only the first is a choice. The others accumulate on their own.
| Source | Example | Avoidable? |
|---|---|---|
| Deliberate shortcut | Hard-coding a value to launch on time | Yes, and sometimes worth it |
| Outgrown design | A structure built for one location, now serving twenty | Partly |
| Dependencies | An outside service or plugin that changes or is retired | No, only managed |
| Missing tests | Changes cannot be verified without checking everything by hand | Yes |
| Lost knowledge | Nobody remembers why a rule exists | Yes, by writing it down |
The Motion Generator was mostly the third kind. Outside services are a fast way to get capability you have not built. Each one is also something you do not control.
What are the signs of too much technical debt?
The clearest sign of too much technical debt is that small changes take a long time. When a request that sounds simple gets an estimate that sounds large, and the explanation involves other parts of the system, the software is charging interest.
- Simple changes take disproportionately long.
- Fixing one thing breaks another.
- The same kind of failure keeps recurring.
- Only one person understands a part of the system, and everyone avoids touching it.
- Developers are reluctant to change anything without extensive manual checking.
- Outages are caused by things you do not control, such as an outside service or an unmaintained plugin.
- Updates are overdue because applying them might break something.
- A new developer needs a long time before they can safely contribute.
The fifth sign usually means tests are missing. A project with automated checks can change with confidence. Our post on how software is tested before launch explains why.
When should you pay technical debt down?
Pay technical debt down when its interest exceeds the cost of fixing it. In practice that means when it slows down work you do frequently, when it causes failures customers notice, when it creates a security risk, or when it stands between you and something the business needs.
The reverse is just as true and more often ignored. Debt in code that works and rarely changes costs almost nothing. An awkward old script that runs once a month without incident does not need improving. Cleaning it up is spending money to feel better.
A practical approach is to pay as you go. When a feature requires touching a messy area, tidy that area as part of the work. The cleanup is then attached to something the business wanted, and effort goes where the software is actively changing.
When is a rewrite justified?
A rewrite is justified when the existing design cannot support what the business now needs, when the software is being absorbed into a larger system anyway, or when its foundations are no longer maintained. It is not justified merely because the code is unpleasant to read.
Rewrites are risky. The old system contains years of small corrections, each one a lesson about a real case. A rewrite discards them unless someone carries them across deliberately. Until the replacement matches the original, you are paying for two systems.
Our rebuild of the motion tool met the second condition. CaseCobra already held the cases, clients, and calendar. A separate app pulling case data from elsewhere and leaning on five outside services made less sense once the data was in the same product. Rebuilt as a native feature, the engine now produces 37 Arizona criminal document types with the caption, parties, and judge already filled in, and five outside services were retired.
It also helped that the original had already proved the idea. It worked well enough to be worth rebuilding. Rewriting something whose value is established is a much safer bet than rewriting on a hunch.
How do you keep technical debt under control?
Keep technical debt under control by making it visible. Record shortcuts when they are taken, keep dependencies few and up to date, maintain automated tests, and set aside regular time for upkeep. The aim is debt that was chosen and is known, not zero debt.
- Write shortcuts down at the moment they are taken, with the reason.
- Count your dependencies. Each outside service is a recurring cost and a point of failure. This is a large part of the build vs buy decision.
- Keep things updated in small steps. Small frequent updates are less painful than rare large ones.
- Budget for maintenance. See what website maintenance includes.
Frequently asked questions
Is technical debt the developer's fault?
Not necessarily. Much of it comes from reasonable decisions made with the information available, or from the business changing after the software was built. What a developer does owe you is honesty about shortcuts as they are taken.
Can technical debt be avoided completely?
No. Requirements change, and the tools software depends on keep moving. Software with no debt at all has probably been over-engineered for needs that never arrived, which is its own kind of waste.
How do I know if my software has technical debt if I cannot read code?
Watch the symptoms. Compare how long changes take now with how long similar changes took a year ago, and note how often a fix causes a new problem. You can also ask a second developer for an independent review.
What is refactoring?
Refactoring is restructuring existing code without changing what it does. It is how debt is usually repaid: in small, safe steps, checked by tests, alongside normal work.
Is old software the same as bad software?
No. Age alone is not a defect. Software that works and rarely needs changing can stay as it is.
If changes to your software have become slow or risky, tell us what you are seeing and we will give you a straight opinion.