The trade-off required between delivering perfect products and meeting tight deadlines makes the issue of technical debt particularly relevant to software and system developers. Yet this issue is often shifted to the back burner. Why? Because addressing it rarely fulfills an urgent business need. What’s more – and especially for cases that aren’t urgent – the return on investment (ROI) is often unclear to decision-makers in an organization. So the issue of technical debt is perceived as deferrable.
Yet technical debt cannot be written off simply as a maintenance issue. It has substantial implications for the operational and commercial viability of an organization. Large software companies, for example, need to support the continuous and rapid delivery of customer value – in both the short- and long-term. However, this value provision can suffer if technical debt hampers the evolution and maintenance of existing systems.
A Science of Computer Programming survey and multiple case studies of 15 large organizations found the cost of managing technical debt in large software enterprises to be, on average, 25% of the entire development time. That’s a significant proportion and a clear indicator that technical debt must be taken into account.
What Is Technical Debt?
The term “technical debt” was coined by Ward Cunningham, one of the founders of agile programming, during a discussion of the concept in an experience report for OOPSLA 1992. It’s a financial metaphor which proposes that the “debt” incurred in an IT project represents the extra development work required when imperfect code is implemented in the short-term, despite it not being the best overall solution. The terms “code debt” and “design debt” are often taken as synonymous.
(Image source: BrainHub.eu)
Developer Martin Fowler talks of software systems in terms of “cruft” – “deficiencies in internal quality that make it harder than it would ideally be to modify and extend the system further.” The technical debt metaphor looks on cruft as a financial burden, with the extra effort that it takes to add new features being the interest paid on that debt.
In his analysis, Fowler argues that while it’s possible to estimate how long it will take to program a new feature, predict how it might behave if the cruft was removed, and estimate the cost of actually removing the cruft, the accuracy of these estimates will always be pretty low. The best course for developers is, therefore, to pay off “the principal” gradually – as with financial debt – by systematically and incrementally removing cruft, thereby reducing the “interest rate” on future enhancements.
(Image source: martinfowler.com)
Note that technical debt is often a necessary part of the development process, and is often accumulated intentionally. So, imperfect but stable sections of code might be left alone – especially for new features which are needed urgently – while debt reduction in areas of high performance and low to zero fault tolerance would become a priority. In all cases, there should be an understanding and awareness that some level of technical debt exists, and that it will need to be managed at some point in the future.
Fowler goes on to quote analyst Scott Wood, who takes the financial analogy further to bring the concept of “inflation” into the mix: “Technical Inflation could be viewed as the ground lost when the current level of technology surpasses that of the foundation of your product to the extent that it begins losing compatibility with the industry. Examples of this would be falling behind in versions of a language to the point where your code is no longer compatible with mainstream compilers.”
(Image source: Accenture)
Accenture’s Technical Debt Model looks at technical debt from an organizational standpoint. It includes the cost of renewing legacy systems to meet current requirements and the conditions of today’s operating environment while maintaining software quality for acceptable levels of risk, performance, and agility. Taking the financial metaphor to an even greater depth, the model sets out the component costs of technical debt as follows:
- Principal: The largest cost burden, including maintenance and remediation of legacy systems.
- Interest: Staffing, delays, and the costs of maintaining redundant systems when decisions to integrate or retire older technologies have been deferred.
- Liability: The costs associated with patching software, replacing hardware, or restoring systems, when deferred maintenance leaves systems fragile and vulnerable to outages, security breaches, or data corruption.
- Opportunity Costs: These costs effectively represent “borrowing from the future,” due to an inability or unwillingness to support modernization efforts that could close current gaps in cost, performance, and security.
Types of Technical Debt
There are several kinds of technical debt that a project or organization can incur. The maintenance burden left behind after implementing a complex feature would be one example. Deploying fresh code using a new version of a library or service, and leaving the upgrade of older code to a later time, would be another. DZone.com enumerates the most common technical debt cases as:
Source Code Formatting Errors
These errors can be avoided through coding best practices, an agreement on common standards before commencing a project, and the use of appropriate tools and templates.
Low Test Coverage
Frequent testing ensures that each section of the code is behaving in its intended manner. Particularly for agile development projects, a low level of test coverage gives an inadequate picture of code quality and makes it less likely that problems encountered down the line will have an easy fix.
Lack of Modularity
In an ideal environment, code should be set out in modules that serve specific purposes, retain a consistent logic, and integrate seamlessly with each other. Poor code design may result in a various mix of logic that makes it difficult for the various modules to interact successfully – and more difficult and time-consuming for developers to rectify.
Long path lengths and multiple dependencies typically translate into complex and often clunky code that’s difficult to troubleshoot and maintain.
Poor or Minimal Documentation
As a project evolves, everyone involved in the development process must have a clear and common understanding of its various parts and behaviors. Clear and comprehensive documentation is key to this.
Tech Debt Classification
Dag Liodden, Co-founder and CTO of AdTech company Tapad, uses a simpler classification for communicating and addressing technical debt issues in and across teams.
“Deliberate tech debt” is incurred when development teams intentionally do something the “wrong” way because they need to deliver a product to the market quickly. Developers should keep track of it in the backlog, and be aware of both how much time this corner-cutting saves on product delivery, and what will eventually be required to cover the debt. This type of debt is driven by business logic, and the product owners and stakeholders should be held accountable for it.
“Accidental or outdated design tech debt” occurs as systems evolve, and user requirements change. As design flaws become evident or new functionality becomes difficult and slow to implement, some degree of refactoring (the restructuring of existing code) becomes necessary. Team or tech leads and product owners should be held accountable for setting time aside to resolve this type of debt.
“Bit rot tech debt” occurs over time, as incremental changes to components or systems cause them to degrade progressively. The problem is exacerbated when numerous parties contribute to a project without a clear understanding of its original design. Continuous refactoring is essential to managing this type of debt, with the development team taking responsibility for incrementally improving the design and cleaning up bad code.
Causes of Technical Debt
(Image source: BrainHub.eu)
Poor conception, poor scheduling, bad development practices, and outdated technology are among the principal causes of technical debt.
Poor conception and poorly designed software frequently result from market pressures to deliver quick results or to follow trends set by other market-leading products. This rush can lead to software that isn’t well thought out, with a focus on functionality and little consideration for other aspects of the project that could become relevant later on. Though the product owner and the developers may have an agreement to iron out these kinks at a later date, the poor initial concept can contribute to making refactoring and remediation difficult and time-consuming.
Technical debt can also mount up due to an inaccurate estimation of the time required to complete a project. A schedule that allocates little time for completion will put the development team under pressure to cut corners and adopt methods that can negatively impact the project moving forward.
A common set of design conventions and development good practices will enable a software team to maintain a consistent methodology and quality as they implement each feature. An ad hoc approach to development practices may lead to the use of multiple and conflicting standards or formats and require developers to reconstruct the same logic numerous times as the work proceeds.
Advances in technology can build up technical debt, as legacy systems and software that haven’t been upgraded struggle to keep pace with new developments and demands.
AgileScrumGuide.com identifies seven factors which can result in the accumulation of technical inefficiencies that need to be serviced in the future:
- Time pressures
- Overly complex technical design
- Poor alignment to standards
- Lack of skill
- Suboptimal code
- Delayed refactoring
- Insufficient testing
How to Measure Technical Debt
As the “interest” on technical debt accumulates, software owners and developers can find themselves in a descending spiral of poor software performance, difficulties in making changes and improvements to the software, and increased risk of software or system failure after each update. So, it’s imperative to manage technical debt at an early stage of the development process.
The principle of software entropy contributes to making “We’ll come back to this later when we have time,” a no-go option for technical debt management. Software entropy describes the tendency for software to become more difficult and expensive to maintain as it gets modified over time. And as the code base expands, maintenance can become trickier and more expensive.
However, if technical debt can be quantified, it immediately becomes more manageable. But with technical debt being only one of several variables affecting code quality, it can be difficult to identify which metrics are most relevant in determining how much work needs to be done to pay off technical debt. In its 2018 study on measuring technical debt, Accenture reports that while organizations need a systematic means for measuring and managing their technical debt, most (70%) do not have a fully-integrated approach. And as a starting point, agencies need to distinguish between application-level and structural-level technical debt.
Application-level debt within an organization can be analyzed and benchmarked using methods like Application Portfolio Management (APM), which can establish total technical debt and cost to remediate, as well as evaluating the impact of possible fixes on overall performance.
Modeling future capabilities and cost structures can assist organizations in assessing their current structural debt. Mapping your target architecture against your current baseline capabilities can identify structural gaps, and help overcome the challenges to technical debt measurement posed by the various dependencies inherent within the infrastructure and related systems.
When accumulated technical debt causes mission-critical systems to either break down completely or decline to a level where the organization is forced to discontinue or significantly reduce its investments in innovative new technology, a discontinuity point occurs. This may be caused by legacy systems, a lack of the skills needed to upgrade and modernize, or an inability to integrate systems and data. Poor maintenance, inadequate investment, inherent complexity, and changing mission requirements can also contribute. But monitoring and measuring technical debt can help in staving off these critical occurrences.
DZone.com proposes two ways of measuring technical debt. One uses the results of static code analysis performed by tools such as Coverity, SonarQube, or Checkstyle, in conjunction with your list of technical debts and their references to the code.
The other approach is to get a ratio of technical debt according to code volume, using initial estimates or the overall time needed to develop the software so far, and extrapolating that value according to the technical debt ratio. Daniel Okwufulueze, Senior Engineer at customer data science company Dunnhumby, suggests measuring technical debt as a ratio of the cost to fix a software system [Remediation Cost] to the cost of developing it [Development Cost]. This ratio is called the Technical Debt Ratio [TDR] and can be expressed as a simple equation:
Technical Debt Ratio = (Remediation Cost / Development Cost) x 100%
These costs may be expressed in terms of time, with, for example, the Remediation Cost [RC] being a function of any code quality metric that a team feels is relevant, based on its rules for resolving code issues. TDR values indicate how long it would take an engineering team to restore sanity to their code base and achieve a desired quality level and should ideally be kept as short as possible.
Tracking Technical Debt
Tracking and monitoring technical debt is as critical to its management as being able to quantify it. Developer Mark Heath suggests creating a “technical debt document” listing specific issues that need addressing, explaining the problems that they are currently causing, and the proposed solutions. The document may also include estimates of how long a fix will take, and upcoming features in the development roadmap that will become easier to implement once a particular technical debt item has been resolved.
Heath also mentions the work of researchers Philippe Kruchten, Robert Nord, and Ipek Ozkaya. In their book, Managing Technical Debt, the authors recommend setting up a “technical debt register,” using regular work tracking tools like GitHub issues, Jira, or Azure DevOps to store “technical debt items.” These items may be tagged (e.g., as “TechDebt”) in a common knowledge base, where they can be planned and estimated with the same tools used for defects and features.
This approach also enables developers to associate commits with specific technical debt items, which can also be linked to relevant software features and defects. Having a common document also promotes dialogue within the team, allowing the developers to decide by consensus the best ways of dealing with particular issues, and providing a known and centralized location for developers wishing to add new technical debt items.
Technical debt tracking is by no means a standard practice. In its research, Science of Computer Programming found that of the 226 respondents from 15 organizations surveyed, only a few participants (26%) use a tool, and only 7.2% methodically track Technical Debt.
(Image source: ScienceDirect.com)
This laxity flies in the face of logic somewhat, given that Accenture reports 83% of respondents to its Federal Digital Decoupling Study to believe that technical debt greatly increases their organization’s IT costs, 80% believe that technical debt in their legacy systems severely limits their ability to augment or enhance these systems, and 81% believe that technical debt in their legacy systems must be remediated before migrating to the cloud.
Some Best Practices
Maintaining a visible journal of technical debts that lists and groups deferred tasks into workable units – alongside the consequences of ignoring each unit – are just some of the best practices recommended by The Business of IT Blog. Others include scheduling regular and frequent time to pay off technical debt and making stakeholders who rely on delivery releases aware of when you’re working on technical debt so that they can appreciate why a particular update doesn’t exclusively include new features.
(Image source: Accenture)
In terms of remediation, you can look at the time that developers need to spend reducing technical debt by refactoring or replacing an application and assign a dollar amount to these transactions. This will enable you to compare this data with other milestones, such as the number of days remaining before the next release date. This information can also form the basis of a cost/benefit analysis for communicating the value of technical debt reduction efforts to business stakeholders.
(Image source: BrainHub.eu)
Communication is especially important in keeping non-technical stakeholders in the loop regarding the true cost of technical debt, the importance of paying it off sooner rather than later, and how technical debt is projected to change over time.
Addressing debts like code formatting that take little time to fix is an excellent way to eliminate technical debt gradually. Issues with potentially significant consequences should also be prioritized and addressed early on.
Since agile development embraces increments and iterations rather than finished projects, implementing agile methodologies can be a good way to stay on top of technical debt. Short bursts of work make it easier for IT teams to tackle small and manageable groups of technical debt issues in an ongoing manner. Agile methodologies like test automation and continuous integration (CI) can enable development teams to work on technical debt reduction continuously.
Technical debt is a necessary and often unavoidable part of software and systems development. Identifying, tracking, and measuring technical debt is essential in understanding how it affects the performance of software projects and development team performance. Effective management of technical debt facilitates a balance between delivering new features in the short-term and increasing overall productivity and stability in the medium- to long-term.
What is technical debt?
The trade-off required between delivering perfect products and meeting tight deadlines makes the issue of technical debt particularly relevant to software and system developers. The term “technical debt” was coined by Ward Cunningham, one of the founders of agile programming, during a discussion of the concept in an experience report for OOPSLA 1992. It’s a financial metaphor which proposes that the “debt” incurred in an IT project represents the extra development work required when imperfect code is implemented in the short-term, despite it not being the best overall solution. The terms “code debt” and “design debt” are often taken as synonymous. Note that technical debt is often a necessary part of the development process, and is often accumulated intentionally. So, imperfect but stable sections of code might be left alone – especially for new features which are needed urgently. Poor conception, poor scheduling, bad development practices, and outdated technology are among the principal causes of technical debt. Tracking and monitoring technical debt is as critical to its management as being able to quantify it. Developer Mark Heath suggests creating a “technical debt document” listing specific issues that need addressing, explaining the problems that they are currently causing, and the proposed solutions. The document may also include estimates of how long a fix will take, and upcoming features in the development roadmap that will become easier to implement once a particular technical debt item has been resolved.