We all have been there. The software engineering project starts slow, but then you pick up speed and quickly deliver new features. However, as time goes by, more and more things keep popping up. You deal with certain problems. More time passes, and things keep getting worse and worse. You see the same issues repeatedly.
Well, you've got yourself a severe case of technical debt. Its symptoms are often loud and clear: the system is tightly coupled and resistant to any change; you can hardly ever re-use the same parts of code; new features take forever to implement; bugs are piling up in the backlog. If you want to know what causes all these problems and how to deal with it - keep reading. In the article, we are going to look at:
- Definition of technical debt;
- Main causes of tech debt;
- Best practices in reducing tech debt;
- Major types of technical debt and how to deal with them.
What is technical debt?
Technical debt (TD) is a concept that describes the cost and/or additional efforts for new features or maintenance of the system. Think of it like friction in the car. The longer you choose to ignore it, the more money you will have to pay to fix it later. It is mostly invisible to people outside of the development team, but it manifests itself in two ways:
- difficulty and additional cost in evolving the system;
- difficulty and additional cost in maintaining the system.
Experts often describe technical debt as the result of false or suboptimal technical decisions that later result in issues with both maintenance and expansion of the system [1].
Technical debt is inevitable. Martin Fowler [2] once suggested using the technical debt quadrant in order to explain the nature of the technical debt. He suggested there are four types of TD.
Deliberate and prudent technical debt is the most harmless one. It happens when you have to ship an MVP to users to get money for further development and choose to deal with the consequences later on. In other cases, developers may be not aware of some best practices and not know that the chosen approach was not the best decision (inadvertent and prudent tech debt). Things get rather messy when you ignore the design or planning of the solution, which leads to reckless, yet deliberate tech debt. The worst-case scenario is when engineers don’t care or are incompetent, thus do not adhere to the best standards in development (inadvertent & reckless). But what leads to these decisions? Let’s dig deeper into the causes of technical debt.
What causes technical debt?
Now that we have seen the symptoms of having technical debt, let's dig deeper into the causes of this phenomenon.
Often, what we see is just the tip of the iceberg. And to separate consequences from causes, we need to address the reasons and circumstances that lead to technical debt. Typically, there are four root causes of technical debt:
- Business. Often, business needs stand in the way of the best practices in software development. Teams are pressured to release products faster or for less money. Sometimes requirements change in the middle of the way. The company needs to cut the costs.
- Change of the context. It often happens that requirements that made sense for the initial system, do not fit anymore. You may need to change the tech stack/tools or simply the technology you use got outdated.
- Development process. Technical debt also occurs when the initial concept wasn’t appropriately documented. People get confused about what should have been done and why. If you add insufficient resources and a lack of test automation to this equation, the technical debt will emerge.
- Team/people. This is the most complex cause of technical debt. It’s not about blaming people or pointing fingers, but about understanding what can be done better in terms of human resources. If there is a lack of experienced developers, ineffective communication between distributed teams, or resources that are moved from project to project - you are bound to get in trouble with tech debt.
So how can companies reduce the existing technical debt? Unfortunately, there is no universal recipe for reducing technical debt. Everything depends on your context, on how big the system is, how old it is, what business model you rely on, who makes the decisions, etc.
Things that work for small startups with 5 engineers, most likely will not work for a 100+ people team supporting an enterprise-level legacy system. However, there are some general recommendations that can help you reduce technical debt or acquire it less frequently.
Best practices to reduce technical debt
Depending on your situation, you may need to skip a step or an extra move, but all companies typically start in the same place.
1. Acknowledge tech debt
It often happens that companies acquire technical debt without realizing it or even benefiting from it. However, there is a tipping point when the technical debt is no longer a benefit but a painful issue that causes a lot of troubles. The earlier you acknowledge it, the easier it may be for you to reduce your technical debt.
2. Understand your technology adoption stage and identify the best approach to tech debt
Depending on the amount of technical debt, you may need to access your technology adoption stage. Most likely, it will define the approach to repaying technical debt.
Ozkaya [3] suggests that there are three strategies for managing technical debt:
- Do nothing. Sometimes technical debt is not a bad thing if it allows you to reach business goals. However, it is important to understand the consequences of not dealing with this issue.
- Replace the whole system. Sometimes legacy systems are too complicated, and there's no way you can fix them by adding patches or addressing only specific issues. It is a long and expensive process, but sometimes it is the only smart way out.
- Incremental refactoring (commitment to investing). This method allows you to reduce technical debt by paying attention to every single sprint. It might be expensive, but it definitely pays back in the long run.
3. Classify and document tech debt
The third step is to understand what type of debt you have and document it properly. You need to state the type of issue, remediation approach, responsible person, plus describe the consequences of not paying this debt.
Make sure to measure when and how your team is slowed down by technical debt. It will help you identify the business impact and transform an abstract concept into measurable tasks.
4. Align your backlog and track technical debt
Try to pay back your technical debt regularly. Technical leaders must constantly work with stakeholders to include technical debt review into backlog and schedule maintenance sprints when necessary. Wolpers says that Scrum teams should consider allocating 15-20 percent of their resources to refactoring code and fixing bugs every sprint cycle [4]. Make sure that you include related tasks into your backlog and prevent it from falling through the cracks and being forgotten about.
Technical debt is best controlled when measured continuously. Tools like SonarQube allow users to use metrics and rules to observe technical debt in time.
2020 McKinsey research shows that most companies spend under 20% of their tech budget on paying the technical debt.
5. Stick to the best practices
Development is often about finding the balance between ''what is right'' and ''what works''. Yes, we all have heard GRASP or KISS principles, as well as the characteristics of the good code. However, modernizing a legacy application means that you need to be consistent with the existing approaches. So you need to find the balance and adopt those best practices that will work best for your case
You should also adjust your definition of ''done''. Every team member needs to understand when the task is ready and it meets the criteria of acceptable and manageable technical debt.
For example, here at N-iX, we have introduced Centers of Excellence that help our clients and development teams implement and maintain the best software development practices.
6. Educate non-technical stakeholders
One of the critical aspects of managing your technical debt is ensuring that people who make decisions understand the importance of reducing technical debt. The more you explain why technical debt occurred and why it is essential to pay it down, the easier it will be to get them on your side.
Now that we have looked at the causes let's zoom in on specific types of technical debt.
4 major types of technical debt and how to reduce them
Back in 2014, a group of academics was concerned that the existing gradation of technical debt had nothing to do with the nature of the debt. These experts dismissed a traditional division of strategic vs. non-strategic debt and suggested a different approach. Their efforts resulted in a classification, published by the Software Engineering Institute as Towards an Ontology of Terms on Technical Debt. We built our list on the reflections of their work, focusing primarily on technical and code-related issues.
Architectural technical debt
This type of debt is about the design of the entire system. It typically affects the critical architectural requirements like performance metrics, robustness, etc. Why does this happen? Things like poor understanding of software architecture, the complexity of software systems, architectural erosion, and lack of understanding of software development life cycles (SDLC) create architectural debt.
How to address architectural debt? First of all, you need to assess the existing architecture. You can even have an external audit for a better understanding of the situation. Experts will analyze the current state of the system, define the scope for transformation, outline potential bottlenecks and risks, and find ways to address them.
If you are dealing with a legacy system and have difficulty scaling your product, you can also benefit from the adoption of microservices.
Code debt
This form of debt refers to issues found in the source code. Some of the most common attributes are so-called ''code smells'', i.e., long methods, code duplicates, and other similar symptoms. It often emerges when there’s a lack of code review, standardized guidelines, or lints.
Refactoring is the major answer to code debt. It helps you to modernize the system without changing the behavior of an application. You can also improve code review procedures and introduce the use of lints during code review and before pushing it.
Infrastructure debt
Infrastructure debt is mostly related to operating environments. It disguises itself in infrastructure code, causing numerous issues like lack of observability (a.k.a. monitoring debt), deployment issues, disrupted CI/CD pipelines, etc.
DevOps to the rescue. Not only can DevOps help you reduce operational costs, but DevOps also minimize the risks by ensuring that development, testing, and production environments are consistent.
Test debt
This type of technical debt covers general testing debt, lack of test automation, and defect debt. It includes lack of test coverage, poor alignment between test and actual code, unclear or immature design of test cases, etc.
To successfully reduce testing debt, it is vital to a) increase test coverage, b) test both positive and negative scenarios, c) introduce automation tests, and d)start testing as soon as possible.
Wrap up
Whether you have a legacy system or build a new one from scratch, acquiring technical debt is inevitable. It is a complicated issue that every company faces. Despite its nature, it is important to acknowledge its existence, document it, and pay it down. Make sure you are honest and vocal about this matter with both development teams and stakeholders.
How can N-iX help you reduce technical debt?
We can help you find the balance between reducing technical debt and adding new features at a marginal value that makes sense for your business.
- N-iX has extensive expertise in custom software development, software product development, and IT staff augmentation.
- We have extensive expertise in both Cloud and DevOps services, including Cloud adoption (architecture, migration, optimization), building and streamlining CI/CD processes, security issues detection/prevention (DDOS & intrusion), firewall-as-a-service, and more.
- N-iX partners with leading global companies such as Currencycloud and Globacap to help them launch fintech projects and leverage all the benefits of hybrid cloud in banking.
- The company has been listed among the top software development providers by Clutch, in the Global Outsourcing 100 by IAOP for 7 consecutive years, recognized by GSA UK Awards, included in top software development companies by GoodFirms.co, and others.
- N-iX complies with international regulations and security norms, including ISO 27001:2013, PCI DSS, ISO 9001:2015, GDPR, and HIPAA, so your sensitive data will always be safe.
Featured case studies
1. Managing tech debt in BFSI
One of our UK customers, which provides financial services to clients, owns and operates a peer-to-peer lending platform that's been around for more than 10 years. The platform was up for much needed upgrades and wasn't scaling according to the client's needs. Also, the platform contained a lot of legacy code. The client engaged N-iX to improve platform performance and detect and manage the existing technical debt. Here’s how we approached this request:
- We dedicated 20% of the sprint time to managing technical debt in every sprint. To speed up the process of getting everyone on board, we had several sessions with key stakeholders and showed how tech debt management can help reduce system downtime and decrease the number of critical or emergent bug fixes over time.
- The N-iX team has identified technical debt by conducting regular code reviews and static code analysis.
- Our experts have created a system that helps the team prioritize technical debt tasks depending on the time required to overcome it and the impact it may cause.
Depending on the impact on the system, technical debt is divided into the following categories:
- Technical debt with a high impact includes urgent issues that prevent users from doing their everyday tasks (like security issues).
- Technical debt with a medium impact involves known system vulnerabilities that are not critical to users.
- Technical debt with low impact consists of outdated user flows, which are rarely used. Overcoming this type of technical debt is not critical, but recommended.
To overcome the existing technical debt, we established regular code refactoring for improving the code structure, readability, and maintainability without changing its external behavior.
To prevent the accumulation of technical debt, we defined the code quality standards and rules for building APIs and backend services and set up a unified approach to overall code quality.
Overall, we have helped the client to increase the platform's security, reduce the number of critical issues, and accelerate the average development time by 20%.
2. Reducing tech debt through migration and change of architecture
One of our clients, a Fortune 100 company, has chosen N-iX to help scale an existing system. It was a logistics platform that was supposed to improve the logistics between its 400+ warehouses in over 60 countries. It was used for several months and appeared to be ineffective. The system was hard to scale and resistant to any changes or introduction of new features due to its monolithic architecture. Although our client had a vision that they needed to migrate to microservices, they did not have enough in-house expertise and resources to address multiple technical issues and make the platform more efficient and scalable.
Our Solution Architect designed and presented a new cloud-native infrastructure of the platform, as well as a suggested tech stack and the most efficient roadmap. Moreover, migration to microservices allowed us to add new SaaS services for our client: anomaly detection, delivery prediction, route recommendations, object detection in logistics, OCR (optical character recognition) of labels, Natural Language Processing for document verification, data mining, and sensor data processing.
Our experts are also building the DevOps pipeline from scratch, setting up the environment for development and QA, and introducing CI/CD processes that allow us to easily assemble and deploy microservices to the environment.
References and recommended reading:
- Sustainable Software Architecture. Analyze and Reduce Technical Debt by Carola Lilienthal
- Technical debt by Martin Fowler
- Managing Technical Debt: Reducing Friction in Software Development by Philippe Kruchten, Robert Nord, Ipek Ozkaya
- Technical Debt & Scrum: Who Is Responsible? By Stefan Wolpers
- Rubin, Kenneth (2013), Essential Scrum. A Practical Guide to the Most Popular Agile Process, Addison-Wesley, p. 155, ISBN 978-0-13-704329-3
- A Longitudinal Study of Identifying and Paying Down Architectural Debt. In Search of a Metric for Managing Architectural Technical Debt