How much technical debt is acceptable?
Do you remember working on that app two years ago, and a decision you made under the pressure of time, budget or stakeholders? Maybe that decision was less than ideal, but you made it to prevent an issue from holding up the development process? The consequences of that not-ideal decision are still alive as a technical debt. But don’t worry, every single digital product carries some amount of technical debt. And some debt is acceptable. The questions are, how to measure an app’s technical debt, and how much technical debt is healthy?
Table of contents
This article will answer both questions, but I would like to clarify the meaning of ‘technical debt’ before we tackle that. I will also raise the topics of technical debt in agile and technical debt management in general to offer a comprehensive understanding of the subject.
What is technical debt?
Simply put, technical debt is a result of prioritizing speed over quality in software development. It happens when a product team decides to accelerate the delivery of the project or a feature which will have to be refactored later.
Technical debt, also known as tech debt, code debt, design and UX debt, may refer to things like bugs, low code quality, missing documentation, unintuitive design, etc. This can lead to issues like lower customer retention, security vulnerabilities and consequences - potentially resulting in the business failure of the product. At some point, the organization will have to fix that – repay its debt with resources, time, money, and energy.
When talking about what technical debt is, people usually think of old legacy products; however, technical debt appears from day one. It just gets significantly bigger and more costly over time. Some of the most common causes of code debt are time pressure, constant change (in the industry in general, in client needs, etc.), and outdated technology.
Types of technical debt
Technical debt may be categorized based on various characteristics, but the most popular classification, called the Technical Debt Quadrant, considers two factors: intent and context.
According to the Technical Debt Quadrant, there are four types of technical debt:
- Prudent and deliberate: when a team decides to ship something fast and compromise on quality intentionally. In that case, the team is aware of the consequences, but the benefit of releasing something quickly is worth the technical debt it will generate.
- Prudent and accidental: when a team makes a decision based on the best knowledge available at that time, but it turns out later that the information was incomplete and they should have done something differently.
- Reckless and deliberate: when a team is aware of the consequences and can avoid them but decides to prioritize speed over quality anyway.
- Reckless and accidental: when a team is not aware of the consequences because it lacks knowledge and/or experience, and they get into technical debt unconsciously.
Reckless technical debt should always be avoided. The more experienced the team is, the less likely it is to happen, and the smaller the size and consequences.
Is technical debt good or bad?
Prioritizing client value, delivery deadlines or other project constraints over a better technical implementation provides a company with a short-term competitive advantage. As I mentioned above, the debt will have to be repaid at some point. It may result in a lost opportunity in the long run, as resources will be focused on an old issue instead of providing new value to customers. This means that there’s no simple answer to the question of whether a debt is good or bad. Technical debt incurred in order to deliver an MVP application and validate business assumptions may be “good”. But “Reckless and accidental” technical debt is something you or your customers don’t want to deal with.
Technical debt in agile
The definition of done and QA (quality assurance) differ between agile and more traditional, waterfall software development.
In agile teams, the development process is divided into short iterations. Each iteration ends with value being delivered to the customer. So, when a feature is released (or is ready to release) it means that each iteration involves QA, and the code (and/or design) quality is verified regularly.
The main branch of the code is always ready to ship. New features are developed on separate branches that should include automated tests. Once a feature is complete and passes the automated tests, it is merged with the main branch. This process ensures that the technical debt stays under control, prevents reckless technical debt, and improves overall code quality.
In traditional “waterfall” teams, QA happens late in the development process. At that point, the risk of a product including layers of bugs is high, and the cost of fixing them is significantly higher than in the case of each feature being developed on a separate branch. So why would anyone do it the traditional way, you might ask. Well, going agile requires organizational changes across the whole enterprise that not every business is ready for or interested in. But that is a whole different topic, you can explore it in this article: The great dilemma. Agile or waterfall?.
When it comes to technical debt and the differences between waterfall and agile, in agile there is a natural emphasis on iteration and testing various metrics, but also on placing the product in front of real users, which makes the technical debt easier to identify at every stage of work. Thanks to that, it’s easier to spot, plan for and remove issues, before they become critical in a more mature product.
To sum up, preventing technical debt allows agile development and being agile is a way of preventing technical debt at the same time.
The cost of technical debt
As code debt increases, so does its cost. The effort needed to maintain and develop more mature products is generally higher. But when a development team has to face sizable code debt at the same time, that extra workload grows even faster. To estimate the cost of technical debt, we need to first understand the debt’s impact on project productivity. Then we can calculate the cost of the productivity we are losing by dealing with the debt.
The cost of technical debt starts with engineering time. According to Stripe, code debt consumes 33% of engineers’ time. The average base salary of a JavaScript Developer in the United States in 2021 is around $100,000 per year. For a 10-person development team, that leaves the business with a $330,000 annual cost. While that calculation is quite general, based on industry averages and heavily dependent on the size of the specific debt, it demonstrates the potential scale of tech debt and its influence on project budgeting.
To decrease the above cost, it would make sense to refactor the code and downsize the technical debt to a minimum. Again, depending on the size of the debt, that will require assigning developers to the task, which means time and money. The third of developers’ time spent on dealing with technical debt could be used to ship new features faster. This is what your competitors spend that time on, actually.
A healthy codebase reduces the time needed to deliver product increments, and each delay in a product release is a revenue loss.
Apart from the financial costs, increased technical debt influences morale in the engineering team. Being stuck working with buggy code that requires a lot of manual workarounds is frustrating for any developer.
How much technical debt is acceptable?
As with any debt, technical debt can be bad and good for you. Having debt is not a bad thing in itself. Maintaining income that pays for the debt is a business strategy that can work not only in real estate but also in product development. The trick is to balance it in a way that benefits your business in the long run.
Code quality and performance are crucial for a good user experience and future development. Speed and agility are essential to respond to market needs fast. Managing technical debt is about balancing quality, speed, and cost. Remember that and look for the sweet spot when making product development decisions.
One thing that is crucial for technical debt management but rarely exists and/or is updated in engineering teams, is documentation of the debt. A well-understood and documented debt is a debt that can be managed with informed decisions. A common practice is to document the debt in Jira as an issue and tackle it when slack time occurs.
Another important topic in code debt management is understanding the impact of its different parts on the business. Your technical debt may be located in multiple places in the code. It’s best to ensure that developers maintain a record of the dependencies in the codebase and the technical debt issues that can impact other functionalities. Repaying the most problematic parts of the debt will decrease its cost significantly, while dealing with bugs related to rarely used sub-features may not be financially viable.
Some of the strategies that can be employed to keep technical debt at an acceptable level are:
- Reserving a fixed percentage of developers’ time to repay the technical debt.
- Setting a benchmark for the amount of debt you can tolerate and adhering to that.
- Using quiet moments in the development process to repay the debt.
All of these can be used together, but the main requirement stays the same – to do it effectively, you need to understand your technical debt and its cost first.
In order to use technical debt for your benefit, have it documented and find the best way to calculate its cost. Only then will you be able to find the amount of technical debt that best suits your P&L.
Conclusion
How much technical debt is acceptable? Whether technical debt appears harmless or threatening, it is an indispensable part of any software product. Be aware that if you cannot control it, it only becomes more problematic and costly as a project scales up.
Learning how to manage your technical debt effectively may build your competitive advantage. Keeping in mind both its cost and potential value, hold yourself and your CTO accountable for making it a part of your product development cycle.
Some key takeaways regarding technical debt:
- Technical debt is natural as some conditions change over time and some assumptions may prove to have been wrong.
- Technical debt is inevitable, as every state of the product will become deprecated in a few years’ time.
- Technical debt needs to be documented as people come and go, and later it is not obvious which decision was meant to be a temporary one.
- Technical debt needs to be tracked, as it is very easy to neglect it for a long time until its amount exceeds what is manageable for the team.
- Technical debt needs to be acknowledged, as the customer needs to be aware that most of the decisions to speed up the work will incur some additional costs later on down the line.
- Static analysis can be used for early identification and monitoring of some of the signs of technical debt.
See also our previous article: how to deal with technical debt.
Share this article: