A legacy rescue starts with understanding.
Before the rewrite: map the behavior, add protection, change one thing.
Resist the instant rewrite
An unfamiliar codebase can look worse than it is. Awkward code may contain important business behavior that no longer exists in a specification. Before changing it, identify the users, critical workflows and external systems that depend on it.
AI can help navigate files and propose explanations. Treat those explanations as hypotheses until you confirm them in code, tests or the running application.
Protect the behavior that matters
Add checks around the most important paths before restructuring. A regression test does not need to bless every historical implementation detail. It should protect a behavior that users rely on, including a relevant failure case.
If production access is needed for investigation, agree on permissions and data handling first. Prefer a reproducible case in an isolated environment.
Make one reversible change
Fix a bounded issue and compare the result with the baseline. Keep data migrations explicit, preserve a recovery path and avoid mixing a broad formatting change with a behavior fix. Small diffs make review more effective.
Modernize where there is a reason
A dependency upgrade, a clearer boundary or better monitoring may remove the immediate risk without replacing the entire system. A larger migration can still be the right decision, but it should follow evidence about cost and risk.
Read about rescue missions and how we validate changes.