Here’s a typical scenario in many development teams all around the world: The sprint is nearing completion, and the profile on that burndown chart remains at the same crazy angle. As it was in the last sprint, and the sprint before that. Same as it ever was. (Is that Talking Heads song stuck in your head, now?) The testing team has been mostly idle, waiting for the signal. At the daily stand-up meetings, they continue to hear rumors about various issues, impediments, and obstacles. Frustratingly, there is still no code ready for testing.
Finally, the day arrives for the demo and a review of the sprint. The developers declare that all the stories are done, and everything is ready in the new build. It’s time for the QA team to get to work! Oh, and only 24 hours are granted to test everything in this sprint. The lead says that there will be a complete internal demo tomorrow afternoon, followed by an external demo to the stakeholders the next morning. Better get cracking, testers. This isn’t the first time. So, without even performing a single test, each tester knows that they’ve taken on more water into the boat—a boat that is already swamped. With the highest degree of certainty, the application has accumulated even more technical debt.
What is technical debt?
When facing a challenge that requires a modification to the software, a development team has two options. The team can agree to delay the release and make a solid effort now to write additional code that is both durable and scalable. Or, the team can respond with quick, suboptimal—and probably messy—fixes that will sufficiently address only that problem. This quick-fix option will eventually require a future intervention from developers to repair, replace or clean up the code. That option generates technical debt: a temporary compromise the permits the fulfillment of higher-priority business objectives. The effort to do it right is deferred. Repayment of this technical debt will eventually require a proper replacement of the temporary fix that will integrate solidly with the entire application or system.
Simply put, technical debt occurs when a development team decides to fix it later. Anything that is intentionally deferred is technical debt, which will also require an interest payment when it becomes necessary to redesign and rewrite a better solution. It’s important not to confuse technical debt with bugs that need fixing. Bugs correspond to existing software functions, not missing functionality. The team manages bugs differently than technical debt. However, technical debt is not only about deferring a reconstruction or a refactoring. It’s the entirety of what the team owes to the product, such as current database schemas and missing tests.
Technical debt also includes performance and scalability issues such as:
- Security functionality that has been deferred or bypassed
- Neglect of coding, industry, or engineering best practices
- Deferred upgrades to technology
- Development workarounds that result in unnecessary complexity, duplication, unused components that remain in the application.
Another way to be sure of increasing technical debt is when you hear statements like these:
- “It’s possible that you’ll break Y if you change X.”
- “We thought that there was a test for this!”
- “Please, please don’t touch this code. Last time, it took many weeks to fix.”
- “Do you know if there have been any communications about that bug?”
- “Why isn’t there any documentation on the file specifications?”
- “There’s no way we can upgrade since our team now has no one who understands that code.”
- “The server is down. Can you reply with the new location for the backups?”
Technical debt and quality assurance
Many QA managers tend to view technical debt impulsively—as the natural consequence of focusing all effort only on the current sprint. This tendency leads to achieving necessary test coverage by mostly manual approach and often leaves no time to consider how automation might serve to mitigate the accumulation of some technical debt and help in managing it for the future.
Metrics such as coupling, cohesion, coupling, and complexity are useful in quantifying technical debt. Another way to view technical debt is to consider the number of defects that have been deferred in a product that has been released, the number of accepted requirements that remain unsatisfied, the number of tests that have not been built to validate new functionality, the number of tests that have not been added to the regression suite, and documentation that has not yet been written. Quantifying technical debt is a matter of estimating the effort necessary to address all of these omissions and counting the costs in time and money.
Many developers will approach technical debt from the perspective of writing and extending code. Quality assurance staff tend to pursue reductions in technical debt by managing defects as follows:
- Defect prevention — Preventing various types of faults from becoming part of the software product. This includes eliminating technical ambiguity and rectifying misconceptions about specific functionality. This also includes preventing any faults of incorrect or missing human actions.
- Defect reduction — Detecting and remove faults that are present in a software product or system. Typically, this is done by inspection, testing, static code analysis, observing dynamic behaviors, or monitoring operations during execution.
- Defect containment — Containing failures to limit the intensity and extent of impact. This includes applying fault tolerant techniques that sever the link between the fault and its failure.
Minimizing technical debt reaps long-term benefits
Limiting technical debt is important because it’s an essential aspect of the enduring commitment to software quality, good user experience, and customer satisfaction. As more unpaid technical debt accumulates over several development cycles, the quality of the deliverable will decrease.
Quality software is not expensive. From inception through to total cost of ownership, software development efforts are faster and less expensive to build when the team tenaciously pursue quality work products and final deliverables. A big part of this is carefully managing technical debt—which must be a team effort. This effort requires forward-thinking that deliberately keeps a long-term focus.
If they step back and think about it, developers and their managers know that it’s necessary to spend time writing quality code from the start. There is a price to pay otherwise: writing spaghetti code and hacking an interminable sequence of quick fixes to push something workable along the pipeline only results in a terrible mess that needs untangling later. This is senseless unproductivity. It is far better to write every line of code with a view to high quality, as much as possible. This will minimize technical debt and add much more value to a software product.
Tracking items that may be technical debt
Much like monetary debt, it’s important to know the amount of debt that you’ve been accumulating, and what steps are necessary to reduce it. With software technical debt, you’re always likely to have some amount present. It’s sensible to maintain a task list consisting of prioritized items such as cleaning up the code base or ensuring all relevant tests will be written following release of the product. This has value if for no other reason than the entire team can review the list and realize how much technical debt is accumulating.
In addition to tracking technical debt as it accumulates, it’s also important to watch for additional legacy code improvements or refactoring optimizations. Taking all of the technical debt together, work with your management and make a plan for allocating a portion of future effort to reducing this debt.
Tracking, communication, and planning aren’t very useful if the team doesn’t actually commit to repaying (minimizing) its technical debt. It’s vital to regularly take steps to reduce this debt while prioritizing according to both impact and age:
- Impact — There’s a big difference between a subsystem that has no test coverage and a segment of code that lacks commenting or good formatting. Prioritize work to reduce technical debt that is likely to have the most significant impact.
- Age — Technical debt accrues interest. The longer that code remains in poor condition, the bigger the impact is likely to be. More bugs and integration issues will correspond to this such code. Also, long delays will result in developers forgetting about the code and how best to improve it.
There are various ways to repay the debt:
- Partially repayment — Rather than implementing the best solution that will likely require more effort, build or reconfigure a different solution that reduces the interest that is accruing on that debt.
- Repay it in full — As time permits, replace the code or refactor it to optimal quality.
- Don’t repay — Simply make the interest payment. This may be a good approach if the cost is low, the code is rarely changed, and the replacement cost is too high.
Technical debt is an inevitable attachment to each and every software system. It’s really futile to make any attempt to avoid it entirely. Rather, development teams should focus on managing it effectively. Proper management and repayment will help your team consistently release quality software products and likely improve productivity over the course of several development cycles.