In a report on managing technical debt, Google researchers make a startling admission:
“With a large and rapidly changing codebase, Google software engineers are constantly paying interest on various forms of technical debt.”
What’s true of Google is very likely true of your company as well, especially if you have legacy applications you still depend on for important business functions. If you do, you’re almost certainly carrying a load of technical debt that is hindering your ability to innovate as quickly and as nimbly as you need to in today’s fast-changing marketplace and technological environments.
Technical debt is an issue you cannot afford to ignore. As an article in CIO Magazine explains,
“CIOs say reducing technical debt needs increasing focus. It isn’t wasting money. It’s about replacing brittle, monolithic systems with more secure, fluid, customizable systems. CIOs stress there is ROI in less maintenance labor, fewer incursions, and easier change.”
But what, exactly, is technical debt, and why is managing it so vital for companies today?
Why Managing Technical Debt is Critical
What is technical debt? According to Ori Saporta: “Technical debt, in plain words, is an accumulation over time of lots of little compromises that hamper your coding efforts.”
In other words, technical debt is what happens when developers prioritize speed over quality. The problem is that, just as with financial debt, you must eventually pay off your technical debt, and until you do, you’ll pay interest on the principal.
- The “interest” on technical debt consists of the ongoing charges you incur in trying to keep flawed, inflexible, and outmoded applications running as the technological context for which they were designed recedes further and further into the past. Software developers spend, on average, about a third of their workweek addressing technical debt. Plus, there’s also the opportunity cost of time that’s not being spent to develop the innovations that can help propel a company ahead in its marketplace.
- The “principle” on technical debt is what it costs to clean up (or replace) the original messy code and bring the application into the modern world. Companies typically incur $361,000 of technical debt for every 100,000 lines of code.
Managing your technical debt is critical because the price you’ll pay for not doing so, in terms of time, money, focus, and lost market opportunities, will grow at an ever-accelerating pace until you do.
Managing Technical Debt: Getting Started
A report from McKinsey highlights how a company can begin dealing with its technical debt:
“[A] degree of tech debt is an unavoidable cost of doing business, and it needs to be managed appropriately to ensure an organization’s long-term viability. That could include ‘paying down’ debt through carefully targeted, high-impact interventions, such as modernizing systems to align with target architecture.”
The place to start in managing technical debt is with modernizing legacy applications to align with a target architecture, which today is usually the cloud. Legacy applications weren’t designed to work in the cloud context, and it’s very difficult to upgrade them to do so. That’s because such apps often have a monolithic system architecture.
Monolithic code is organized as a single unit with various functionalities and dependencies interwoven throughout the code. The coding shortcuts, ad hoc patches, and documentation inadequacies that are typical sources of technical debt in legacy applications are embedded in the code in ways that are extremely difficult for humans to unravel. Worse, because of hidden dependencies in the code, any changes aimed at upgrading functions or adding features may ripple throughout the codebase in unexpected ways, potentially causing the entire application to fail.
From Monoliths to Microservices
Because a monolithic architecture makes upgrading an application for new features or for integration into the cloud ecosystem so difficult, the first step of legacy app modernization is usually to restructure the code from a monolith to a cloud-native, microservices architecture.
Microservices are small chunks of code that perform a single task. Each can be deployed and updated independently of any others. This allows developers to change a specific function in an application by updating the associated microservice without the risk of unintentionally impacting the codebase as a whole.
The process of restructuring a codebase from a monolith to microservices will expose the hidden dependencies and coding shortcuts that are the source of technical debt.
Related: Migrating Monolithic Applications to Microservices Architecture
Options for Modernizing Legacy Apps
Gartner lists seven options for modernizing legacy applications:
- Encapsulate: Connect the app to cloud resources by providing API access to its existing data and functions, but without changing its internal structure and operations.
- Rehost (“Lift and Shift”): Migrate the application to the cloud as-is, without significantly modifying its code.
- Replatform: Migrate the application’s code to the cloud, incorporating small changes designed to enhance its functionality in the cloud environment, but without modifying its existing architecture or functionality.
- Refactor: Restructure the app’s code to a microservices architecture without changing its external behavior.
- Rearchitect: Create a new application architecture that enables improved performance and new capabilities.
- Rewrite: Rewrite the application from scratch, retaining its original scope and specifications.
- Replace: Throw out the original application, and replace it with a new one.
The first three options, encapsulation, rehosting, and replatforming, simply migrate an app to the cloud with minimal changes. They offer some improvements in terms of operating costs, performance, and integration with the cloud. However, they do little to reduce technical debt because there’s no restructuring of the legacy application’s codebase—if it was monolithic before being migrated to the cloud, it remains monolithic once there.
The last option, replacing the original application, can certainly impact technical debt, but because it’s the most extreme in terms of time, cost, and risk, it’s usually considered only as a last resort.
The most viable options, then, for removing technical debt are refactoring, rearchitecting, or rewriting the code.
Assessing Your Monolithic Application Landscape
The ideal solution for managing technical debt would be to immediately identify and convert a subset of your legacy applications to microservices. But because any restructuring project involves significant costs in terms of money, time, and risk, trying to modernize every app in your portfolio is not a practical strategy for most companies.
That’s why your first step on the road to effectively managing technical debt should be surveying your portfolio of monolithic legacy applications to assess each in terms of its complexity, degree of technical debt, and the level of risk associated with upgrading it. With that information in hand, you can then prioritize each app based on the degree to which its value to the business justifies the amount of effort required to modernize it.
- For apps with high levels of technical debt and great value to the business, consider full modernization through refactoring, rearchitecting, or rewriting.
- Apps with lower levels of technical debt (meaning that they function acceptably as they are) or that have a lesser business value should be considered for simple migration through encapsulation, rehosting, or replatforming.
Refactoring is Key
Refactoring is fundamental to managing technical debt for at least two reasons:
- It exposes the elements of technical debt, such as hidden dependencies and undocumented functionalities, that are inherent in an app’s original monolithic code. These must be well understood before any rearchitecting or rewriting efforts can be safely initiated.
- By converting an app to a cloud-native microservices architecture, refactoring positions it for full integration into the cloud ecosystem, making further upgrades and functional extensions relatively easy.
That’s why refactoring is normally the first stage in modernizing a monolithic legacy app. Then, if new capabilities or performance improvements are required that the original code structure does not support, rearchitecting may be in order. Or, if the development team wishes to avoid the complexities of rearchitecting existing code, they may opt to rewrite the application instead.
In any case, refactoring will normally be the initial step because it produces a codebase that developers can easily understand and work with.
Implement “Continuous Modernization”
Technical debt is unavoidable. As the pace of technological change continues to accelerate, even your most recently written or upgraded apps will slide relentlessly over time toward increased technical debt. That means you should plan to deal with your technical debt on a continuous basis–known as continuous modernization. As John Kodumal, CTO and cofounder of LaunchDarkly has said,
“Technical debt is inevitable in software development, but you can combat it by being proactive… This is much healthier than stopping other work and trying to dig out from a mountain of debt.”
You need to constantly monitor and clean up your technical debt as you go, rather than waiting until some application or system reaches a crisis point that requires an immediate all-out effort at modernization. In fact, continuous modernization leads to technical debt removal and should be a fundamental element of your CI/CD pipeline.
Related: Preventing Monoliths: Why Cloud Modernization is a Continuum
vFunction Can Help You Manage Your Technical Debt
As we’ve seen, the first step toward effectively managing your technical debt is to assess your suite of legacy apps to understand just how large the problem is. That has historically been a very complex and time-consuming task when pursued manually. But now the AI-driven vFunction platform can substantially simplify and speed up the process.
The vFunction Architectural Observability Platform will automatically evaluate your applications and generate qualitative measures of code complexity and risk due to interdependencies. It produces a number that represents the amount of technical debt associated with each app, providing you with just the information you need to prioritize your modernization efforts.
And once you’ve determined your modernization priorities, the vFunction Code Copy automates the process of actually transforming complex monolithic applications into microservices, which can result in immense savings of time and money. If you’d like a first-hand view of how vFunction can help your company effectively manage its technical debt, schedule a demo today.