The secret to maintaining applications and avoiding or at least delaying legacy status lies in how organizations and teams manage technical debt Credit: Getty Images A big challenge for any development organization managing technical debt, the pile of work created from past decisions in software development efforts. Addressing technical debt often gets short shrift, because doing so rarely addresses an urgent business need and, especially for nonurgent cases, the ROI is unclear and thus perceived as deferrable. It’s a classic issue for anything involving maintenance, whether code or houses. But there are ways to measure and manage technical debt that will help you keep control of that technical debt. How do the applications that you are developing today evolve into tomorrow’s legacy applications? You and the development team are sprinting and releasing application improvements on a regular release schedule, so it might be hard to imagine these applications dissolving to legacy status in the future. You might also be wondering what you can do today as you are developing the application to reduce the risk of it becoming a legacy application. Applications don’t become legacy overnight, and they become that way because of two primary factors: As the application gets older, an organization may assign fewer people to maintain it , instead shifting people to more strategic projects. The amount of time the team dedicates to address technical improvements to the application may get smaller over time, given then focus on new activities. Technical debt defined A backlog of these technical improvements is called technical debt. Technical debt is something development teams have to do to maintain the application’s architecture, underlying platforms, and code. Examples of technical debt include: Small things like a to-do around a piece of code that should be refactored when there is more time to implement a stronger solution. The maintenance left behind after implementing a complex feature. The team may have estimated the feature with a high number of story points, but the product owner still prioritized its development. It was then developed with the best of intentions, but in hindsight, there are likely more efficient and stronger implementations. This creates another source of technical debt. A module of code that was developed for a simple use case, but over time its refactoring means the code is used for a wider range of use cases. Sometimes, code is released without the proper “scaffolding,” the things that make the code strong in a production environment. Scaffolding includes application logging, error checking, exception handling, documentation, and other artifacts. Sometimes, a code module may be better managed as a standalone microservice. This type of transition may be considered by some as an architecture upgrade, but I still label it as technical debt because it is a technology-driven improvement. Sometimes, a team deploys new code using a new version of a library or service and leaves the upgrading of older code to a later time. This delay creates technical debt. Upgrading and patching platforms, third-party services, development tools, and connections to new API versions are also forms of technical debt. Measuring this debt demonstrates how much work the development team believes is needed to best support the application. Applications that have large and increasing technical debt are strong indicators that they are marching toward legacy status. The secret to maintaining applications and avoiding or at least delaying legacy status lies in how organizations and teams manage technical debt. With all these sources of technical debt, how do technical organizations of different sizes manage these issues? One of the toughest issues CIOs face is in managing legacy system and modernizing technologies, so we have a vested interest in managing technical debt. Every Thursday at 2pm ET, I participate in a Twitter chat under the hashtag #CIOChat. I asked that group about their technical-debt strategies and included some of their thoughts on how best to measure and manage technical debt in the five best practices that follow. 1. Managing technical debt starts by measuring it You can’t manage a growing problem without some way of capturing the details and managing it. As Ed Featherston, vice president and principal architect at Cloud Technology Partners, says: Everything is a trade-off. Technical debt is a direct result of that. Decisions are made for expediency that leave a debt that must be repaid. One of the best ways I have seen this dealt with is having a specific tech-debt backlog separate from the product one. This gives visibility/transparency on the accumulated debt, and each spring should include product and tech-debt stories. Itemizing technical debt in the backlog is an important discipline for agile teams. It can be done in sprint as technical debt is recognized, and it can be captured at sprint retrospectives. Featherston and I differ here: I prefer capturing both product enhancements and technical debt in the same backlog but have the technical debt user stories and tasks tagged with a label or under one or more epics. But either approach works as long as the team and product owner have visibility on what technical debt is being added and addressed in every sprint. 2. Use release planning strategies to manage technical debt Most development organizations have an approach to managing application releases where decisions are made on the target scope and timing of a release. Even teams practicing more-continuous release cycles conduct meetings to review short- and longer-term priorities. It’s during these sessions that architects and developers can voice what functionality priorities are complex and may drive new forms of technical debt. In other words, says Wayne Sadin, CDO & CTO at Affinitas Life: Stop adding to technical debt by ensuring project budgets/plans explicitly address ongoing maintenance costs and include retirement (dates/costs/processes) for systems being replaced. The first step in filling in a hole: stop digging! Sadin is alluding to several strong management principles at planning sessions: Discuss complex features at the time of planning and look for more simplified solutions that are easier to implement and introduce less technical debt. Ensure that a percent of the team’s priorities is applied to addressing technical debt. My rule of thumb is that 30 percent of a release’s velocity should be applied to addressing debt and release planning sessions are a good place to discuss and debate priorities. While we all enjoy building new applications and working on innovation, development organizations also need to focus on retiring old platforms, applications, libraries, and code modules. This also can be factored into release plans. Last, and possibly most important, is how the technology organization manages the selection and adoption of new technologies including development platforms and libraries. If you’re selecting a technology because it’s the “next best thing” and that “next best thing” overlaps with technologies already being used, you are creating new technical debt! 3. Devops CI/CD makes it easier to address technical debt One of the key devops practices is in implementing a continuous integration, continuous testing, and continuous delivery pipeline or CI/CD pipeline. This automation takes code checked into a version-control system, packages the application, delivers the code to development or testing environments, and runs though a series of regression tests. With this automation, teams have a lot more confidence in making small, incremental changes to the code base because deployments are scripted, and regression tests identify application issues. Contrast that to legacy applications that don’t have this automation or testing in place. Development teams grow a fear in making changes to these applications because they don’t know what will break and whether deployments can be performed reliably. This fear slows down teams in addressing technical debt and accelerates applications to legacy status. 4. Planning release cycles to address patching and upgrades Smaller technical debt items such as fixing and refactoring code can be done in the scope of a release. But when it comes to larger upgrades, a dedicated “systems upgrade” release to perform and test the upgrades is often needed. System upgrades are best performed without introducing new functionality and capabilities so that the team can validate the upgrade against established tests and known behaviors. Disciplined organizations perform cyclical planning to schedule these upgrade periods when it’s least impactful to business and user needs. As Theresa Rowe, CIO of Oakland University, suggests: We manage technical debt by careful cyclical planning for existing technology investment; investment needs preservation or planned forklifts that match strategic initiatives. For example, if your application runs on Java with a MySQL back end, the development team may look to schedule one major upgrade per year to account for the major release cycles of these platforms. It then should look for periods of relatively low usage to schedule these upgrades. 5. Communicating the state of legacy applications and technical debt It is important to recognize that the state of application maintenance is invisible to most business leaders. They sense a legacy application only when it has poor reliability or when needed functionality upgrades take too long or are too expensive to implement. In other words, they can sense when an application achieves legacy status, but they have poor understanding and visibility on measuring and managing the technical debt that leads to it. It’s a collective responsibility of the technology organization to address this gap. First, by measuring it. Second, by proactively prioritizing and addressing it. Third, by creating reports or communication tools that provide visibility into it. Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos