Tech debt occurs when we solve a software problem with our limited understanding of the business at the time. We start building a solution to get feedback as early as possible. By the time we deliver the software, we might have accumulated some burden. The debt metaphor comes into play. Instead of spending additional time on business requirements, we prefer to deliver software early. Hence, we borrow some. As the software grows, our limited understanding, as well as additional factors, become hurdles. We might be okay with those limitations for a while. We can pay interest where interest is extra time for a change. We then address the debt to cut down the interest we pay. As we deliver new features, we accumulate new debt. The debt will never be zero. Therefore, we should keep the interest payments affordable. If the debt becomes a huge pile, we might go into arrears. We would then lose the capability to deliver new changes. Typically, arrears happens when everyone firefights incidents and bugs.
Although technical debt doesn’t suggest poor quality software, the industry has taken sloppiness as a metaphor. When someone thinks about incurring debt, it’s often around lack of unit tests, inferior design, and hacks. Thinking of technical debt as an excuse for subpar software is counterproductive. There are three fundamental reasons for technical debt: deliberate decisions, outdated design, and rotten components.
Tech Debt Types
One might argue skipping unit tests is a deliberate decision. Hence, it’s part of technical debt. There’s no justification for such a move. We would immediately pay some harsh penalty. On the flip side, the aforementioned decisions are around business use cases. We might lack clarity for the needs and requirements of a system. Hence, part of the initial development is delivering the software to give a tasting and uncover unknowns. The developed software might not decently meet expectations. Though, It might be good enough for the time being. We incur a debt. Many more decisions later, we accumulate much more debts.
The second way to incur technical debt is the flaws in the design. There’s no way to get something right in the first place. We do our best at the time with the information we have. We make some trade-offs. Nonetheless, trade-offs might not work out well. Every time we want to add a new feature, the design would cause friction. Besides, refactoring accidentally poorly designed software might be challenging. Similarly, our architecture might not hold itself well against time. It then can cause a loss of productivity.
Last but not least, rotten components and services contribute to the technical debt. A software component might get more features and potentially gain more responsibility. The complexity comes naturally due to incremental changes to the system. Nevertheless, it can get to a point where the boundaries of the service might become unclear. Adding new features or clearing out bugs becomes time-consuming. Hence, it becomes a debt that we incur as long as we keep it running as it is.
Indicators
We need to pay interest for accumulated debt. Before the interest hinders shipping new features, we need to reduce the technical debt. Where do we start? How do we identify components or services to refactor? Although there’s no recipe, we can still look for a couple of indicators. Here are some of these indicators.
- The old tech stack is one of the causes of technical debt. Aged libraries and dependencies can cause hurdles in development time.
- There are automation tools that can show areas that might benefit from refactoring. Complexity analysis can uncover these components.
- A frequent number of incidents to a particular service or component shows how bad it has become.
- Many bugs reported for a particular component show it needs some servicing.
- The amount of refusal to work with a particular component from the team suggests how complex it has evolved.
Even though we can have some sense of technical debt for a particular part, we might not want to address it. We need cost-effective parts to refactor. We don’t have an infinite budget or time. Thus, we should carefully observe components that would help the most.
Engineering Health
Once we get a sense of what we want to refactor, we need a methodology. Instead of stop-the-world events, I prefer continuously addressing technical debt. Teams create technical debt issues such as refactorings and improvements. We then classify these as engineering health work. Engineering health is 20-25% of overall engineering work. We continuously evaluate and iron out the components of our software stack.
Although we would prefer ongoing treatment of tech debt, we might take over teams or teams with significant problems. In such circumstances, we might need to stop the world and take the debt to a manageable amount. Examples of such cases are bugs and incidents that the team can’t even address promptly. We can’t pay interest any more. We are in arrears.
Partner Collaboration
Engineering health work might not seem relevant to product development. Several partners might not understand why we need it. The key is to communicate it early and constantly. We point out possible outcomes due to a lack of technical debt activities. The other key is to prevent stop-the-world events. Teams should deliver without disruption. Making technical debt tasks part of the routine engineering work is easier than asking for a full stoppage. If we have to go into stop the world route, then we need to incorporate it into the company’s yearly and quarterly roadmap.
Nowadays, most of the stakeholders actually understand the concept of technical debt. The challenge is still though choosing engineering health work over feature work. The product work might have a clear justification such as dollar amount. The angle we should take is generally the velocity and stability. If we don’t pay the tech debt, we have to pay more interest. Hence, we would slow down. What’s worse, customers might experience more bugs and downtimes.
Conclusion
Software development lifecycle requires steady investment and maintenance. Technical debt is part of it. We identify components and services for technical debt activities. We then choose activities that require immediate attention or have high priority. We address these tasks on an ongoing basis. We communicate technical debt to our stakeholders and how we manage it. In consequence, we identify engineering health tasks, make them part of the engineering routine, communicate these tasks with our stakeholders and continue delivering high-quality software.
References
Article: The WyCash Portfolio Management System
Article: Managing Technical Debt
Article: Erasing tech debt: A leader’s guide to getting in the black
Article: 3 Main Types of Technical Debt and How to Manage Them
Blog Post: Dealing with technical debt
[…] Note that team/s can’t work on these projects full time. We need to take operational or engineering health work into […]
[…] its origins, and its ramifications equips us better for the future. We can then effectively address technical debt on an ongoing basis while promoting sustainable and healthy development […]
[…] a bit like tuning a car regularly, not just repairing it when it breaks down. Plus, dealing with technical debt is a big part of this, making sure we clean up old or clunky code so everything runs smoother in […]