Technical Debt: How to Measure, Prioritize, and Reduce

What is technical debt and how to measure it using code metrics and business indicators. Prioritization methods, refactoring sprints…

What Is Technical Debt and Why You Can’t Ignore It

Technical debt is the set of compromises in code, architecture, infrastructure, or testing made to speed up development, but which in the long run slow down speed and increase the cost of changes. The term, coined by Ward Cunningham, compares these “quick fixes” to financial debt: taking out a loan allows you to get results faster, but the interest consumes more and more resources if you don’t pay down the principal. At ESK Solutions studio, during custom web development, we regularly see how unnoticed accumulated debt turns a flexible project into an expensive legacy.

Types of Technical Debt

  • Intentional (Strategic) — the team consciously takes shortcuts to speed time to market (common in startups).
  • Unintentional (Entropic) — arises naturally as the product evolves, requirements change, and technologies are updated.
  • Infrastructure — outdated versions of environments, manual environment setup, lack of CI/CD.
  • Architectural — accumulation of “crutches” that make the system fragile and non-extensible.

Ignoring any of these types leads to slower time-to-market, an increase in defects, lower developer motivation, and ultimately loss of competitiveness. Therefore, measuring and systematically reducing technical debt is a management task, not a developer whim.

Metrics for Technical Debt

Without numbers, fighting technical debt turns into endless arguments. Metrics provide an objective picture and allow you to justify investments to the business. They are usually divided into two large groups: quantitative code metrics and business metrics.

Quantitative Code Metrics

Modern static analyzers and platforms (SonarQube, CodeScene, CodeClimate, GitHub Advanced Security) automatically compute dozens of indicators. In custom development, for example in cloud services, we necessarily include the following:

  • Cyclomatic Complexity — the number of independent paths through a piece of code. Threshold 10–15; exceeding that directly indicates hard-to-test and maintain methods.
  • Code Duplication — the proportion of repeating fragments. The DRY (Don’t Repeat Yourself) principle is not dogma, but copy-paste levels above 5% usually signal problems.
  • Depth of Inheritance and component coupling — indicators of architectural entropy. High coupling with low cohesion is a classic sign of a “Big Ball of Mud.”
  • Test Coverage — it’s not just the percentage that matters, but coverage of critical scenarios. We believe that less than 60% of code is already a “debt” level.
  • Number and Severity of Vulnerabilities — Security Debt, which grows exponentially as dependencies become outdated.
  • Code Smells — long methods, large classes, throwing inappropriate exceptions, dead code, god objects. Analyzers label them as “Minor”, “Major”, “Critical”, or “Blocker”.

Business Metrics for Technical Debt

Code metrics translate into losses for the business:

  • Team Velocity — a decrease in the number of completed story points per iteration with an unchanged team composition.
  • Lead Time and Cycle Time — time from idea to production and the duration of development itself. If the “tail” grows, debt is slowing things down.
  • Defect Rate — the proportion of defects found after release, as well as regressions.
  • Mean Time to Recovery (MTTR) — with high technical debt, incidents are fixed slowly.
  • Maintenance Cost — the share of the development budget spent on support and bug fixing rather than new features. A healthy range is 15–25%.
  • Technical Debt Index — the ratio of estimated time to remediate to total development time. SonarQube calculates a rating from A to E.

By collecting these metrics monthly, you can build a "tech debt radar" and track dynamics. In projects involving SaaS solutions development, we use exactly this approach, linking the index growth to a decline in customer Retention Rate.

How to Prioritize Technical Debt Work

Getting a budget for "refactoring everything at once" is nearly impossible. Prioritization is the key to ensuring every hour spent on debt reduction delivers a tangible business impact.

The "Effort-Impact" Matrix and Cost of Delay

We recommend mapping each "debt story" along two axes:

  • Effort — person-days, complexity, risks of changes.
  • Impact — how much the fix will increase the development speed of adjacent components, reduce defects, simplify onboarding, or open opportunities for new features.

Items that fall into the "quick wins" quadrant (low effort, high impact) should be done immediately. "Strategic projects" (high effort, high impact) are planned as dedicated phases. The Cost of Delay method is also often used: estimate how much money the company loses each month by postponing the elimination of this debt. For systems with a high number of users, such as CRM development, downtime due to an architectural defect can cost tens of thousands of rubles per hour.

Refactoring Sprints: Embedding into the Process

The approach we scale in our projects is refactoring sprints. These can include:

  • Consistent percentage in each sprint — 15% to 30% of the team's capacity is reserved for tasks from the tech debt backlog. These tasks are planned alongside product tasks, and the product owner cannot cancel them without discussion.
  • Dedicated sprint every 3–4 iterations — the team fully shifts context: only refactoring, test improvements, dependency updates. It's important that goals are measurable (e.g., raise coverage to 75%, reduce Cyclomatic Complexity to 12).
  • Constant "hygiene" (Boy Scout Rule) — each developer leaves the code slightly cleaner than they found it. This doesn't require separate sprints but provides cumulative effect.

We often combine these methods: the consistent percentage prevents a "snowball effect", while dedicated sprints tackle large architectural tasks that depend on further development of corporate portals or mobile solutions.

Creating a Technical Debt Backlog

Without a separate list, tech debt tasks disappear under the pressure of hot features. The technical debt backlog should be visible to all stakeholders. Each entry includes: symptom description, metrics (e.g., current complexity level 25), expected effect after resolution (feature delivery time reduction by 20%), effort estimation. The product owner, together with the tech lead, reviews priorities weekly, aligning them with the product roadmap.

Strategies for Reducing Technical Debt

Debt reduction is not a one-time action but a continuous practice. Below are proven strategies we use in custom development.

1. Continuous Refactoring and Automation

Every actively developed codebase degrades without micro-refactoring. Pair programming and mandatory code review (Pull Request review) focused on cleanliness and readability catch 60–70% of potential debt at the writing stage. Integrating static analyzers directly into the CI/CD pipeline prevents "dirty" code from reaching the main branch. Extensive experience in SaaS solutions development shows that automatic quality checks on every commit provide the greatest debt reduction per ruble invested.

2. Dedicated Refactoring Sprints

For large pieces of legacy code where micro-refactoring no longer helps, full iterations are planned. A sample plan for such a sprint:

  • Target metric: for example, reduce the average cyclomatic complexity of module "A" from 18 to 10.
  • Scope: refactoring main classes, breaking up god objects, covering the most dangerous methods with unit tests.
  • Tooling: a task with automatic calculation of metrics before and after. Result protection — acceptance by Quality Gate in SonarQube.

It's important to record the business impact: "After this sprint, we unblocked 3 features, and the time to deliver them decreased by 40%." This strengthens business trust in such investments.

3. Testing and deployment automation

Most debt manifests as regressions and fear of making changes. Increasing test coverage of critical paths with automated tests (unit, integration, e2e) reduces that fear. Implementing Continuous Delivery with automated deployment eliminates infrastructure debt and shifts manual routine operations to robots. In web application development projects, we always insist on setting up CI/CD from day one.

4. Architectural refactorings and migrations

If the system has grown from a monolith into an unchangeable blob, strategic modernization is required: extracting microservices, migrating to a more performant stack, using event-driven architecture. We precede such projects with a break-even analysis. It is crucial not to reinvent the wheel but to use proven approaches. In cloud development, adopting managed services (e.g., managed queues, databases) allows shifting part of the infrastructure debt to the provider.

5. Team training and a "zero debt" culture

Tools won't help if developers don't understand the cost of their decisions. Implementing internal coding standards, guidelines, and regular Tech Talks is a critical investment. Teach the team to always leave the code a little better: variable names, removing commented-out code, extracting methods. Over time, this becomes part of the project's DNA.

Frequently Asked Questions

1. How is technical debt different from "bad code"?

Bad code is low quality due to ignorance or carelessness. Technical debt is a deliberate or unintentional compromise made in exchange for speed. But bad code almost always becomes debt with huge interest, so we don't separate these concepts and treat them the same—with discipline and automation.

2. How often should dedicated refactoring sprints be held?

Optimally, every 3–4 sprints. If the product is young and architecturally sound, constant 20% attention without dedicated iterations is sufficient. For legacy projects, especially in CRM development, quarterly refactoring sprints may not be enough—a full "health" phase lasting 2–3 months is required.

3. Should a separate technical debt backlog be created?

Yes. Without it, refactoring tasks lose visibility. The key is to integrate it with the main product backlog: periodically, the product owner should "buy" these tasks on par with features, seeing their business value.

4. Can technical debt be completely eliminated?

Zero debt is a utopia. Like financial debt, it is sometimes necessary for rapid growth. The goal is a manageable level where debt does not constrain the business and is serviced predictably. A healthy SonarQube rating of A or B and consistent focus on metrics are sufficient benchmarks.

Technical debt is not purely a technical problem but primarily a business problem. Ignoring it steals future speed and increases the product's total cost of ownership. At ESK Solutions, we have embedded debt management into all stages of custom development—from architectural design to code hygiene in every sprint. By using the metrics and approaches outlined, you can take control of technical debt and restore flexibility to the project and confidence in the code to the team.