What is Technical Debt & Why It Matters
When we start developing any new modules from scratch, the development speed is significantly faster — mostly due to limited amount of dependency, as well as not as many inter-dependent features.
However, as we add more and more features with every development sprint, we also add a bit of technical debts— in the form of TODO, FIXME, eslint-disable-xxx, code to refactor, workarounds, etc.
Generally, they can be categorised as follow:
However, often, due to the needs of the business, technical debt is unavoidable.
The popular 4-Type classification by Martin Fowler can be used to simply the type of technical debt:
Initially, technical debts were relatively insignificant and do not show any huge impact to the overall development.
However, they start to add up over time. At some point in the future, it will reach to situation whereby it takes more time to handle, update and test the existing code and features, than to add new features due to the accumulated technical debts and code complexity.
Remember the time where you have to update so many places just to change one simple logic?
…Or spending so much time to do testing and making sure nothing breaks after changing one simple line of code?
Managing Technical Debts
There are two parts to managing the technical debts:
- Detection and Measurement: Defining how the technical debts will be measures, prioritised and tracked.
- Repayment: Establishing processes to manage and resolve (pay back) them efficiently and regularly.
However, unintentional technical reasons are hard to detect and they could still add sizeable amount of technical debts to the overall situation.
Hence, processes and guidelines should be put in place to minimize and prevent those unintentionally caused technical debts as well.
Detection & Measurement
This section defines how technical debts can be measured, prioritised and tracked.
Test Automation
A good unit test and test automation coverage can help to ensure things can be changed quickly (modifying features, adding features, etc) without having to spend too much time testing each affected area manually.
Static Code Analyzer
This would be the easiest to get started.
Try to customize them to suit the needs of the team over time. Even though they are not perfect and often produces a lot of false negatives, they would help to take care of the majority of the common mistakes.
In addition, a lot of static code analyser support code complexity checking. A complex code is more likely to break and causes bugs when making some changes or when new features are added.
These tools can help reduces the workload of reviewers significantly and also make the development process a lot more efficient since now the reviewers can focus on important stuff during the PR review — which bring us to the next topic.
Pull Requests
This is where majority of technical debts could be detected.
Pull Requests isn’t something that we are trying to get past the reviewers.
Instead, they are the perfect time to get your work have a look at by someone else and get feedback — we can improve and learn so much from those especially since the reviews are done by seniors.
If you make any tradeoff to get the development done faster, discuss with them about the trades-off (preferably, it should be discussed even before doing the implementation).
This is the best way to to detect those inadvertently caused technical debts and prevent them.
Team Progress Rate / Velocity
The progress rate of the team could be an indicator to the overall technical debt.
Are members taking more and more time to implement new features?
Are there more bugs generated?
Investigate each of those causes and they could be indicator of too much technical debt being incurred as shown in the [Technical Debt & Time Available for Feature Development].
Knowledge Sharing and Training
This would be the best long term solution to the problem.
If everyone knows and understands, it effectively makes members from incurring technical debts without giving it second thoughts. In addition, this is the best way to help reduces the unintentional technical debts.
Repayment
So, how do we make sure we replay our technical debts systematically. We have to establish processes to manage and resolve (pay back) them efficiently and regularly.
Make It Visible
We tends to forget or ignore what we don’t see overtime.
So, make sure everyone knows and understand the current technical debts. Try to analyse them and estimate the efforts required as well as the benefits of resolving them visible.
As an added benefit, it will also be helpful for stakeholders to understand why the ROI for resolving them would be worth it as well.
“Now” Is Usually The Right Time
Every time we are working on something, we have two choices.
- Do we build more on top of currently “shaky” foundation (with lots of workarounds and hacks);
Or
- Do we spend a bit more time to rework it and make it stable?
If there is no tight timeline and if there is opportunity, it’s always better to repay the debts earlier before they incurred even more interests and debts.
Talk to the stakeholders and discuss the pros and cons of reducing the technical debts while you are at it.
Slow And Steady
As engineers, we often think “we can resolve all of them at once later” as we don’t like to switch context and we love being in the zone while developing.
“Discuss once and fix them all” is our usual approach.
But it put a lot of stress to everyone in the team when we are trying to resolve one big chunk at one go — from developers to QAs. Instead, aim to resolve it slowly, but consistently over time — preferably set aside some time for it in each sprint.
Everyone Should Contribute
Everyone — regardless of seniority — should help with the repayment of the debt.
This helps to ensure everyone understands the consequence of technical debts, and at the same time, let members see more of the existing code base and a chance to work on them.
It’s an opportunity to learn from our past “mistakes”.
Tackling The Root Causes & Understanding The Consequences
Even with different monitoring and repayment processes in place, without trying to understand or resolve the root cause, those processes would not be very effective at managing and reducing technical debts.
Some of the common root causes include:
- Time pressure (having to meet deadlines);
- Unclear and/or unnecessarily complex technical design;
- No guidelines/standards or not following the guidelines;
- Lack of technical skills and suboptimal codes;
- Delayed refactoring;
- Lack of or insufficient automated test coverage, etc.
What’s The Most Common Cause?
Ultimately technical debt is usually caused by lack of long-term vision and communication. There will always be scenarios where we are forced to deliver results within limited time (time pressure).
Often, it is also due to the roadmap design and careful planning as well.
When a feature is designed or planned in roadmap, an initial estimate is made roughly. Unfortunately, from time to time, we miss to revise that estimate or the scope of the feature along the way, causing the workloads in sprints to become heavier and deviate from original estimations by a huge margin.
This will unavoidable causes a lot of time pressure during the development resulting in technical debts being incurred in order to finish as planned.
However, often times, the consequences of doing so was not shared with the stakeholder, which means they couldn’t make informed decisions about whether such technical debts are worth it or not.
In some worst case scenarios, they might not even be aware about such trade-off happening.
Is Technical Debt Really That Bad & Should We Try To Avoid Them At All Cost?
But at the same time, it’s important to understand that technical debt isn’t inherently bad — depending on each case.
It is, however, crucial to understand the consequences and manage them. We don’t have to avoid every easy and dirty options and make our code perfect. “Done is better than perfect” especially with agile development.
After all, we don’t want to build a perfect solution nobody want to use. We want to build a working solution that everybody wants and then improve on it.
Essentially, it is one of the merits of agile development — to release, learn, adapt and improve.
Key Takeaway
The bottom-line is we don’t always have to avoid technical debt.
We do have to make sure that we are considering the cost of incurring such debts, manage and try to repay them.
As Robert A Fornal puts it —
“Acquiring technical debt may help to achieve a short-term goal, but one should have a plan in place to address it moving forward.”
What do you think? Let us know your thoughts in the comments section below.