How to Answer "Describe Working with Legacy Code"
Legacy code is the reality of professional software development. Most engineering work involves maintaining, extending, or gradually modernizing existing systems rather than building from scratch. This question evaluates your patience, pragmatism, and ability to deliver value within imperfect constraints.
Interviewers want to see someone who respects legacy code as a working system, understands why it exists in its current form, and can improve it incrementally without introducing regressions or alienating the team.
What Interviewers Are Really Assessing
- Pragmatism: Can you work productively within imperfect systems?
- Patience: Do you approach legacy code with curiosity rather than frustration?
- Risk management: Can you make changes without breaking things?
- Incremental improvement: Do you leave the code better than you found it?
- Empathy: Do you respect the context in which the code was originally written?
How to Structure Your Answer
Use the Understand-Stabilize-Improve framework:
1. Understand the System (25%)
How did you learn how the legacy code worked? What was its history and purpose?
2. Stabilize Before Changing (30%)
What safety nets did you establish before modifying the code? Tests, monitoring, documentation?
3. Improve Incrementally (45%)
How did you make the code better while continuing to deliver business value? What was the outcome?
Sample Answers by Career Level
Entry-Level Example
Situation: Tasked with adding a feature to an older codebase. Answer: "I was assigned to add a notification feature to a PHP application that had been running for six years with minimal documentation. My first instinct was to rewrite the relevant module, but my senior colleague advised me to understand it first. I spent three days reading the code, tracing execution paths, and writing characterization tests that documented the current behavior. This saved me from a mistake: I discovered the module had an undocumented dependency on a specific execution order that a rewrite would have broken. With tests in place, I added the notification feature by carefully extending the existing patterns rather than fighting them. I also documented the module's architecture for the next developer. The feature shipped without incident, and my team lead said the documentation was the most valuable part of my contribution."
Mid-Career Example
Situation: Modernizing a legacy monolith while maintaining feature delivery. Answer: "Our main application was a ten-year-old Rails monolith with over 500,000 lines of code. It worked but was increasingly difficult to modify: no test coverage in critical paths, global state everywhere, and deployment took 45 minutes. Rather than proposing a rewrite, which would have taken years, I introduced the Strangler Fig pattern. For each new feature or significant modification, we'd extract the relevant domain into a clean module with proper tests and interfaces, then route traffic to the new module. I started with the billing module because it was both high-risk and frequently changing. Over four months, I extracted billing into a well-tested, documented module while maintaining backward compatibility. The rest of the team adopted the pattern for their areas. After a year, we'd modernized the highest-change areas while the stable, rarely-touched legacy code continued running untouched. Deployment time dropped to 8 minutes for the extracted modules, and bug rates in modernized areas dropped 70%."
Senior-Level Example
Situation: Leading a legacy modernization strategy for the organization. Answer: "I inherited a platform with three legacy applications that the company had been afraid to modify for years. Teams were routing around them with workarounds that created even more complexity. I established a modernization strategy built on three principles: never rewrite, always extract; every modernization deliverable must include a business feature; and measure progress by change failure rate and deployment frequency, not lines of code rewritten. I created a risk-heatmap of the legacy systems, scoring each component by change frequency, business criticality, and defect rate. The highest-scoring areas were modernization candidates. The first year, we extracted four high-risk modules and wrapped the rest in anti-corruption layers. Change failure rate dropped from 30% to 8%, and teams that had been avoiding the legacy code started modifying it confidently because the new interfaces protected them from ripple effects. The key insight I share with my teams is that legacy code is not the enemy. It's a working system that has been delivering value for years. Our job is to make it easier to evolve, not to replace it for the sake of newness."
Common Mistakes to Avoid
- Proposing a full rewrite: The impulse to rewrite everything signals immaturity. Show that you understand why incremental approaches are usually safer.
- Disrespecting the original developers: Legacy code was written under constraints you may not understand. Show empathy for the decisions that were made.
- Skipping safety nets: Making changes to legacy code without tests or monitoring is reckless. Show that you prioritize stability.
Tips for Different Industries
Technology: Emphasize specific modernization patterns (Strangler Fig, anti-corruption layers) and how you maintained delivery velocity during the transition.
Consulting: Client legacy systems are often politically sensitive. Show that you can navigate the human aspects of modernization, not just the technical ones.
Finance: Legacy financial systems often have compliance implications. Show awareness of regulatory requirements during modernization and the importance of data integrity.
Healthcare: Clinical legacy systems may have patient safety dependencies. Show that you approach modernization with extra caution and thorough testing for healthcare applications.
Practice This Question
Ready to practice your answer with real-time AI feedback? Try Revarta's interview practice to get personalized coaching on your delivery, structure, and content.