Technical debt

Author: Dmitry Ro
Updated: 2023-08-25

1. What is technical debt ?

Technical debt is defined as:

the incremental cost and loss of agility to a company as a result of prior decisions that were made to save time or money when implementing new systems or maintaining existing ones.

In the world of software development, where innovation and rapid releases are paramount, developers often find themselves navigating a delicate balance between delivering immediate results and building a strong foundation for the future. This delicate balance is encapsulated by a term that has become a cornerstone of software engineering discussions: technical debt.

Imagine you’re constructing a bridge. You have two options: You can spend extra time and resources building a sturdy, well-designed structure that can withstand the test of time and changing conditions, or you can take shortcuts, using subpar materials and hastily assembled components to get the bridge up quickly. While the second option might allow you to open the bridge to traffic sooner, it comes with a catch: as time goes on, you’ll need to perform more frequent repairs, face increased maintenance costs, and risk potential safety issues due to the initial shortcuts.

In the realm of software development, technical debt is analogous to those shortcuts. It refers to the conscious or sometimes unwitting decisions made during the development process to expedite the delivery of software or new features. These shortcuts can manifest as temporary patches, incomplete solutions, or suboptimal coding practices that address immediate needs at the expense of long-term software health.

Technical debt is not inherently a negative concept. In fact, it often serves as a pragmatic strategy to meet tight deadlines, deliver a minimal viable product, or adapt to rapidly changing market demands. Just as taking on financial debt can provide resources to invest in opportunities, accruing technical debt can provide short-term benefits. However, much like financial debt, technical debt needs to be managed effectively to avoid negative repercussions.

2. How technical debt impact project and team morale ?

2.1. Project Delays and Frustration

As technical debt accumulates, developers often find themselves grappling with unforeseen challenges and unexpected bugs. What initially seemed like a quick solution can transform into a time-consuming and frustrating ordeal. Delays in feature delivery or unexpected rework due to technical debt can lead to frustration, demotivation, and a sense of working in a perpetual state of firefighting.

2.2. Quality Compromises

The quality of software is a source of pride for developers. However, when technical debt starts to outweigh well-designed code, it can erode the sense of accomplishment and ownership that team members feel for their work. Knowing that suboptimal solutions have been implemented can create a sense of unease, undermining the team’s confidence in the final product.

2.3. Resistance to Innovation

Technical debt tends to accumulate in areas that developers are hesitant to touch. This can lead to an aversion to making changes or introducing new features, as team members fear they might unearth hidden issues or inadvertently trigger a cascade of bugs. This resistance stifles innovation and creativity, as developers become wary of taking risks.

2.4. High Maintenance Burden

A significant portion of the team’s time and effort may be spent on maintaining and fixing existing code riddled with technical debt. This not only detracts from the time available for developing new features but can also lead to a sense of monotony and unfulfilling work. Over time, the repetitive nature of maintenance work can lead to a drop in team morale.

2.5. Blurred Vision and Alignment

Technical debt can obscure the project’s long-term vision and goals. As teams grapple with immediate challenges posed by debt-ridden code, they may lose sight of the broader project objectives. This lack of alignment can result in a fragmented sense of purpose and reduced motivation to contribute effectively.

3. Types of technical debt ?

3.1. Intentional technical debt

3.1.1. Architectural Shortcuts

Teams may choose to bypass a comprehensive architectural overhaul in favor of making smaller adjustments to meet a pressing deadline. This can lead to suboptimal design patterns or workarounds that might require refactoring later.

3.1.2. Incomplete Testing

When timelines are tight, comprehensive testing might take a backseat. Teams might intentionally skip certain tests or limit the scope of testing to ensure timely delivery, with the intention of enhancing testing rigor in subsequent iterations.

3.1.3. Minimal Viable Product (MVP) Approach

In situations where a rapid product release is essential, teams might prioritize building the core features needed for a functional MVP. This can result in a product with fewer features and potentially less polished code.

3.1.4. Code Duplication

To save time, developers might duplicate code in different parts of the application instead of refactoring for reusability. This can lead to maintenance challenges down the line.

3.1.5. Deferred Documentation

While comprehensive documentation is crucial for code maintainability, teams might choose to defer writing extensive documentation during high-pressure phases, focusing instead on delivering functionality.

3.2. Managing Intentional Technical Debt:

While the deliberate accumulation of technical debt is a conscious decision, it’s important to manage it effectively to prevent it from spiraling out of control. Here’s how:

3.2.1. Documentation

Clearly document the decisions to incur intentional technical debt. Explain the reasons, trade-offs, and the intended plan for addressing the debt in the future.

3.2.2. Transparency

Communicate the presence of intentional technical debt to stakeholders, including project managers, product owners, and team members. Transparency fosters a shared understanding of the development strategy.

3.2.3. Monitoring and Repayment

Keep a vigilant eye on the accumulated technical debt. Prioritize regular reviews and allocate time to address the debt during planned refactorings and improvements.

3.2.4. Communication of Risks

Make sure that stakeholders are aware of the potential risks associated with intentional technical debt. Balancing immediate results with long-term sustainability requires informed decision-making.

3.3. Ununintentional debt

While deliberate technical debt is a conscious choice made to meet immediate needs, unintentional technical debt arises organically due to various factors that can compromise the quality of software development. These factors can include time pressures, evolving requirements, inexperience, and miscommunication. Unintentional technical debt often accumulates without teams realizing it, leading to long-term consequences that can impact project success and software health.

To mitigate the effects of unintentional technical debt, development teams must adopt proactive practices. This includes investing time in proper planning, ensuring code reviews, implementing automated testing, and fostering a culture of continuous improvement. By being vigilant about the accumulation of unintentional debt, teams can maintain software quality, enhance project predictability, and foster a collaborative and motivated work environment.

3.3.1. Factors Contributing to Unintentional Technical Debt

  1. Rushed Development

    Under tight deadlines, developers might skip thorough testing, proper code reviews, or careful design, leading to the introduction of bugs and suboptimal code.

  2. Insufficient Planning

    Inadequate upfront planning can result in incomplete understanding of requirements, leading to design decisions that may need to be revisited later.

  3. Lack of Experience

    Junior developers or teams new to a technology stack may inadvertently create technical debt due to unfamiliarity with best practices.

  4. Scope Creep

    When project requirements change frequently or expand beyond initial expectations, development teams might make on-the-fly adjustments that result in technical debt.

  5. Temporary Fixes

    Urgent bug fixes or quick solutions can turn into permanent parts of the codebase if they’re not revisited for proper resolution later.

3.3.2. The Unseen Costs of Unintentional Technical Debt

  1. Increased Maintenance Burden

    Code riddled with unintentional debt requires ongoing attention, as developers grapple with fixing bugs and patching issues that could have been avoided with better initial design.

  2. Reduced Agility

    As debt accumulates, code becomes more complex and intertwined, making it harder to adapt to changing requirements or pivot direction.

  3. Decline in Code Quality

    Unintentional debt can lead to poor code quality, causing a drop in overall software reliability and maintainability.

  4. Drain on Resources

    The time and effort spent on addressing unintended technical debt could have been allocated to more strategic tasks, hindering productivity.

  5. Team Morale Impact

    Continuously dealing with the consequences of unintentional debt can demotivate developers, affecting their sense of accomplishment and job satisfaction.

4. How much money companies losing on technical debt ?

According to Stripe report about ~20 hours per week spent on technical debt and bad code

Measurement value
Average hours per developer workweek 41.1h
Average hours spent by developers on bad code, debugging, refactoring, modifying 17.3h
Average hours spent on technical debt 13.5h
Average hours spent on bad code 3.8h
Percent productivity loss from bad code 9.25%

So, it’s about 17 hours per week, which amounts to approximately 40% of the time developers spend dealing with previously made mistakes, all the while potentially creating new ones. On average, companies end up using around 40% of their development budget on addressing the consequences of poor code quality.

Let’s take the scenario of an average team comprising 5 developers, each with a monthly cost of $5000. This accumulates to a total cost of $25,000 per month. Now, if we subtract 40% from this figure, we arrive at $10,000 being allocated to the resolution of issues stemming from what we term as ’bad code.’ It’s important to remember that the impacts of ’bad code’ ripple outward, affecting not only the developers themselves but also consuming the time of others, including the end customers.

Subject Value Spent on technical debt
Developer hourly cost $30 $12 per hour
Hours per week 40h 16h
Developer cost per week $1200 $480 per week
Developer cost per month $4800 $1920 per month
Team of 5 developer cost per month $24000 $9600 per month
     

This is for EU market salaries. Imagine numbers for US market.

4.1. Lets drill down more deep example

I will outline potential challenges and conduct a cost analysis of technical debt using a hypothetical product named InsureWizard. With a history spanning five years, InsureWizard’s initial Minimum Viable Product (MVP) was expedited through numerous technical shortcuts, a common practice in MVP development. Despite these shortcuts, the product garnered significant attention and achieved substantial success. The monthly development expenditure hovers at approximately $50,000. Concurrently, the product sustains a cumulative monthly revenue of $150,000, generated from a dedicated customer base of 5,000 subscribers, each contributing $30 to their subscription.

Development cost per month $50,000
Number of paying customers 5000
Subscription price $30
MRR (Monthly Recurring Revenue) $150,000

So, the InsureWizard team starts a new sprint by carefully estimating tasks and agreeing on what they’ll work on. Among the team members, there’s John, a skilled developer at InsureWizard. He takes on a task with dedication. He codes quickly, tests thoroughly, and then releases the code. This leads to happy users, longer subscriptions, and company growth—basically, a success story. However, this story doesn’t match what happens in around 90% of real cases. That’s mostly because of technical debt’s influence, and unfortunately, the situation at InsureWizard fits this pattern.

In reality, things happen differently. As the sprint gains momentum, John picks a task to work on. He’s excited about coding, but then he hits a roadblock.

4.1.1. Inability to estimate

Unexpected problems pop up in the existing code, making it not work properly. These issues include bugs and complicated things that make it hard to add new features later. Challenges pile up, making the task more complex than originally thought. John spends a lot of time debugging, trying to figure out the complex code and fixing the problematic parts. This process involves testing multiple times. What was supposed to be a quick day of coding now stretches into few days or even a full week of focused effort.

Development cost $50,000 Technical debt cost = $50,000 * 0.4 = $20,000 / month

4.1.2. Performance and infrastructure cost

Inadequate architecture and the inability to make necessary changes lead to a substantial increase in unnecessary infrastructure expenses. Additionally, InsureWizard faces a frequent occurrence of errors during runtime. To manage this, the development teams rely on a third-party log tracking service. The cost of this subscription is determined by the volume of data processed, meaning more logs result in higher costs. Remarkably, half of these logs are unnecessary and redundant, making their transmission to the log tracking service redundant as well.

Similar patterns extend to cloud services, where developers often fail to configure settings optimally. Consequently, excessive expenditures are incurred daily due to improper configuration of these services.

Technical debt cost = $1000 / month

4.1.3. People costs

The psychology behind technical debt and people is quite straightforward: the more it irritates the developer, the higher the likelihood that they will leave the company. For developers with high ambitions, the inability to achieve proper results is critical. Therefore, expecting motivation and interest from the rest of your team, who endorse bad practices, poor code, and a multitude of technical debt, is unrealistic. Moreover, they are probably only working for monetary gain and might not be interested in self-improvement.

Technical debt cost = $5000 / month (Each month new developer)

4.1.4. Customer impact

Bad code means more bugs, more bugs means less customer success. Customers express dissatisfaction due to problems such as a subpar user experience and reliability issues. However, due to the suboptimal development pace and the unpredictable development process, the initially agreed-upon deadlines get postponed. As a result, customers are compelled to wait for extended periods, leading to mounting frustration. This frustration eventually prompts users to abandon the product or service. An escalation in bugs and issues directly impacts customer support operations. As the frequency of problems rises, so does the influx of support tickets, consequently driving up operational costs.

Technical debt cost = $2000 / month (Add support resources, without reduction of customers left)

4.2. Summarize

$20,000 + $1000 + $5000 + $2000 = $28,000 per month spent because of technical debt. Which is $336,000 per year!!!.

Examples of technical debt

Subject Type Impact Negative Impact On
Not knowing fundamentals of used tools Unintentional High Cost, quality, team morale
Not keeping up with current industry standards Unintentional High Cost, quality, team morale
Relying on outdated technology Unintentional High Cost, innovation, competitiveness
Neglecting code documentation Unintentional Moderate Maintainability, onboarding, team productivity
Ignoring scalability considerations Unintentional High Future development, user experience, cost
Failing to perform proper testing Unintentional High Bugs, user satisfaction, reputation
Neglecting security measures Unintentional High Data breaches, user trust, legal repercussions
Doing MVP without following coding standards Intentional Low Quality
Delaying refactoring Intentional Moderate Maintainability, technical debt accumulation
Opting for quick fixes instead of thorough solutions Intentional High Technical debt accumulation, long-term stability
Not discussing technical debt within the team Both High Cost, quality, team morale
Rushing development without proper planning Both High Quality, scope changes, missed deadlines
Neglecting continuous integration and deployment Unintentional High Deployment issues, reduced development efficiency
Over-architecting the system Unintentional High Development complexity, maintenance challenges
Not involving end-users during development Unintentional High Mismatched features, user dissatisfaction
Ignoring performance optimization Unintentional High Slow application, user dissatisfaction
Not aligning with business goals and user needs Unintentional High Reduced value, poor user engagement
Failing to adapt to changing technology trends Unintentional High Technological obsolescence, competitive disadvantage
Neglecting code reviews and peer feedback Unintentional High Quality, code maintainability, team collaboration
Not considering cross-platform compatibility Unintentional High Limited user reach, development inefficiencies
Disregarding user experience and usability principles Unintentional High User dissatisfaction, decreased engagement

5. How to mitigate technical debt ?

Take another credit and increase the debt, or pay it back with:

  • Regular Code Reviews: Establish a culture of thorough code reviews to catch and rectify issues early, preventing the accumulation of debt.
  • Continuous Refactoring: Prioritize ongoing refactoring to improve code quality and maintainability, even allocating specific time for it in development cycles.
  • Documentation: Maintain clear and updated documentation to aid understanding and future maintenance, reducing confusion and errors.
  • Adhere to Standards: Enforce coding standards and best practices to ensure consistency and enhance code quality from the outset.
  • Test Driven Development (TDD): Adopt TDD to catch issues early and validate the functionality of code, reducing future debugging efforts.
  • Automated Testing: Implement robust automated testing to identify regressions and bugs, bolstering code reliability.
  • Prioritize Security: Address security concerns during development to prevent vulnerabilities and potential breaches.
  • Refine Processes: Optimize development methodologies and workflows to streamline processes and minimize errors.
  • Eliminate Unnecessary Dependencies: Identify and remove redundant dependencies that contribute to unnecessary complexities.
  • Invest in Learning: Encourage developers to continuously learn and adapt to new technologies, preventing obsolescence and stagnation.
  • Risk Assessment: Evaluate the impact of decisions on technical debt before committing to them, considering long-term consequences.
  • Regular Updates: Keep software dependencies up to date to benefit from bug fixes, performance enhancements, and security patches.
  • Communication: Foster open communication among team members about technical debt, encouraging transparency and collaborative solutions.
  • Long-Term Planning: Balance short-term goals with long-term vision, avoiding shortcuts that sacrifice future stability.

6. Real life examples of technical debt harmness

  • Netscape: (https://news.ycombinator.com/item?id=840935)
  • BlackBerry: BlackBerry, once a leader in the smartphone market, struggled to keep up with competitors due to technical debt. Their proprietary operating system became outdated and less user-friendly compared to iOS and Android. The company’s failure to modernize their software contributed to their decline in market share.
  • Nokia: Nokia, a former mobile phone giant, faced a similar fate. Their insistence on using their Symbian operating system instead of adopting newer platforms like iOS and Android led to technical debt. As a result, they lost their dominance in the smartphone market. (https://medium.com/multiplier-magazine/why-did-nokia-fail-81110d981787)
  • Healthcare.gov: The launch of the healthcare.gov website in the United States, intended to facilitate healthcare enrollment, was marred by technical debt. The website experienced glitches, crashes, and slow performance due to rushed development and poor system architecture, resulting in a problematic rollout. (https://d3.harvard.edu/platform-rctom/submission/the-failed-launch-of-www-healthcare-gov/)
  • Knight Capital Group: In 2012, Knight Capital Group, a financial services company, suffered a massive trading loss due to technical debt in their trading software. A faulty software update led to erroneous trades, resulting in a loss of $440 million and almost causing the company’s bankruptcy. (https://www.henricodolfing.com/2019/06/project-failure-case-study-knight-capital.html)

Bonus


Comments