Technical debt

On this page 7

Technical debt is the accumulated future cost of rework that a software system carries because of design, code, testing or infrastructure choices that were expedient at the time but are harder to change later. In software quality, it describes the gap between the system as it is and the system as it would need to be to absorb change cheaply and safely.

The metaphor borrows from finance on purpose. Taking a shortcut is like borrowing principal, and every later change that becomes slower or riskier because of that shortcut is an interest payment. Debt is not automatically a mistake; it becomes a problem when it is invisible, unmanaged or allowed to grow faster than the team repays it.

How technical debt accumulates

Technical debt accumulates whenever the cost of changing the system rises faster than the value of the features being added. The cause can be a deliberate trade-off, such as skipping an abstraction to meet a release date, or simple drift, as requirements evolve and the original design no longer fits.

A widely used framing is the technical debt quadrant, which sorts debt by two questions: was it taken on deliberately or inadvertently, and was the decision prudent or reckless. The quadrant matters because each kind calls for a different response.

KindTypical thought behind itAppropriate response
Deliberate and prudentShip now and refactor after launchRecord it and schedule repayment
Deliberate and recklessThere is no time for designStop the practice, then repay
Inadvertent and prudentNow the better design is clearRefactor as part of normal work
Inadvertent and recklessThe team did not know betterTraining, reviews and standards
The four kinds of technical debt

Debt also grows without any decision at all. Dependency aging, where libraries and frameworks fall behind supported versions, and knowledge loss, where the people who understood a module leave, both raise the interest rate on code that nobody has touched.

Forms of technical debt

Technical debt takes several distinct forms, and naming the form is the first step toward measuring it. Code debt is the most visible, but architecture and test debt usually carry the highest interest because they affect every future change.

FormExampleTypical symptom
Code debtDuplicated logic, very long functionsThe same bug fixed in several places
Architecture debtTightly coupled modules, no clear boundariesSmall changes ripple across the system
Test debtMissing or flaky automated testsFrequent regressions, fear of refactoring
Dependency debtOutdated libraries or runtimesSecurity patches cannot be applied
Infrastructure debtManual deployments, snowflake serversSlow, error-prone releases
Documentation debtUndocumented decisions and interfacesLong onboarding, repeated questions
Common forms and their symptoms

Measuring and making debt visible

Technical debt cannot be measured directly, so teams rely on proxies that together indicate where interest is being paid. No single metric is reliable on its own; the value lies in trends over time and in combining signals.

Static analysis tools estimate remediation effort from rule violations, cyclomatic complexity and duplication. These estimates are useful for spotting hotspots but say nothing about business impact. Delivery metrics such as lead time for changes and change failure rate show the interest actually paid. Defect data matters as well: a steady stream of bug reports and regression findings in the same modules points to debt more reliably than any code score.

IndicatorWhat it revealsLimitation
Code complexity and duplicationHard-to-change hotspotsIgnores how often the code changes
Change frequency of complex filesWhere interest is paid most oftenNeeds version-control history
Regression rate per moduleFragile areas lacking testsDepends on consistent defect tracking
Lead time for changesOverall drag on deliveryAlso affected by process and staffing
Dependency ageUpgrade and security exposureSays little about internal design
Indicators of technical debt

The most effective visibility tool is often a simple debt register: a list of known items with the affected area, the estimated cost of repayment and the observed cost of leaving it. This turns a vague complaint into a prioritizable backlog item.

Strategies for paying down technical debt

Paying down technical debt works best as a continuous activity rather than a one-off cleanup project. Large rewrites promise to clear all debt at once but carry high risk, because they reproduce old behavior while the existing system keeps changing.

StrategyHow it worksWhen it fits
Boy scout ruleLeave touched code slightly cleanerSteady, low-level code debt
Capacity allocationReserve a fixed share of each iterationPersistent debt across the product
Strangler fig patternReplace a legacy part piece by pieceArchitecture debt in large systems
Targeted refactoringFix hotspots with the highest interestA few modules cause most problems
Full rewriteRebuild the component from scratchOnly when the platform itself is obsolete
Repayment strategies and when they fit

Many teams reserve roughly 10 to 20 percent of capacity for maintenance and debt work, although the right share depends on product age and risk. The key principle is to repay where change happens: debt in code that is never modified costs little interest and may never need repayment.

Misconceptions and pitfalls

Technical debt is frequently misused as a catch-all label for anything engineers dislike. Precision in the term keeps the conversation useful for both engineers and decision-makers.

  • Debt is not the same as a bug. A defect is incorrect behavior; debt is a structure that makes future changes costly even when behavior is correct.
  • Not all debt must be repaid. Code scheduled for retirement or rarely modified can carry debt indefinitely at low cost.
  • Zero debt is not a goal. Some debt is the price of learning quickly and reaching users early.
  • Unrecorded debt is the real danger. Shortcuts that nobody documents compound silently until a release slips or an outage reveals them.
  • Rewrites often recreate debt. Without changes to practices, a new codebase accumulates the same problems.

Stripped to the essentials

Technical debt is what happens when software is built the quick way instead of the sturdy way. The quick way gets something working sooner, but it leaves behind work that will have to be done later, usually at a higher price.

It resembles a house where the owner keeps adding rooms without fixing the foundation. Each new room is possible, yet each one takes longer and becomes riskier to build. Sooner or later, the owner must fix the foundation or stop adding rooms.

Where it is applied

An online retailer built its checkout as a single module during a rushed launch. Three years later, adding a new payment method takes about six weeks instead of one, and every release of the checkout produces regressions in tax calculation, which customers report through the support desk.

The engineering lead records the problem in the debt register, measures the regression rate and lead time for checkout changes, and agrees with product management to allocate 15 percent of each sprint to repayment. The team adds automated tests around tax logic, then extracts payment handling behind a clear interface using the strangler fig approach. Within two quarters, the next payment method ships in eight working days and checkout regressions largely disappear.