Technical debt rarely arrives as a dramatic failure. It appears when a small change takes three days, a deployment needs one particular person or everybody agrees not to touch the reporting module before Friday. The useful question is not whether the codebase contains debt. It is which debt is charging the business the most interest and what should be done about it.
01
The small change that opened a large problem
Imagine an established service business with an internal customer portal. Operations asks for one extra approval status so managers can distinguish work waiting for evidence from work waiting for a decision.
The request sounds like a field, a filter and a label. The developer discovers three different status lists, an old report that reads the database directly, email rules that depend on the wording and no automated tests around approval permissions. A change estimated in hours becomes several days of investigation, manual checking and cautious release planning.
The extra time is not really the cost of the new status. It is interest on earlier decisions. Some were sensible when the portal was smaller. Some were shortcuts. Some appeared because the business and technology changed. Together, they make today's useful work slower and less predictable.
That is the point at which technical debt stops being an internal code complaint and becomes a business planning problem.
02
Technical debt is the cost carried into the next change
The financial debt metaphor is useful because it separates the original borrowing from the ongoing cost.
A team may take a shortcut to launch a pilot, meet a fixed deadline or learn whether customers need a feature. That shortcut is the principal. Every later hour spent working around it, investigating it or recovering from it is the interest.
Technical debt is broader than untidy code. It can sit in the application architecture, data model, tests, infrastructure, deployment route, documentation, security controls or delivery process. Anything that makes a reasonable future change slower, riskier or harder to understand can create debt.
The debt is not measured by how offended a developer feels when opening a file. It matters when it creates a real cost, constraint or risk for the service.
03
Old software is not automatically technical debt
A ten-year-old module that performs one stable job, has useful tests and rarely needs changing may be less expensive than a new module that changes every week without clear boundaries.
Age can increase risk when frameworks, operating systems or dependencies leave support. It can also make skills harder to find. Those are evidence of a problem, not proof that every old line needs rewriting.
The same is true of code style. A function can be unfashionable and still be clear, dependable and cheap to maintain. Cleaning it may improve consistency, but that does not automatically make it the most valuable work on the roadmap.
Start with the effect on change, operation and risk. Then inspect the technical cause. This prevents a technical debt programme becoming an expensive campaign to make the codebase look nicer without improving the business.
04
Debt hides in more places than source code
The portal's duplicated status lists are code and data debt. The missing approval tests are testing debt. The report that reads internal tables directly is architecture debt because it turns a database change into a reporting change. The release checklist stored in one person's notes is deployment and documentation debt.
Other common forms include unsupported frameworks, manual server configuration, hard-coded credentials, unreliable backups, missing audit records, fragile integrations, unclear ownership and an onboarding process that takes a developer two days to reproduce.
Zendesk's current explanation groups technical debt across architecture, infrastructure and DevOps, code, process, security, defects and documentation. The categories are useful for finding debt, but they should not become seven disconnected backlogs. One operational problem often crosses several of them.
For the approval status, the business needs one joined view of the change. Splitting it into code, data, testing and reporting tickets may help delivery, but the reason for doing the work remains the same: this part of the portal makes routine workflow changes slow and risky.
05
Look for interest payments in normal delivery
Technical debt often reveals itself before a code analysis tool finds it.
Listen for phrases such as:
- only one person understands this area;
- we need to test everything when this changes;
- the estimate depends on what we find;
- the deployment is manual but it normally works;
- we cannot update that library because another component depends on it;
- we fixed the same type of bug last month;
- nobody knows whether this report is still used.
Delivery data can add evidence. Compare how long similar changes take in different parts of the application. Look at defects reopened after release, failed deployments, repeated incidents, time spent preparing development environments and work delayed by an integration or approval bottleneck.
No single measure proves technical debt. A complicated feature may simply be complicated. Patterns matter. If small changes in one area repeatedly require more investigation, review and recovery work than similar changes elsewhere, that area is paying interest.
06
Create a debt register people can use
A backlog item called refactor portal is too vague to fund and too large to finish.
Record each meaningful debt item with enough context to support a decision:
- Where is the problem?
- What behaviour or delivery symptom reveals it?
- Which users, services or business processes are affected?
- What evidence shows the current cost or risk?
- What future work is likely to touch it?
- What are the repair options?
- What could go wrong during the repair?
- Who owns the next decision?
The portal item could say that approval status logic exists in three places, every status change requires manual checking across workflow, email and reports, and two planned features need another status. The first repair option is to centralise the rules behind one application service and add tests around current behaviour.
That description gives product and engineering people something concrete to compare with other work. It also stops the debt disappearing when the developer who found it moves to another task.
07
Prioritise the interest, not the ugliness
The cost of removing technical debt is similar to paying the principal. The reason to pay it is the interest avoided afterwards.
A useful priority test considers four things:
- Frequency: How often does the team work in this area?
- Friction: How much extra time or uncertainty does the debt add?
- Exposure: What customer, operational, security or compliance harm could occur?
- Timing: Is planned work about to increase the cost or create a safe opportunity to repair it?
The duplicated status logic scores highly because the team expects more workflow changes and every change touches customer communication and management reporting. A badly named internal class in a stable export tool may score much lower, even if a code quality tool dislikes it.
This is why technical debt should not be prioritised only by estimated repair effort or a generic severity score. A small debt item in a busy, sensitive workflow can cost more than a large awkward module nobody needs to change.
08
Security debt may need to jump the queue
Some debt creates a business choice. Some removes the luxury of waiting.
Unsupported software, known exploited vulnerabilities, weak authentication and exposed credentials need a risk decision based on the service and its exposure. The National Cyber Security Centre advises organisations to track vulnerabilities, prioritise them in context and make the remaining risk visible to senior leaders. It also warns that unsupported products may contain weaknesses that will no longer be patched.
That does not mean every available update should be pushed into production without testing. It means the decision to delay an important update must have an owner, a reason, a temporary mitigation where possible and a route away from the unsupported position.
Keep security debt visible in the same operational conversation, but do not let a normal feature priority quietly overrule a risk the business has never assessed.
09
Deliberate debt needs an expiry condition
Technical debt is not always the result of carelessness. A controlled trial may use a manual import because automating it would cost more than the business should spend before demand is proven. That can be a responsible choice.
The decision becomes dangerous when temporary has no meaning. Record why the shortcut is acceptable, what it affects, who owns it and what event should trigger another decision.
An expiry condition is more useful than a hopeful date. For example: replace the manual import before the service processes 500 records a week, before a second customer uses it or before the source system removes the current export. The condition connects repayment to the reason the shortcut stops being sensible.
Martin Fowler's technical debt quadrant distinguishes deliberate from accidental debt and prudent choices from reckless ones. The important lesson is not to debate which box makes somebody look better. It is to expose what the team knew, why the choice made sense and how the consequences will be managed.
10
Repay debt while changing the affected area
The safest time to improve part of a system is often when the team already needs to understand and test it.
For the new approval status, the developer can first add tests that capture the current permission and notification behaviour. The status rules can then move behind one clear boundary. The feature is added through that boundary and the report receives a supported data source instead of reaching into internal tables.
This approach is sometimes called the boy scout rule: leave the area a little cleaner than you found it. The useful part is the limited scope. The team improves the code needed for the current outcome without turning one status request into an unbounded portal rewrite.
Not every debt item fits inside feature work. A framework upgrade, database change or deployment rebuild may need focused planning. Even then, connecting the work to upcoming changes makes its value easier to explain.
11
Use focused remediation when the debt blocks several plans
A dedicated improvement phase earns its cost when one constraint affects several important outcomes.
Suppose the portal runs on an unsupported framework, the test suite cannot run on a current language version and the hosting environment cannot receive security updates without breaking the application. Several feature requests now depend on the same foundation.
Treating each request as a separate workaround will add more debt. A focused stabilisation or upgrade phase can become the smaller business decision. Define the supported target, important behaviour that must remain, migration steps, recovery route and point at which feature delivery can resume.
Keep the phase narrow enough to verify. A title such as modernise platform is still too broad. Move the portal to a supported runtime, restore the automated test pipeline and document deployment is a result the business can inspect.
12
A full rewrite is a last option, not a cleaning strategy
Once a team can name many debt items, starting again can feel attractive. A new codebase contains none of the old mess because it contains very little at all.
The existing system also contains years of business rules, exceptions and operational knowledge. Some will be documented. Much of it will be hidden in behaviour users rely on. A rewrite must rediscover that value while the old application continues to run.
Choose replacement when the current platform cannot support an important business need, the technology or operating model creates unacceptable risk, and gradual improvement cannot provide a responsible route. Otherwise, local repairs, a strangler approach or replacing one bounded area may deliver value sooner with less disruption.
The decision should compare lifetime cost, migration, dual running, data, support and recovery. It should not be a vote on whether developers enjoy the current code.
13
Stop new debt becoming invisible
Paying down old debt will not help for long if new compromises enter the system without a record.
Code review and automated checks can prevent some accidental debt. Clear architecture boundaries, supported dependencies, useful tests and repeatable deployments reduce the number of surprises. A definition of done can include the documentation, monitoring or migration work needed to operate a change safely.
The team still needs permission to make trade-offs. A rule that no debt may ever be introduced usually pushes the real decisions underground. Make the compromise visible in the pull request or backlog, explain the business reason and give it an owner and expiry condition.
Microsoft's current operational guidance recommends tracking technical debt alongside feature work and addressing it at a regular cadence. That works because debt becomes ordinary product work rather than a separate engineering wish list that is easy to postpone.
14
Explain debt through the decision it affects
Directors do not need a lecture about cyclomatic complexity before approving an improvement. They need to understand what the current constraint does to delivery, service risk and future options.
Instead of saying the approval module is tightly coupled, explain that changing one workflow status requires edits in three places and manual checking of customer emails and reports. Two planned features need the same area, so centralising the rules now should reduce the cost and risk of both.
Include the choice. The business can repair the area before the features, accept slower delivery for both or change the feature plan. A good technical explanation makes those options and their consequences visible without pretending the estimate is certain.
Technical debt becomes fundable when it is connected to work the business values and risk the business recognises.
15
Measure the result in delivery, not tidiness
The debt item is not complete because a refactoring ticket moved to done.
Return to the evidence that justified it. Did status changes become easier to estimate? Can the automated tests confirm permissions and notifications? Does the report use the supported route? Can another developer make a change without finding three versions of the rule?
Code quality measures can help locate complexity, duplication or missing coverage. They should support the decision rather than become the outcome. A perfect score in an isolated tool does not prove that the portal is easier to change or safer to operate.
The clearest success measure is often boring: the next useful change passes through the area with less investigation, less repeated work and a more predictable release.
16
Manage the debt that changes the business outcome
The new approval status did not need a complete portal rewrite. It needed the team to recognise why a small request had become expensive, make the relevant debt visible and repair the boundary that several future changes would use.
That is the practical job of technical debt management. Find where the business keeps paying interest. Record the evidence and owner. Prioritise frequency, friction, exposure and timing. Repair the debt beside useful work when possible, and fund a focused improvement when one constraint blocks several plans.
The aim is not a permanently perfect codebase. It is software the business can still understand, support and change without every sensible request reopening the same old problem.
If routine changes keep producing surprising estimates or fragile releases, I can help review the application, connect the technical constraints to the business roadmap and define a controlled first improvement.
Useful questions
Technical debt review checklist
- Which small changes repeatedly take longer than expected?
- Where does the team rely on one person, manual step or undocumented rule?
- What customer, operational, security or compliance outcome is affected?
- What evidence shows the current cost or risk?
- How often will planned work touch this area?
- Is the debt deliberate, accidental or caused by a changed requirement?
- Does an accepted shortcut have an owner and expiry condition?
- Can the debt be reduced safely beside a useful feature?
- Does one constraint justify a focused stabilisation or upgrade phase?
- Is replacement genuinely safer than gradual improvement?
- How will the business know the repair improved delivery or operation?
- Which controls stop the same debt becoming invisible again?


