What is technical debt?
Technical debt, also known as code debt or design debt, is a term used in software development to describe the cost of additional rework caused by initially choosing a quicker delivery over clean, efficient code that would take longer. Essentially, it refers to the compromises made in project speed over good coding practices, which accumulate ‘debt’ that must eventually be ‘repaid’ with interest, in the form of time, money, and resources.
Tech debt is used and defined to include a wide variety of different possibilities with what is wrong with your code. Ranging from legacy code, missing or incomplete documentation, bugs, etc.
The concept is borrowed from financial debt where one is loaned money to buy something one wants now when you do not have the money for it and will have to pay for it later, with interest.
We all know interest can be high and may always increase!
Arguably technical debt, similar to financial debt, may not be a bad thing and can be used to progress a project forward.
Still, eliminating technical debt from the start of a project is recommended because it creates software entropy if it is not dealt with in a decent amount of time.
Thinking of tech debt as a necessary evil to move things forward generally results in insufficient prioritization of the necessary tasks to correct and fix it.
As one part of the codebase is changed, there is often a need to make calculated updates to other parts of the codebase or adjust your code accordingly to other areas of the code or documentation.
If you do not make the necessary changes now, those issues will continue to accrue interest until they are paid or fixed.
Technical debt in agile
Technical debt in Agile development refers to the cost of delaying essential work tasks during the development of a software project.
Agile development depends on speed and software features need to be functional in continuous development. Prioritizing speed and delivery over quality assurance and best practices.
Implementing quick sprints with short deadlines means that code may not get the necessary review needed and cause low-quality code. Often, they prefer new features over bug fixes and other needed fixes.
Even though Agiles' main purpose is to increase forward motion by speed, the lack of tackling bug fixes eventually reduces forward motion as the issues accumulate.
Technical debt in scrum
Technical debt in scrum, similar to agile, refers to the implied cost of work or rework by going with an easy, quicker, or more convenient solution now instead of using a better approach that would take longer.
Scrum is an agile project management framework that is supposed to help structure and manage teams, typically through a product owner, Scrum Master and developers with different responsibilities.
The way Scrum is structured, removing and eradicating technical debt is supposed to be built into the next sprint.
This involves controlling and paying off technical debt in order to ensure that developer velocity and productivity is maintained.
Each sprint is supposed to be designed to allocate time and resources in addressing technical debt which can be achieved by adding tasks for reducing technical debt in the backlog to make sure they are prioritized and worked on by the teams as needed.
Not managing technical debt goes against scrum principles of adaptability and deliverability and can block the team's progress; making the codebase harder to read, maintain and extend.
Some of the issues that arise are who is responsible for identifying, measuring and dealing with tech debt.
What causes technical debt?
Technical debt is typically caused when software development choices are made that are not up to the recommended or needed standards when it is moved to production. There are some amounts of technical debt that are basically inevitable but can be greatly reduced by utilizing code reviews.
Causes of technical debt include:
Ongoing development
With companies and code constantly changing, they operate in long or continuous periods of project improvements that over time make old solutions inefficient.
Modern software applications generally include several programming languages, development frameworks, and libraries, among other external resources.
The support, or lack thereof, can greatly impact those applications and their effectiveness.
Lack of definition
This is when development begins before any designing occurs.
If you do not clarify or establish a baseline of what constitutes technical debt or if requirements are still being established during the dev cycle; then what was created at the start may not be what is needed by the end of the project.
Business pressure
With the constant pressure of businesses trying to stay afloat and remain competitive and financially prosperous, they may release or produce something that is not quite ready yet in order to get it out there or be first in the field.
You see this with website and app launches that crash or have glaring glitches and usability issues.
With business pressure remaining constant, updating and fixing these problems may always remain in the development backlog.
Lack of technical knowledge or comprehension
Even really savvy business people can be unaware of tech debt and blind to the complications that arise as they strive to push out and release update after update while focusing on the product and bottom line.
Coupling of software modules
Where the degree of interdependence between software functions is not independent of interchangeable modules and is unable to accommodate changing business demands.
The lack of a test or validation suite
Allows swift and unsafe jerry-rigged bug fixes without proper test cases to test the software program and ensure it operates as expected.
Lack of collaboration
Where vital knowledge is siloed between departments, teams, and individuals. This causes business productivity to diminish through a lack of communication, training, and mentoring.
Simultaneous development
Within many organizations, development teams may be working on various branches at the same time leading to a lack of code cohesion when the finished product is merged into a single code base.
The more code creation occurs in siloes, the more technical debt emerges.
Delayed code refactoring
Refactoring is the process of improving code structure internally without changing it desired behavior.
As the development requirements change for a project, the other previous code creation may become obsolete or hard to update for future coding or business needs.
As refactoring is pushed back the bigger the tech debt becomes.
No clear standards or alignment
When business best practices, standards, software frameworks, and existing technology are disregarded.
Ultimately, the standards for code integration will happen and the longer the wait, the more it will cost in the future.
Insufficient developer knowledge
The developer doesn't have the know-how to create and execute elegant, clean code.
Outsourced software developers
When resources are outsourced to third-party developers it sometimes culminates in the in-house development team needing to refactor the code delivered.
Defective leadership
The communication of commands which are distributed from the top down and is not clearly thought out or contemplated before being executed.
Last minute changes
When the project is almost completed or close to completion and new requirements are provided before a tight deadline and there is no time, resources or budget to test and collect the implications of the adjustments to make the appropriate changes correctly.
Here the main goal is to ship the product with the additional changes in hopes that everything works correctly.
Types of technical debt
While there is a wide variety of technical debt types and definitions, they can ultimately be divided into three categories: unintentional, intentional, and environmental technical debt.
Intentional technical debt can be defined as deliberate, tactical decisions one makes knowingly at the time and may or may not have the intention of going back and refactoring the code.
The company is choosing bad, or dirty code, which may result in code security risks, unstable code, intermittent, or terrible performance, and user experience.
Though not optimal, knowing about these issues allows the team to document, measure, and update when needed.
Decision-makers with a bird’s-eye view of the situation might intentionally embrace shortcuts or less-than-perfect solutions to chase quick returns.
Such decisions often emerge from the necessity of speedy time-to-market or other immediate objectives.
Still, they come with the baggage of possibly unidentified bugs or hastily promoted code, making them ticking time bombs for your application.
Unintentional technical debt may be defined as the unconscious or unforeseen creation of poor or sloppy coding that is promoted to production without proper testing and review, oftentimes under the stress of strict delivery deadlines. Picture this as the byproduct of good intentions gone wrong.
Other factors, such as added or increased complexity within a project where the developers are unaware of the bugs they are inadvertently adding to their code.
These developer choices, where suboptimal code is introduced to production without immediate rollback with the hope (or gamble) of revisiting and refining it later, could lead to issues, compromised security, or subpar performance in the long run.
This kind of technical debt is dangerous because some issues can be unknown for a while.
While awareness of its existence allows teams to monitor and rectify it, unchecked unintentional technical debt ultimately leads to unmaintainable software.
Environmental technical debt is defined as debt that has increased over time without any active development from within the code itself. It is independent of the software's intrinsic quality or the developers' intentions and accumulates due to external factors.
This may be caused by other external factors such as an operating system is updated, resulting in something breaking or not working properly. Third-party API updates that break the connection or codebase libraries that bring in unwanted user issues.
Security updates or patches may stop an application from functioning as it should. Even if the original code is good and works, the tech debt will gradually increase over time.
Imagine a house built to perfection, but as the environment changes over time, it causes foundational shifts or decay.
This metaphor encapsulates the essence of environmental tech debt - even if a codebase starts flawlessly, external updates
The types of technical debt may be further broken down based on the particular classification of essential differentiators such as
- Architecture Debt: Refers to problems in the product architecture, which affect the architecture requirements. Generally, this technical debt results from initial solutions below the ideal, compromising internal quality.
- Build Debt: Refers to issues that make the build task harder and unnecessarily time-consuming.
- Code Debt: Refers to problems found in the source code (violating best practices or coding rules) that negatively affect its readability and make it difficult to maintain.
- Defect Debt: Refers to known defects, usually identified by test activities or the user. The development team agrees to correct them, but they will be delayed due to competing priorities and limited resources.
- Design Debt: Refers to technical debt discovered by analyzing the source code and identifying violations of good software design principles.
- Documentation Debt: This type of technical debt occurs when developers are too rushed to document their code thoroughly, hence there’s no documentation trail that other developers can use to understand their code.
- Infrastructure Debt: Refers to infrastructure problems that delay or hinder development activities if present in the software organization. Such TD negatively affects the team’s ability to produce a quality product.
- People Debt: Debt created by unresolved issues with staff training or distribution.
- Versioning Debt: Refers to problems in source code versioning, such as unnecessary code forks.
- Process Debt: Refers to inefficient processes, e.g. (the projected process may not be appropriate).
- Requirement Debt: Refers to the gap between the optimal requirements specification and the actual system implementation.
- Service Debt: Refers to inappropriate web services that lead to incompatibility between service features and application requirements.
- Test Automation Debt: Refers to the work involved in automating functionality tests developed to support continuous integration and faster development cycles.
- Test Debt: Refers to technical debt incurred when the team starts to spend more time on test maintenance and less on creating tests to ensure the software is bug-free.
Is technical debt bad?
While some say that it is not necessarily bad, it is not something you want to collect if you can help it.
Accepting a little technical debt for the short term when time is against you on a product release can be justifiable, or when vital software updates need to be shipped immediately.
Technical debt is bad and becomes a problem when it is left alone and not corrected in a timely fashion.
The build-up will continue to pile up and eventually cascade into an avalanche.
However, most tech debt produced today is due to poorly written code.
This is a shame because no developer wants to write bad code and be inefficient in their level of programming expertise.
Technical debt may only be considered good if you have the intention of paying it back and removing the debt completely.
Anything outside of that is truly considered bad.
Can you reduce technical debt?
There are several proactive ways to reduce technical debt.
Automate Testing to eliminate technical debt
Manually testing code for quality assurance can be time-consuming and inefficient.
Using automated testing tools, like SonarQube Server, can reduce or eliminate technical debt.
The use of automated debugging cycles and other operations which scan for code problems every time the module is updated.
SonarQube Server provides continuous inspection of code quality to perform automatic reviews with static analysis of code to detect bugs, code smells, duplicates, coverage, and security vulnerabilities in multiple programming languages.
Refactoring source code
Refactoring can be a different way to deal with technical debt by taking advantage of the source code's quality while leaving the expected behavior of the code alone. Refactoring is meant to correct poor code quality and can be fixed with automated testing tools.
However, lack of experience or incompetence may also play a part, which should be dealt with on a personal basis. Either more education or training may be required.
Use coding best practices
Companies and organizations should establish coding standards internally that developers are to follow and execute. When developers are on the same page regarding code etiquette and standards, this assists in eliminating technical debt from the beginning.
Project structure
Creating better project structures through project management tools or monitoring code troubles and fixing them as soon as possible within projects will reduce the debt. Prioritize projects and the structure to support your timeline and workflow.
As mentioned earlier, using code quality, security and analysis tools can greatly decrease the amount of technical debt you and your company will have to deal with at a later point in time.
How do you find and manage technical debt?
Probably one of the best, and easiest, ways of finding and managing technical debt is to use code metrics as a base to measure technical debt. There are many methods available to provide that data.
Code coverage
Code coverage is the percentage of your source code that is tested to a certain degree when a program is executed on specific test suites.
These are rules and requirements that must be met with the test suite (program subroutines or statements called during the test).
As more and more code is added, you will want to make sure the coverage remains consistent and does not slowly or significantly decrease.
Cyclomatic complexity
Cyclomatic complexity is a quantified software metric used to show the complexity of a program by analyzing the independent paths against the total lines of code.
The more independent divergent paths, the higher the cyclomatic complexity, and thus the more difficult the source is for maintainability.
SQALE-Rating
SQALE-Rating is a method to support assessing the quality of source code as a direct correlation with technical debt over the project.
Typically based on an alphabetical scale from A to E with A being the best quality score.
Rule violations
Rule violations are calculated by the established set of code standards that are violated or broken. Typically grouped into categories based on the severity of the violation.
Bugs
Counting the number of bugs in your software and monitoring critical issues is a good option to evaluate technical debt. (The more bugs found, the more technical debt increases).
Cost of delay
The measurement “cost of delay” is a framework that helps businesses quantify the economic value of finishing a project sooner instead of later based on prioritization. The goal is to provide transparency on how much time teams lose that is attributed to technical debt and the cost of completing a project sooner as opposed to later.
Conclusion
While some technical debt may be inevitable, most of it surely can be preventable. No one wants to spend time doing extra work.
Getting ahead of it before it becomes a problem later down the road is one way to ensure that you, your operations, your business, and most importantly, your code, are clean and debt-free moving forward.
While there are numerous tools available in the market that can be used to clean and prevent technical debt, we highly encourage the use of our free Lint IDE tool. Completely free and covering several programming languages, SonarQube for IDE provides real-time feedback evaluating over 5,000 rules covering a wide range of issues.
Utilizing language-specific analysis to detect bugs, code smells, and security vulnerabilities all the while maintaining the latest language standards.
This free tool for your IDE contains a large ruleset spanning reliability, maintainability, readability, security, quality and so much more. Work more and rework less.