Technical Debt is a metaphor that describes the price of compromises in development: the faster suboptimal decisions are made, the more interest accumulates. The term was coined by Ward Cunningham in 1992, comparing low-quality code to financial debt. According to Martin Fowler, technical debt is inevitable, but conscious management of it distinguishes a professional team from a chaotic one.
Key Takeaways
Technical Debt is a metaphor first coined by Ward Cunningham in 1992 at OOPSLA. He compared programming to investing: careless code is like taking out a loan. Interest on it is paid in the form of additional time spent on maintenance, bug fixes, and adaptation to new requirements. It’s important to understand that debt is not always bad; strategic debt can be justified.
The financial analogy works almost literally. If a team takes out a loan (releases imperfect code to meet a deadline), it must pay interest. Interest is the slowdown of development, bugs when modifying code, and the complexity of onboarding new developers. When interest becomes higher than the cost of refactoring, it’s time to pay off the debt. The main problem: unlike a bank loan, developers don’t always realize they’ve taken on debt.
An important clarification: technical debt ≠ bad code. Bad code is a consequence of incompetence. Technical debt is a conscious compromise. The team understands it’s doing something imperfectly, documents it in technical documentation, and plans to return to improve it. The difference between debt and bad code lies in the awareness of the decision. That’s why the first step to managing debt is acknowledging its existence.
Classifying technical debt helps understand its nature and choose the right repayment strategy. Martin Fowler proposed a quadrant model with two axes: intentional/unintentional and reckless/prudent. Each combination requires a different approach. Let’s look at the main types of debt that a mobile development team faces.
Intentional Debt — the team deliberately decides to release suboptimal code to meet a deadline. Example: launching an MVP with a single monolithic ViewModel, understanding that after hypothesis validation, the ViewModel will be split into several by domain. Such debt is recorded in the backlog and has a planned repayment date. Without a plan, intentional debt becomes chronic.
Unintentional Debt — code whose quality is lower than expected due to lack of knowledge, absence of code review, or poor processes. Example: a developer didn’t know best practices for working with Room DB and wrote queries on the UI thread, causing ANR. This type of debt is the most insidious — the team doesn’t realize it until they face critical performance issues.
Architecture Debt — wrong choice of patterns or project structure. Example: an app without an abstraction layer over networking, where Retrofit is used directly from ViewModel. Replacing Retrofit with Ktor would require changing all ViewModels. Fixing architectural debt is the most expensive, so architectural-level decisions are made with maximum caution.
Code Debt — local suboptimalities within a single class or method. Example: a long method with 200 lines where UI, business logic, and data handling are mixed. Fixed with Extract Method in 15 minutes. Code debt is less critical, but its accumulation at the project scale slows down development no less than architectural debt.
Testing Debt — lack of Unit tests, UI tests, or integration tests. Every manual regression run is interest on this debt. If a project has no automated tests, any change requires hours of manual testing. According to the Google Testing Blog, projects with test coverage >70% release bugs to production 2 times less often.
Documentation Debt — absence or obsolescence of architectural documentation, comments on complex code areas, onboarding readme. A new developer spends weeks getting up to speed without documentation. Solution: maintain Architecture Decision Records (ADR) and make documentation part of the Definition of Done for every task.
| Debt Type | Example | Fix Difficulty |
|---|---|---|
| Architecture | Wrong pattern choice | High (weeks) |
| Code | Long method, duplication | Low (hours) |
| Testing | Lack of Unit tests | Medium (days) |
| Documentation | Outdated ADR | Low (hours) |
The compound interest effect is the main danger of technical debt. Each new layer of suboptimal code increases system complexity not linearly, but exponentially. A simple example: if module A depends on module B, and both contain debt, then changing A requires understanding the debt in B. After 10 iterations, a developer spends 80% of their time untangling dependencies and only 20% on new functionality.
Slowdown of time-to-market is a direct consequence of debt. The team spends more and more time on maintenance and less on new features. A Stripe study (2023) showed that developers spend an average of 17 hours per week dealing with technical debt, rather than creating business value. In mobile development, this is compounded by the need to support two platforms — each with its own platform updates.
Team burnout is an unobvious but devastating consequence. Working in code where every change breaks three other things causes chronic stress. Developers stop being proud of the product, motivation drops, and turnover increases. According to the Stack Overflow Survey 2024, working with legacy code is the second most common cause of job dissatisfaction after low salary.
Fowler’s Quadrant is a practical tool for prioritizing debt. Two axes: intentional/unintentional and reckless/prudent. Reckless intentional debt: “we don’t have time for tests, ship without them.” Prudent intentional: “we know tests are needed, but now it’s more important to ship the feature — we’ll create a task for tests in the next sprint.” The first requires immediate intervention, the second requires monitoring.
The Boy Scout Rule strategy — “leave the campsite cleaner than you found it.” A simple rule: when modifying a method, spend 10% more time to make it a little better — rename a variable, split a 50-line block into two. At the team scale, this approach yields a gradual reduction in debt without dedicating separate sprints to refactoring. The improvement should be microscopic but regular.
Allocating time for debt management is a marker of team maturity. It’s recommended to reserve 15–20% of the sprint for technical improvements. This doesn’t mean the team does nothing but refactoring one day a week. Technical tasks are distributed evenly: improving metrics, refactoring hot spots, updating dependencies. Without dedicated time, debt grows continuously.
// Boy Scout Rule strategy in action
// Before: unreadable method with magic numbers
fun calc(a: Int): Int = a * 60 * 1000
// After: readable method with constants
private const val SECONDS_IN_MINUTE = 60
private const val MILLIS_IN_SECOND = 1000
fun minutesToMillis(minutes: Int): Int =
minutes * SECONDS_IN_MINUTE * MILLIS_IN_SECOND
Automating debt detection is the third pillar of management. Set up alerts for detecting long methods (>30 lines), classes (>500 lines), excessive nesting (>5 levels). Use Danger or similar tools for automatic comments on pull requests: if a method exceeds the complexity threshold, the bot writes “This method has cyclomatic complexity of 12 — please consider splitting it.” Automation reduces the burden on code review.
SonarQube is the most popular platform for technical debt analysis. It calculates “days to fix” — a metric understandable to managers. SonarQube supports Kotlin, Swift, Java, Python, and other languages. It integrates into the CI/CD pipeline and rejects pull requests if debt increases beyond the threshold. For mobile teams, this is the de facto standard.
For Android teams Detekt (Kotlin static analysis) and Android Lint are also used. Detekt calculates code metrics and finds Code Smell patterns. The SonarQube Android Gradle plugin combines results into a single report. For iOS teams — SwiftLint for static analysis and Periphery for finding unused code. Xcode Organizer shows performance metrics that often correlate with architectural debt.
CodeClimate and CodeFactor are cloud solutions that analyze GitHub/GitLab repositories and show debt dynamics. They evaluate each commit, allowing you to track when debt started growing. The Maintainability chart is an understandable tool for communicating with management: “See the peak in March? That’s when we pushed a release and accumulated 3 days’ worth of fix debt.”
Frequently Asked Questions
Use the credit metaphor: “We can ship the feature in 2 weeks now, but every subsequent sprint we’ll spend 20% more time on maintenance. If we don’t pay off the debt, in 6 months a sprint will take 3 weeks instead of 2.” Managers intuitively understand the financial analogy.
For MVP and experiments — yes, if a repayment plan is documented. For a startup that needs to show a prototype to an investor tomorrow — yes. For a product with a million users — no, the cost of mistakes is too high. The key condition: a conscious decision with a planned fix date.
SonarQube shows “Debt Ratio” — the ratio of time to fix to time to develop. A Debt Ratio < 5% is considered normal. For code: Lines of Code per Method, Cyclomatic Complexity, Duplication Rate. For processes: ratio of bug-fix time to feature time.
No — that’s a last resort. Practice shows that allocating 15–20% of each sprint to technical improvements is more effective than a “refactoring sprint.” Refactoring without business value is perceived as a waste of time. It’s better to weave improvements into every product task.
No — strategic debt can be a tool. If a team consciously takes on debt to ship a feature that will generate revenue, and then pays it off, that’s effective management. The problem starts when debt accumulates uncontrollably and no one knows how much “interest” has already accrued.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also