The economy of tech debt
Most articles about tech debt are pretty much theory only with lots of interesting philosophies. I’d like to approach this topic in two steps:
- The first part of this article is all about theory: what’s a tech debt, what’s not, and what’s the root causes and impacts on product and team.
- In the second part, I’m going to give you a hands-on approach to how to manage it so you can improve your product time-to-market.
What’s Tech Debt
Tech Debt is a concept in software development that reflects the implied cost of additional rework caused by choosing an easy (limited) solution now instead of using a better approach that would take longer.
It was introduced by Ward Cunningham with the following words:
“Shipping first-time code is like going into debt. A little debt speeds development so long as it is paid back promptly with refactoring. The danger occurs when the debt is not repaid.”
So, in fact:
- Is not something necessarily wrong, nor is it inherently right
- It is potentially dangerous when left unpaid (it can stack up quickly and easily) This means we can accept some degree of tech debt during the development and be sure to constantly keep it in check.
What’s Not Tech Debt
It is often much easier to put all the mess under the tech debt umbrella, but there is some stuff that is not eligible as tech debt, like:
- Legacy Code As long it’s tested/properly written, legacy code is boring code you should not have fun rewriting once again.
- Trending Techie Don’t be such a baby; if it’s not the FoTM it’s great anyway.
- Multiple Design Patterns As much as you can appreciate a common design pattern inside a product, as long as the code is properly written, it’s not a problem nor a tech debt
- Code Guidelines Same of above, feel free people having some uniqueness
Before you consider any action, you need to measure it: a good metric to evaluate tech debt and plan any action is the amount of unplanned work.
Not all of the technical debt is worth repaying Usually when the time spent refactoring exceed the benefits it’s probably a better idea to just ignore the debt (note: you should still keep the track of it, where it lays and why you have decided to not address).
Unplanned work is any task due to bugs, service interruptions, or flawed software designs.
Statistically has been shown that unplanned work should represent from 5% to 15% of the work of an organization.
When it goes higher, it should be accurately monitored in order to avoid further problems.
Unplanned work, and therefore tech debt, have 3 different root causes:
- Time Pressure We know deadlines are part of any business. Without setting deadlines, everything is bound to collapse. However, time pressure inevitably leads to corner-cutting, which means tech debt. Beware of artificial ship dates because they lead to hidden costs.
- Team Changes Teams are living creatures; they change over time (and that’s good news, indeed). When new people come into the team, they typically have steep learning curves to learn what has come before. Learning is far from perfect.
- Pivots Engineering teams hate that, but pivots are a fundamental part of business reality. The alternative to pivoting is flogging a dead horse. However, pivots lead to stretching existing implementations to fit new objectives; eventually, things may break.
Mounting tech debt means spread of unmanaged complexity, resulting in less business value being unlocked.
Simpler tasks require unnecessary cognitive load, which means more [shitty] work to get done and longer delivery times. Moreover, the result is anything but good, and the situation is going to get worse once new debts are going to be added.
Impacts are on the tech side:
- Performance/Stability The responsiveness and the overall stability of the application
- Changeability Likelihood of introducing new defects while changing existing features or adding new ones
- Security The ability of your application to prevent unauthorized intrusions
… but also for the team:
- Morale The mess of tech debt slows developers down and sometimes even prevents them from doing their job. It can make it difficult to be proud of the work you’re doing as a lot of time is lost dealing with annoying problems (moreover invisible to product stakeholders).
- Transferability The ease with which new developers can onboard into the product.
- Retainability 51% of engineers consider quitting their job due to tech debt (read more)
Learn how to Communicate, Manage & Minimize the Impacts of tech debt in your code.
Discussing tech debt with nontech people may be hard.
The secret here is to speak the language of business: Persuade your stakeholders that time improving the product behind the scenes will increase productivity, sustainability, and scalability.
- The focus is always on cost and time instead of quality Unmanaged tech debt increase the volatility in the marginal cost of features (aka. longer development times for new/existing features).
- Collect Data Measure measure measure: the number of bugs reported and accumulated per week, emergencies that occur per week, and so on. The point is to deliver your message along with measurable data. Because data are money.
- Invest to save Investing 10-15% of our time in code quality help to reduce developers’ turnover. How much does it cost us to replace a leaving dev?
Make the waste visible
The difference between financial debt and technical debt is visibility. It’s not always clear how much technical debt you have at any time. A tech debt follows 3 different stages:
- Unknown As you may imagine, this is tech debt that you simply haven’t identified and have no idea it even exists. Uncertainty makes this debt the most dangerous type: you can’t consider it in future tasks without knowing of its existence. This is the reason for missed deadlines, blocks, and unforeseen issues.
- Dormant You know about it, but you don’t plan to address it now. You can spot this debt while working on something, eventually in some old codebase. The best thing you can do is to take a note and face it later in the distant future. It’s perfectly healthy to have.
- Active You know about it, it’s defined, and you are able to plan a schedule to fix it in the foreseeable future. A common example you may incur active tech debt is when introducing a new feature following a strict deadline; the result may be less-than-ideal, but you plan actively fix it in a minor update after the release. Also, Active Debt is perfectly healthy to have.
As tech team, you’re like gardeners managing a green park along each season of the year. It’s springtime: you enthusiastically spend a large sum at the garden center and work your soil adding new plants (features) and architecting each garden (organizing your infrastructure).
Discipline is a fundamental part of your work.
You must be diligent, regularly tame and tends their urban oasis, ripping out weeds, and ultimately end up with a beautiful park (congrats, you are managing tech debts!). Failing to do regular maintenance, you eventually end up with a mess of dead plants everywhere, a dense forest, and frustration.
The goal is to make the waste visible, then schedule a plan to fix them.
Like working in a garden, software needs time and resources to keep it sustainable and avoid long-term costs.
The biggest symptom of tech debt in an average software is a specific issue or issues correlated to each other (by technical dependency) with a moderate/high occurrence-rate.
As with any good plan, it starts measuring the impact.
You can’t plan or prioritize anything without knowing its impact.
Can’t avoid it, your job is to monitor where it is easy to find.
Once you spot it, take a deep breath and avoid fixing it immediately.
Annotate it in your backlog along with a meaningful description or a grade.
Tracking tech debts has a similar lifecycle of any product activity. Start grading your debt on 4 levels with a values between 1 (light) to 5 (heavy).
- Severity: defines how much the user is disturbed/prevented from using your product. Show-stoppers or tech debt inside core parts of any foundation layer should be addressed urgently (level 5). Users rely on it, and you are likely to want to continue to develop those features. certainly, continuing to build on shaky foundations is far from an optimal solution.
- Occurrence: the number of times any user encounter the issue. Be sure to correctly link the tech error with the issue (1-5 at least in the top 5 of tracking occurrences)
- Dependency: How much the issue is linked to other dependencies (aka. you should also touch other parts of the code).
Now put all issues in an ordered list with those total grades.
That’s your priority.
Allocate time in each cycle
In my team, we have reserved part of any sprint (2 weeks) for addressing tech debt. The amount of this time may vary depending on a lot of factors (how big the activity is, pressure to deliver other product-related features…), but you should consider a dedicated slot (~20%) for each iteration. If you can’t commit to a fixed amount of time for each iteration, use the end of a quarter as a suitable time to do this.
Beware Artificial Deadlines
Deadlines can be real or artificial. Most of the time, artificial deadlines are used to set boundaries for all people involved. However, the hidden cost of an artificial deadline is a tech debt: while you think you can address a debt just after the release, instead, you may end up using the time supporting early changes and defects found.
I’m sure you land in this paragraph hoping for a simple and fast answer. At this time, you should have learned you can’t avoid Tech Debt completely. It’s an inevitable part of shipping a product.
But don’t be discouraged; it doesn’t mean you can’t take some actions to minimize it:
- Consistently refactoring the codebase In our team, we often joke about continuous refactoring, but a disciplined approach to refactoring leads to a codebase that is low-maintenance, highly readable as well as highly functional, all while bringing down technical debt.
- A common known enemy Engineers waste more than seven hours per week on tech debt which is often invisible to stakeholders. Communicate the value of paying down technical debt to the product owner and stakeholders in your organization to make sure you have a common understanding.
- Be aware of ninja devs Finding talent that can create a working solution is not enough: it is also necessary to find talent that diligently creates a solution that is as sustainable as it is functional. Be aware of the ninja devs in your team.
- Encourage cross-collaboration Everyone should have a robust understanding of how core stuff works in the project; pair programming and cross-reviews must be part of the workflow.
- Take time Expect to spend a chunk of time/money after each major feature release to address the Tech Debt accumulated during the push to get the feature over the finish line.
- Don’t write twice MVP (Minimum Viable Product) is a critical part of each fast-moving business. You can’t afford to write things twice: produced code should be part of the product for a reasonable amount of time, so you need to make a plan even for an MVP. This doesn’t mean over-engineer; it means engineer once.
- Tech Debt is an evitable output of any development activity. Not all of the technical debt is worth repaying (see time/benefits – check out this article)
- Consider investing 15-20% of each iteration for maintenance and improvements requested by your team (read more)
- Tracking & classification is fundamental; instill good habits in your team (read more).
- Speak to nontechnical stakeholders using business terms (check out this article for some examples)
- Tech Debt also impacts team morale (see “State of Technical Debt 2021”)
- Propose a Tech Wealth culture in your organization