15 Technical Debt, Those Negligible Latent Issues

15 Technical Debt, Those Negligible Latent Issues #

Hello, I am Shi Xuefeng. Today I want to talk to you about technical debt.

If you were to ask software developers about the least desirable thing they would encounter in a project, the answer would probably be taking over a system that someone else has developed halfway. Moreover, the longer the system development time, the greater the resistance of the developers. So, since it’s the same code language, the same syntax rules, and at least something runnable, why do developers have such an inherent aversion? I speculate that the main reason is not wanting to see code written by someone else. The inability to understand it and the fear of making mistakes are both significant reasons, and they are all results of technical debt.

What is Technical Debt? #

So, what exactly is technical debt? Where does it come from? How can you end up in debt even when you write good code?

Imagine this scenario: your boss gives you an urgent requirement and expects you to develop and deploy it within 3 days. During the evaluation and design process, you realize that there are two possible solutions to implement this feature:

  • Solution 1: Adopt a layered architecture and introduce a message queue. This approach offers clear structure and decoupled functionality, but it requires 1 week to complete.
  • Solution 2: Make quick fixes and modifications to the existing code, squeezing in the new logic and page. This approach can be done in 2 days, leaving 1 day for testing.

So, which solution would you choose?

In most cases, you might choose Solution 2 because meeting business requirements always takes the highest priority. Especially in today’s market, competition is fierce and being the first to market is a significant advantage.

Technical debt refers to the additional cost the team incurs in maintaining this code in the future, as they opted for a quick fix rather than a better solution in order to achieve short-term goals. Just like any financial debt, technical debt accrues interest, and the longer it takes to pay off, the higher the cost becomes.

In reality, there are many reasons for technical debt, including the pressure to develop rapidly, temporary solutions without a proper understanding of the situation, insufficient technical skills of new employees, and the accumulation of unavoidable actions due to previous debts. In summary, the longer you maintain the code, the more technical debt you accumulate, burdening the team with heavy responsibilities.

What does technical debt look like? #

Simply put, you can understand technical debt as bad code. But what exactly makes the code “bad”? I believe that anyone who has written code has had experiences like these to a greater or lesser degree:

  • A codebase with a bunch of global variables defined, referenced in various places;
  • A repository with a bunch of scripts that have similar names and content;
  • A function that has been patched and extended to thousands of lines;
  • Magical and complicated table joins in database queries;
  • Parameter passing done solely by eye calculation;
  • Making changes to a piece of code resulting in a series of inexplicable issues;

So, how can we classify technical debt in code? We can borrow from the “Sonar Code Quality Testing Essentials” book and use the concept of the “Seven Deadly Sins” of code: complexity, duplicated code, coding standards, comment quality, test coverage, potential defects, and system architecture. You can refer to the following explanations and descriptions for each of these seven types:

In addition to low-quality code issues, there are many other types of technical debt, such as poor architecture, outdated technologies, and obscure programming languages.

For example, our company developed a system based on the Ruby language before. However, compared to popular languages like Java and Python, Ruby is relatively niche, making it difficult to find suitable engineers, which in turn impacts the further development of the system. Another example is that by January 1, 2020, official support for Python 2.x branch will cease. If your new system is still being developed using Python 2, you will soon face the problem of upgrading to a major version. Although the official provides some solutions to reduce migration costs, there is still a significant potential workload in terms of system stability, among other factors.

Why is technical debt important? #

So, the question is, why is it important to pay attention to technical debt? Or, what problems can bad code cause?

From a user’s perspective, the amount of technical debt doesn’t seem to affect the user’s direct experience. In other words, it doesn’t hinder usage and all the expected functionalities work fine. So, going back to the example mentioned earlier, since a system developed in 2 days and a system developed in 1 week don’t seem to have any difference in terms of usage, does that mean we should choose the solution with lower time cost?

Obviously, it’s not that simple. Let’s take an example. A person leaves the house well-dressed, but their house is in a mess, and it takes a long time to find things. This is certainly not something to be proud of. The same goes for software. The most direct impact of technical debt is the quality of internal code. If the internal code quality is poor, it will have three main effects:

1. Extra development costs

For a system with clear architecture, code standards, logical order, and comprehensive comments, adding a new feature may only take 1-2 days. But for the same requirement in a chaotic codebase, it may take 1 week or even longer. Understanding the logic of the existing code, sorting out the calling relationships, and avoiding potential pitfalls are not easy tasks. Moreover, there is also a large amount of duplicated code that needs to be modified in multiple places, which can easily lead to problems.

2. Unstable product quality

The worse the code quality, the greater the impact caused by fixing issues because you don’t know what kind of problems will be triggered when you make changes. Moreover, such code often lacks reliable test cases to ensure that the logic before and after the modifications is correct. If adding a new feature leads to a serious production issue, then you will have to face the choice between continuing to modify or rolling back. If you choose to continue modifying, you may make more mistakes, and it becomes like a bottomless pit that can never be filled.

3. Difficult to maintain

Because of the above problems, developers tend to be cautious and careful when maintaining such code in order to avoid problems. As a result, developers would rather patch up the code instead of changing the original logic. This will lead to a continuous downward spiral in code quality, making it increasingly difficult to maintain and accumulating more and more issues. Until the day when it becomes impossible to maintain, the code will be rebuilt under the pretext of refactoring. In fact, this is not a refactoring, but a rewrite.

In addition, if a development team constantly deals with such projects, the team’s learning ability and work enthusiasm may be affected. It can be seen that the accumulation of technical debt is like a real debt. It’s something that needs to be paid back sooner or later, the only question is who will do the repayment.

How to Quantify Technical Debt? #

Unlike bank loans, technical debt is invisible and intangible in software development, so we need a set of calculation methods to quantify this debt. Currently, SonarQube is a commonly used open-source software in the industry. In SonarQube, technical debt is calculated based on the SQALE method. SQALE stands for Software Quality Assessment based on Lifecycle Expectations, and it is an open-source algorithm. Today, the focus is not on explaining this algorithm, but you can check out more about it on the official website. In the meantime, I will share an article about the SQALE algorithm, which can help you study code quality more deeply.

SonarQube identifies and calculates different types of rules according to a standardized algorithm and finally aggregates them into a measure of time. This means that it provides an intuitive understanding of the time cost required to address these identified issues, thus providing an insight into code quality.

SonarQube provides a general conversion formula. For example, as shown in the figure below, in SonarQube’s default rules, an out-of-bound data issue is defined as a critical issue, and the technical debt calculated is equivalent to 15 minutes. The 15 minutes is calculated based on the SQALE analysis model mentioned earlier. Of course, you can also customize the estimated fix time for each rule in the rule configuration.

The calculated technical debt will vary depending on the number and types of enabled rules. As mentioned in the previous lecture, reaching consensus within the team on rules is crucial. Only when consensus is reached can optimization be built upon it. Otherwise, if the rule library keeps changing, the technical debt indicators will also change, making it difficult to identify the long-term trend of code quality within the team.

In addition, SonarQube also provides a more intuitive indicator to represent code quality, which is the SQALE rating. The SQALE rating is categorized into A, B, C, D, and E, with A being the highest level, indicating the highest code quality level. The rating algorithm is entirely based on the ratio of technical debt. In simple terms, it is the ratio of the time cost to fix technical debt compared to the time cost of completely rewriting the code, based on the current code’s line count. In extreme cases, the time needed to address technical debt in a piece of code may be even longer than the time needed to completely rewrite it, indicating that the code has reached an unmaintainable state. Therefore, in practical implementation, the health of the SQALE rating of the code is highly valued.

Technical Debt Ratio = Time to Fix Existing Technical Debt / Time to Completely Rewrite the Entire Code

By introducing the line count of code, the overall quality level can be calculated in a more objective manner. After all, comparing the technical debt of a code project with 100,000 lines and another project with 1,000 lines would be meaningless. This approach reflects a more visualized measurement method. For example, many companies currently use a multitude of indicators in team efficiency measurement, which can be incomprehensible. A more sophisticated approach is to aggregate various indicators into a set of algorithms and provide corresponding ratings based on these algorithms.

Of course, if you want to know the calculation method for the rating, you can delve into the detailed data. For example, the capability of continuous integration is composed of multiple indicators such as frequency of continuous integration, duration of continuous integration, success rate of continuous integration, and time to fix issues. If during the measurement process, you find that the overall score for continuous integration is low, you can click into it to view the data and status of each indicator, as well as detailed execution history. This ability for data correlation and drill-down is crucial for constructing a data measurement system.

By visualizing technical debt, the team can have a more intuitive understanding of code quality. However, the next step is to address these issues.

Solutions and Principles #

I have visited many companies, and they all understand the harm of technical debt. They have set up and regularly execute Sonar, but the problem is they don’t have time. Indeed, many times, we don’t have time to do unit testing, code review, or solve technical debt. But compromising like this, when will it end?

A few days ago, I visited the largest securities company in China, and I was impressed. This so-called traditional enterprise has a single digit technical debt in its research projects. After in-depth communication with them, I found that the company has put in a lot of effort in this regard. The top management is controlling it strictly. There are strict quality checkpoints, which is why they have achieved such results.

Therefore, when not all external conditions are in place, what we need to do is to just do it. So, what are the steps to solve technical debt?

  1. Consensus: The team needs to reach a consensus on the harm of technical debt, the goals for solving the project, and the selection and formulation of rules.
  2. Visibility: By building an open-source Sonar platform, integrate code scanning into the continuous delivery pipeline, and execute it regularly or on demand, making technical debt visualized and quantifiable. Moreover, the Sonar platform can also provide suggested solutions for identified issues, which is very helpful for the team to quickly improve their coding skills.
  3. Stop loss: For core business modules, set baselines for core indicator types such as vulnerability, severity of defects, and blocking issues. That is, control the overall number from increasing.
  4. Improvement: Create technical optimization requirements and allocate a certain amount of time in iterations to fix existing issues or use concentrated efforts to tackle major issues, and then continue to improve.

There are four principles to follow in the process of solving technical debt.

  1. Make technical debt have a benign downward trend. A good trend means a good starting point and is also an agreement for the team to collectively maintain technical debt.
  2. Priority should be given to addressing issues with high-frequency changes. The interest of technical debt is the additional cost of introducing new features, so for modules with high-frequency changes, these costs will accumulate quickly, which means the output of fixing them is the greatest. As for which code is subject to high-frequency changes, it can be seen by analyzing the version control system.
  3. Start pilots in new projects. If the existing codebase is too large and it is not possible to complete the fixes in a short period, you can choose to control growth and start pilots in new projects. On one hand, this will test the effectiveness of rules, and on the other hand, it allows for pilots of automated processes such as quality checkpoints and IDE plugin integration.
  4. Technical debt cannot be eliminated, and it should not be left until it’s too late. As long as software projects are being developed, technical debt is almost unavoidable. Therefore, there is no need to set the goal too high all at once. It should be done gradually. However, the accumulation of technical debt is not infinite, and it is too late when it becomes impossible to maintain.

When starting to address technical debt, the biggest problem is not having too few reference indicators, but having too many. So the team needs to spend a lot of time reviewing the rules. Regarding this issue, I have two suggestions for you:

  1. First, refer to the default issue levels of the code quality platform. Generally, blocking and severe issues have higher priority than general issues. This conclusion is based on the long-term professional accumulation of the code quality platform.
  2. Second, you can refer to the best practices of outstanding companies in the industry. For example, many companies refer to Alibaba’s Java development manual, and JD.com also has its own coding conventions. Finally, I have summarized some problem types that have a relatively large impact, and I recommend you prioritize addressing them.
  • A large amount of duplicate code
  • Severe coupling between classes
  • Overly complicated methods
  • Excessive nested conditional statements
  • Lack of necessary exception handling
  • Multiple table associations and lack of indexes
  • Code risks and defects
  • Security vulnerabilities

Summary #

In this lecture, I introduced the concept of technical debt to you. The cost of technical debt is the additional cost of developing new features by the team. Technical debt can take many forms, with the typical one being the “Seven Deadly Sins of Code”. In addition, I discussed the impact of technical debt and methods for quantifying technical debt. Finally, I provided some solutions and principles to help you overcome this problem of technical debt.

Image

In recent years, there has been a constant voice in the field of intelligent development, and one popular research area is the use of artificial intelligence and big data technology to improve code quality. It is a trend to use technology to assist development in solving technical problems. If you are engaged in development support and efficiency improvement work in the company, I recommend that you delve into relevant academic articles, as it will be beneficial to your work.

References:

  1. Customized Management of Code Clones through Continuous Monitoring
  2. Software Development Quality Traceability System Based on Code Big Data
  3. Some Notes on Code Clones: Why Do Developers Clone? How Is the Situation Changing?

Thought question #

Have you ever encountered impressive bad code?

Welcome to write down your thoughts and answers in the comments section. Let’s discuss and learn together for progress. If you find this article helpful, feel free to share it with your friends.