← Glossary

Software architecture

Technical debt

Technical debt is the future cost of rework a team takes on when it chooses a quick solution now instead of a better one that would have taken longer.

The technical debt quadrant as a two by two grid of reckless or prudent against deliberate or inadvertent, with a quote and two concrete examples in each cell
The technical debt quadrant. Each cell has the sentence a team says when it takes on that kind of debt, and two examples of what it looks like in a codebase.

Teams talk about technical debt because it explains a feeling every engineer has had: the system works, but every change takes longer than it should. Naming the debt, sorting it by kind and measuring its cost turns that feeling into a list of things to fix, in an order someone can defend.

Why does technical debt matter?

  • It compounds. Each shortcut makes the next change harder and the next shortcut more likely.
  • It is invisible from outside. The product looks fine while delivery slows. By the time stakeholders notice, the debt is large.
  • It decides what is possible. Past a certain level, features that would take a week on a clean system take a quarter, and some are quietly dropped.

What are the types of technical debt?

The diagram at the top of this page is Martin Fowler’s technical debt quadrant. It sorts debt by whether the team knew it was taking it on and whether it was a reasonable choice at the time.

  • Reckless and deliberate. “We do not have time for design.” The team knows better and skips it anyway: copy-pasting a checkout module to hit a launch date and never merging it back.
  • Prudent and deliberate. “Ship now, fix the data model next quarter.” A considered trade with the repayment tracked: hard-coded tax rates with a ticket and an owner, or one region until a customer needs a second.
  • Reckless and inadvertent. “What is layering?” The team did not know a better way existed. Database calls scattered through the UI, or a cron job nobody can explain.
  • Prudent and inadvertent. “Now we know how we should have done it.” The best decision available at the time, overtaken by what the team learned: service boundaries that fit the business of two years ago.

Debt also sorts by where it lives, which decides who can fix it.

TypeWhat it looks likeWho feels it
Code debtDuplication, long functions, missing tests, dead codeThe engineer changing that file
Architecture debtWrong service boundaries, a shared database, a framework the system has outgrownEvery team, on every feature
Test debtSlow, flaky or missing testsReviewers and whoever is on call
Documentation debtDiagrams and docs that describe a system that no longer existsNew engineers and anyone in an incident

How does architecture debt differ from code debt?

Code debt is local. It lives in a file or a module, one engineer can see it and a refactoring pull request can fix it in a day. Architecture debt is structural. A shared database between two services, a monolith that three teams coordinate releases around or a call chain that fails as a unit cannot be fixed inside one pull request. It shows up as slow delivery across teams rather than as ugly code, which makes it harder to see and more expensive.

The fix is also different. Code debt is paid by refactoring. Architecture debt is paid by changing the system architecture, usually by moving to a different architecture pattern one capability at a time, as described in building new systems alongside legacy systems. That takes a solution architecture, a plan and a budget, so it needs a business case.

How do you measure and track technical debt?

  • Track it as work. Every known item of debt gets a ticket with a label, a cost to fix and a note on what it slows down. Debt that is not in the backlog does not exist to anyone outside the team.
  • Measure the interest. Lead time for changes, change failure rate and bug fixes by module all rise where the debt is. Sorting incidents by component finds the architecture debt.
  • Use static analysis for code debt. Complexity, duplication and coverage tools give a number per module and nothing about architecture.
  • Draw the system. An architecture diagram of the current state, not the intended one, is often the first time anyone sees the shared database. A C4 model container diagram is the right level, and a dependency graph does the same for packages.
  • Record the deliberate debt. When a design review approves a shortcut, write an architecture decision record saying what was skipped, why and when it will be revisited.

How do you make the case to pay it down?

Stakeholders fund outcomes. Tie each repayment to one.

  1. Pick debt on the path of planned work. The shared database the next three features all touch, not the ugliest file.
  2. Quantify the interest. “Features in the billing module take three times as long as elsewhere, and half our incidents start there.”
  3. Estimate the principal. The cost to fix, as a range, with the risks.
  4. Name the payoff. Which planned features get cheaper, which incidents stop happening, what it unlocks.
  5. Propose a sequence. A system design for the target state and steps that each deliver something, so the work can pause without being wasted.
  6. Report back. When the repayment lands, show the before and after numbers. That funds the next one.

What are common technical debt mistakes?

  • Calling everything debt. Code the author dislikes is not debt. Debt has a nameable cost to future change.
  • The big rewrite. Replacing the system wholesale pauses delivery for a year and usually recreates the same debt in a new language.
  • No record of deliberate debt. Prudent debt with no ticket and no owner turns into reckless debt when the team changes.
  • Fixing code debt while ignoring architecture debt. Tidy modules inside the wrong service boundaries still take a quarter to change.

What tools help with technical debt?

  • Static analysis and code quality tools. They measure complexity, duplication and test coverage per module over time, which covers code debt well and architecture debt not at all.
  • Diagram-as-code tools. Keeping the architecture diagram as text next to the code means it gets updated with the system, so documentation debt stops accruing. See diagram as code.
  • AI diagramming tools. Tools like Eraser turn a codebase or infrastructure configuration into an architecture diagram of the system as it actually is, which is the quickest way to put architecture debt in front of the people who can fund fixing it.

For more on this kind of diagram, see architecture diagrams.

Frequently asked questions

  • Who coined the term technical debt?

    Ward Cunningham, in 1992, to explain to non-technical stakeholders why shipping quickly and then revising the code was reasonable, as long as the revision happened. Like financial debt, the interest is the extra effort every later change costs until the principal is repaid. Martin Fowler added the quadrant.

  • Is all technical debt bad?

    No. Prudent, deliberate debt is a tool: shipping a simpler version now to learn whether a feature matters, with a plan to replace it, is often the right call. Debt is a problem when it is taken on unknowingly, when the repayment never gets funded or when the interest is paid by a team that did not take the loan.

  • What is the difference between technical debt and a bug?

    A bug is behavior that is wrong today. Technical debt is a design or implementation that works today but makes future change slower or riskier. Debt produces bugs, since code that is hard to change is easy to break, which is why bug rates by module are a useful signal of where the debt is.

  • How much time should a team spend on technical debt?

    Many teams reserve 10 to 20 percent of each cycle, but a fixed share treats all debt as equal. A better rule is to pay down the debt on the path of planned work, so each repayment makes a specific upcoming feature cheaper, and to schedule the rest as projects with a business case.

Map the system you have before you decide what to fix.