Legacy Code
Legacy code is existing software that is difficult to modify, extend, or understand. Often, it lacks tests, documentation, or the original developers have moved on. Contrary to popular belief, legacy code isn't inherently bad. It represents software that has delivered value long enough to become entrenched. The challenge lies in evolving it safely.
Key Statistics
- • Over 80% of software development budgets are spent on maintaining existing systems rather than building new ones. / Gartner Research
- • The average enterprise application is 10+ years old and maintained by developers who didn't write the original code. / CAST Software Intelligence Report
- • 70% of developers report spending significant time trying to understand unfamiliar code before making changes. / GitPrime Engineering Intelligence Report
- • Legacy modernization projects have a 60-80% failure rate when attempted as full rewrites. / McKinsey Digital
Why This Matters
Almost every professional developer works with legacy code at some point in their career. Whether it's a decade-old monolith or a two-year-old codebase written by a team that has since departed, the skills required to understand, modify, and improve existing code are essential.
The most successful approaches to legacy code focus on incremental improvement rather than wholesale replacement. Techniques like the Strangler Fig pattern, characterization testing, and strategic refactoring allow teams to evolve systems safely while continuing to deliver business value.
On the Maintainable Software Podcast, guests have shared hard-won wisdom about navigating legacy codebases. Michael Feathers talks about getting legacy code under test. DHH shares his perspective on celebrating legacy software as a victory. And many more.
Episodes on Legacy Code
EP-028 | October 21, 2019
Michael Feathers: Be Curious & Chase The Rabbit Holes
EP-050 | April 13, 2020
Sandi Metz: Making is Easy, Mending is a Challenge
EP-108 | October 4, 2021
DHH: Celebrating Legacy Software as a Victory and the Story of How Humans Can't Estimate
EP-111 | November 22, 2021
Chris Birchall: Re-Engineering Legacy Software
EP-121 | May 16, 2022
Chelsea Troy - All Code Has Maintenance Load
EP-185 | October 1, 2024
April Wensel: Navigating Legacy Code with Compassion
EP-038 | January 13, 2020
M. Scott Ford: Menders In Hiding and the Joy of Legacy Code
EP-075 | November 16, 2020
Adrianna Chang: Using the Strangler Fig Pattern at Shopify
EP-171 | June 4, 2024
Stig Brautaset: Understanding Alien Artifacts in Legacy Code
EP-091 | March 8, 2021
Benjamin Wood: Rescuing Ruby on Rails Projects
EP-071 | October 19, 2020
Nicolas Carlo: Changing Messy Software Without Breaking It
EP-006 | May 20, 2019
Eileen M. Uchitelle: Upgrading Ruby on Rails At Github And How To Stay Updated
Frequently Asked Questions
What is legacy code?
Legacy code is generally defined as existing code that is difficult to change safely. Michael Feathers famously defined it as code without tests. More broadly, it includes any codebase where the original context, documentation, or developers are no longer available, making modifications risky and time-consuming.
How do you modernize legacy code without rewriting it?
The most effective approach is incremental modernization using patterns like the Strangler Fig, where new functionality gradually replaces old components. Start by adding characterization tests to understand existing behavior, then refactor in small steps. This reduces risk compared to full rewrites while delivering continuous improvements.
What are the risks of working with legacy code?
Key risks include introducing regressions due to lack of test coverage, misunderstanding business logic embedded in the code, underestimating the complexity of dependencies, and developer burnout from working in frustrating codebases. Mitigate these through incremental testing, documentation, and pair programming.
How do you add tests to legacy code?
Start with characterization tests that capture the code's current behavior, even if that behavior includes bugs. Use Michael Feathers' 'seam' technique to find points where you can alter behavior without changing the code. Focus testing efforts on the areas you plan to modify first, then expand coverage incrementally.
When should you rewrite vs. refactor legacy code?
Rewriting is rarely the right answer. Studies show 60-80% of rewrite projects fail. Refactoring is safer and delivers value incrementally. Consider rewriting only when the technology stack is completely obsolete, the codebase is very small, or the business requirements have changed so fundamentally that the existing architecture can't support them.