“Technical debt” describes the trade-off between delivering new features quickly and having a robust, reliable system.
It’s an inevitable part of the software development process, but we must manage it properly.
In this article, I’m going to cover…
Modern engineering teams can radically improve performance by understanding these different types of tech debt and how to manage them. Those performance gains include code quality, productivity, morale, and reducing the negative impacts of technical debt.
Code debt is the technical debt that accumulates when software development teams cut corners in code production.
Code debt occurs when engineers use shortcuts, increasing complexity that must be addressed later. This complexity can be difficult and expensive to pay off over time, as existing technical debt and code must be refactored or replaced with a better solution.
In some cases, neglecting to address code debt can lead to bugs and security issues in the future.
Martin Fowler, a well-known software development expert, has described four types of code debt. He invented the technical debt quadrant to explain the complex matter of technical debt and how to classify it.
Reckless & Deliberate:
This type of debt results from a lack of understanding of the consequences of taking shortcuts in the code. However, you deliberately take shortcuts without considering the long-term implications.
Example: You can take on technical debt to meet tight deadlines, but don’t create a plan to pay it back.
Reckless & Inadvertent Debt:
This “Reckless & Inadvertent Debt” approach to technical debt refers to “things you should have known as a developer but didn’t”. Understandably, an individual developer doesn’t know everything in their domain. However, a team of developers should understand their domain well and its coding standards and best practices. A team constantly developing sound industry knowledge can avoid accumulating this kind of debt.
Example: A team of JavaScript developers don’t apply their knowledge of good code design patterns. The application becomes riddled with bugs.
Prudent & Inadvertent Debt:
This is tech debt you have accrued even though you took time to improve your team’s skills and implement best practices. Sometimes, technical debt can’t be avoided and can only be learned by doing things. In other situations, you’ve implemented outdated approaches as the IT industry moves forward rapidly. Martin Fowler states this is the hardest quadrant of technical debt to anticipate. It’s impossible to detect this type of debt even when implementing metrics to measure technical debt.
Example: You migrate your application architecture to a monolith while the industry moves towards a microservices architecture. To anticipate this type of debt, you can build many small prototypes to test new technologies before fully committing to a new approach or technology. This way, you can gain valuable knowledge without risking technical debt, only adopting a new technology when it offers clear benefits.
Prudent & Deliberate Debt:
Prudent and deliberate tech debt is the technical debt you want to leverage to ship faster. It results from thoughtful decision-making, balancing the potential risks and rewards. Engineers and product managers consider the possible consequences of their choices and plan accordingly, anticipating worst-case scenarios.
Example*: A startup might opt for this approach to quickly bring their MVP to market to validate the product and secure funding. They prioritize the core functionality of their product with a basic interface. They plan to invest more in a polished product when they secure funding*.
Here are three practical strategies you can implement to avoid technical debt in your codebase.
Track and prioritize high-quality issues
Good tech debt management starts with tracking high-quality issues. If you don’t know what technical debt you have, you can’t prioritize and fix it. By fixing the most impactful issues, you can improve the quality of your codebase and prevent introducing new problems.
It’s essential to use the right tools to track high-priority issues. Proper tools make it easier for me to identify and track high-quality issues without switching tools and adding a lot of context to a new issue. By creating issues directly in my IDE, context gets automatically added and becomes more visible to other developers in my team.
Allocate 15-20% of every sprint to tech debt
Continuously allocate resources to addressing existing technical debt. It allows you to respond quickly to technical debt buildup, reduce technical debt and ensure the code remains maintainable and efficient. You can use these resources to fix bugs, upgrade the code architecture, or improve code performance. Focus on issues that directly impact code quality, morale, performance, or security. I suggest choosing a theme for each sprint.
It might be tempting to fix easier, low-hanging fruit. However, these issues have a negligible impact on code quality. They might even be undone by the adverse effects of not prioritizing high-quality issues.
Technical debt can slow down development processes, making it difficult to deliver new features. To maintain feature velocity as your codebase grows, you should commit 15-20% of your resources to address technical debt each sprint.
Automate the monitoring of technical debt
The technical debt quadrant showed that “Prudent & Inadvertent Debt” can still occur. However, we can detect the three other types of code debt by implementing metrics to measure them.
To get started, you can measure a few valuable metrics: code complexity, code duplication, code churn, and bug density. This last metric is especially valuable because it tells if the number of bugs per unit of code increases. If you notice an increase in a specific area of your codebase, analyze code quality carefully to understand why more bugs occur. Automated tests can help you spot these issues.
Documentation is an essential aspect of your product and provides information about its design, core logic, and functioning.
Inaccurate or incomplete documentation can lead to confusion or misunderstandings among your team members.
For instance, developers might make wrong assumptions about the code when your documentation is outdated. They then accidentally introduce bugs or new code debt.
Avoid documentation debt by implementing a documentation process. Regularly reviewing your documentation or for each release ensures your documentation stays in sync with your code.
You accumulate security tech debt when you accrue security vulnerabilities through your software development process. Neglecting this type of technical debt can have severe consequences for your company and its customers if malicious actors exploit it.
The best practices for addressing security technical debt involve proactive risk management, regular security reviews, continuous testing and monitoring, and continuous education.
Engineering tooling refers to the various tools and technologies you use within your engineering team. Not documenting essential processes related to your engineering tooling may lead to engineering tooling debt.
For instance, you need a formal process document describing how to tag and release a new code version. Otherwise, each developer has their own approach to releasing code, creating a window of opportunity for mistakes. To give a concrete example, an engineer might forget to execute end-to-end tests, unknowingly releasing code that contains bugs.
It’s crucial to write down important processes related to engineering tooling and teach engineers how to use the tool.
Technical debt can be persistent once you encounter it. There are many types of technical debt you should look out for. The most apparent type of technical debt is code debt. However, you can also encounter documentation, security, or engineering tool debt.
Modern engineering teams absolutely should accumulate tech debt. That tech debt should be taken on both deliberately and prudently. Manage tech debt properly using the right tools.
Also published here.