Four Strategies for Managing Technical Debt

Current literature related to software engineering research, developers’ blogs, as well as software engineering developers’ conferences talk in a great deal about technical debt. It is relevant to ask — why technical debt is an important concern for a software development team? Why should we care about technical debt? What if technical debt of a project increasing especially when the project is functional and the clients of the software are not complaining? Should we pay attention to it? In this text, we try to understand technical debt and reason about the need of it to be addressed.

Let us start from the beginning when the term was first introduced. Ward Cunningham introduced the term ‘Technical Debt’ to the world in a 1992 report as the debt that accrues when we knowingly or unknowingly make wrong or non-optimal technical decisions. The decision not only impacts the source code entity concerning the decision but also other technical decisions leading to a higher pile of the debt. In the case of non-payment of the accrued technical debt for a long time, the software increasingly becomes harder to change and in the extreme case, the software product becomes technically bankrupt i.e., it is not feasible to introduce a change reliably in the prescribed time.

Further, large technical debt impacts the productivity of the software development team and lowers their morale and motivation. Continuous accrual of technical debt leads to a vicious cycle: large technical debt reduces the productivity and morale of the team; at the same time low productivity attracts management push for more features and postponement of technical debt issues, which in turn further increases the technical debt.

Technical debt, like a financial debt, is a result of principal (the original hack, or shortcut), and accumulated interest incurred when the principal is not addressed on time. The interest component is compounding in nature: the more development teams ignore it or postpone it, the bigger the debt becomes over time.

Technical debt may source from different artifacts and granularity. For instance, implementation, design, and architecture smells contribute to technical debt that originates from source code at different granularities. Other sources of technical debt are test smells, configuration smells, and poor documentation.

Managing technical debt

The first aspect to manage technical debt is to prevent technical debt from accumulating. It includes increasing awareness within the software development teams about technical debt and introducing relevant processes (such as manual peer review and quality analysis embedded in continuous integration) within the organization.

Often, teams work in projects that have accumulated a considerable amount of technical debt. In such situations, it is not wise to ignore the debt further since it may lead the project towards technical bankruptcy. On the other hand, it is also not feasible and practical to stop developing new features for a few months and instead focus only on repaying technical debt. A balanced and pragmatic approach is required in these situations to repay the debt steadily and keep progressing as far as features and functionality of the software is concerned. Let us now discuss a few pragmatic strategies for repaying technical debt.

1. Identify and track the debt

The first step towards repaying technical debt is to know how deep we are in the mud i.e., to identify existing debt. Relevant tools could be employed to identify the concrete debt instances (for instance smells). For example, Designite could be used to identify smells in the source code at implementation, design, and architecture granularity. Experienced developers and architects in the team can also identify debt instances.

The lack of any action nullifies the effort to identify technical debt issues.

However, not all identified issues or smells are same. Some issues get identified in the source code which has not been touched for years, some issues are simply wrongly detected, and some issues are correctly identified but you would rather live with them (for instance, in a case in which you think it is too expensive to refactor). It is essential to decide what you would like to do with a detected smell. Some tools make it quite easier for the developers. For instance, Designite shows detected implementation and design smell within the Visual Studio IDE and encourage developers to tag smells. A developer takes a decision about a smell, tags it (either Refactor, Wrong, or Drop) which is remembered by the tool. Smell instances tagged as Wrong or Drop are not shown to the developer.

Smell tagging by Designite within Visual Studio
Smell tagging by Designite within Visual Studio

2. Prioritize smells

Not all debts are the same — different types of debt come with different interest rates. Hence, the identified debt instances must be prioritized for refactoring based on factors such as potential impact of the debt instance on the project. It is practically impossible (in fact, not recommended also) to be 100% “debt free” in real-world projects; it is okay to live with some (low priority) debt to maintain the balance between feature development and technical debt repayment.

3. Plan small refactoring installments in each iteration

It is common in the financial domain to pay a large loan in smaller installments. In the same way, it is unlikely for a project team to repay huge technical debt all at once; however, repayment in the form of small installments — ERIs (Equated Release Installments) is quite feasible and practical where a small portion of effort in each iteration is dedicated to refactoring.
Similar to lump-sum repayment in the financial world, make a large part-payment periodically. Such debt repayment is analogous to making the part-payment of a big home loan upon receiving a bonus from the employer. Keep looking out for opportunities to repay debt on a large-scale, for instance, just after a major release. Large-scale changes such as performing architecture refactoring can contribute to a drastic reduction in technical debt. Such exercises require considerable planning and effective communication to reduce the associated risks.

4. Motivate and reward people for maintaining quality

“People care about the things that you measure and you reward.”

The technical management must ensure that the software development team is motivated to maintain the quality of the software. If a manager of a software development team measures the number of features (or LOC) delivered or a number of defects fixed by the team as the yardstick for their performance, then the team will only focus on adding features and fixing defects. How well it is done is as important as getting it done. Keeping the motivation high and rewarding people for not only developing working code but also the quality code is the key strategy in the battle against high technical debt and deteriorating quality.
In this context, the Boy’s scout rule could be highly relevant. It says “always leave the campground cleaner than you got it”. In the context of software development, it can be interpreted as: “leave the class (or method) cleaner than you got it”. Encouraging the team to refactor whenever they touch a piece of code for feature addition or bug fixes improve the code quality continuously over a period of time.
In summary, understanding technical debt and keeping it low is essential for a software development team. Ignoring technical debt issues bring negative consequences for the team such as low productivity and low morale. However, bringing awareness and introducing appropriate tools and strategies may help a team to contain it.

Related reading

1. Book — Refactoring for Software Design Smells
2. A Taxonomy of Software Smells