If you are a DevOps-mature organization, you are in luck. Many DevOps practices, such as the shift-left approach, automated testing and deployment, small work batches, and tiny feedback loops, minimize TD accrual. Still, these practices aren’t the ultimate cure for technical debt. Why?
First of all, DevOps doesn’t spare you from intended shortcuts. Second, automated tests aren’t an all-seeing eye: they can’t detect all types of defects, and besides, they typically don’t have 100% code coverage, and errors can fall through the cracks. On top of that, in DevOps, software development infrastructure is also code, which can also have its own technical debt.
So, we recommend combining the following tips with your DevOps practices.
Identify and measure your technical debt
If you are reading this article, the chances are you have some technical debt. So, the first thing you should do towards managing it is to identify and measure it.
You can calculate it manually using the technical debt ratio (TDR)—the ratio of the time or cost needed to pay off the technical debt to building new features.
However, this approach comes with significant limitations: the findings might be subjective, the calculation will take an eternity in large codebases, and most importantly, it doesn’t help you to actually identify the technical debt. And that’s where technological solutions come into play.
Code scanners like SonarQube and Kiuwan can streamline bad code detection. SonarQube, for example, probes a codebase and estimates how long it will take to address each of the inefficiencies it finds. CodeScene takes a slightly different approach. Relying on the assumption that poorly written code is complex code, the solution analyzes code complexity and visualizes insights using color coding: green areas are low-risk code, yellow areas are a warning space, and red ones indicate the highest-risk code issues.
Communicate the cost of TD to your management
The TD paradox lies in the fact that it’s a purely technical phenomenon, which often occurs (and is sometimes left unmanaged) due to business decisions. So, making things clear to the business decision-makers should be the next thing after you identify and measure your technical debt.
Visualizations will come in handy at this point as they will clearly illustrate the extent of the problem. What’s no less important here is to transform your findings into the actual cost. For example, you can compare the cost of ignoring the TD against paying it off. As a result, your upper management will be more likely to move the delivery deadline or allocate additional budget for development team extension.
Besides, to prevent this concession from being a one-time thing, it’s vital to regularly demonstrate the results of your TD management: for example, you can regularly calculate how many hours of hypothetical unplanned work were avoided.
Prioritize and fix
Surely, if you have a large codebase, you can’t fix all areas of concern in one fell swoop—you need to prioritize them. In this respect, you have two options: do manual reviews or use technology to automate the process.
For this purpose, the abovementioned CodeScene offers another visualization tool known as Hotspots, which helped Capterra reduce the amount of unplanned work by 82%.
Since developers tend to spend most of their time and make the most commits on problematic parts of code, it combines findings from the codebase analysis described above with the data from version-control systems and creates a map with red spots of varying color intensity. The brighter the spot is—the higher priority the code has. The brightest areas indicate the highest number of commits, implying that these parts of the code require more immediate intervention.
Do your refactoring regularly
Once you’ve identified and prioritized the problematic areas in your codebase, the next step is to eliminate them by refactoring—the process of removing complicated, hard-to-read code and replacing it with clean code without changing the system’s capabilities that it’s based on.
And since the problematic code (and its interest) accumulates in a system gradually with time, it’s highly recommended to make refactoring a part of your regular workflow. Depending on your capacity, you can remove the “dirty” code in small portions with every consequent sprint or dedicate a separate sprint to address a large amount of it.
Adopt code reviews and pair coding
In the era of automated testing, this advice might seem to be unnecessary work. Still, let’s face it: automated tests aren’t a panacea. Many of today’s software developers insist that having at least one more pair of eyes will improve any code and prevent unintentional debt from piling up.
Just to make things clear, in pair coding, two developers are sitting in front of the same screen. One—the “driver”—is writing the code while the other one—the “navigator” is observing the process and giving feedback. Code reviews, in turn, take place when the developer thinks their code is ready and submits it to the reviewer for feedback before adding it to the mainline.
As you can see, both practices are DevOps at their best. They’ll help your developers exchange knowledge, facilitate collective ownership of code, and reduce feedback loops, catching bugs and performance defects, which automated tests would probably miss.
Adopt new technical debt acceptance standards
Automated tests, code reviews, and pair coding are great solutions to unintentional technical debt. But unfortunately, they won’t spare your product from intentional TD to build up. Luckily, that’s manageable, too.
You can minimize TD by taking a closer look at every “crutch” you are going to implement. For instance, a permanent security patch that won’t make your end product more vulnerable to cyberattacks is an acceptable solution. Meanwhile, an error that might cause downtime during peak hours isn’t.
Avoid poor software development practices systematically
Sometimes, technical debt builds up where it shouldn’t, and automated tests and peer reviews don’t help. Probably, your DevOps department is using poor software development practices where it isn’t necessary.
Let’s take a few examples of software development mistakes that, in most cases, can be avoided:
- Relying on the cloud providers’ UIs (instead of using code) to initiate deployments. As the number of your cloud providers increases (each with its own deployment interface), it becomes more challenging to switch between different UIs. So, it’s important to codify your deployment workflows in time.
- Not upgrading your product once a month. This means you won’t be able to keep up with updates of any third-party software it’s connected to.
- Not planning for service deprecation. You might end up being dependent on a module you no longer use, or not being able to scale your system.
- Not maintaining a knowledge base. Maintaining digital documentation—roadmaps, code documentation, checklists, etc.—during the development process will ease that process of “paying off” your TD.
And here we must make a reservation: these and other “poor” practices can serve as legitimate shortcuts when the deadline is just around the corner. For example, it’s acceptable to go for UI-based deployments to set up your DevOps infrastructure fast, or you can compile your documentation later. But these “crutches” shouldn’t be systematic and should be removed once possible—otherwise, they’ll backfire later in the form of unaffordable technical debt.