Understanding and Modernizing Old Codebases with AI
Legacy code without tests can't just be rewritten โ characterization tests and small steps make AI-assisted modernization safe.
What makes legacy code different
Software developer Michael Feathers once defined legacy code bluntly as "code without tests." That's exactly what makes it dangerous to change: nobody โ not even an AI agent โ can verify whether a change breaks behavior if there are no tests capturing that behavior in the first place.
Step one: capture behavior, don't improve it
Before restructuring anything, you need characterization tests. These are tests that write down what the code does RIGHT NOW โ even if that looks odd or outright buggy. They're not a quality judgment, just a snapshot that protects later changes.
Step two: migrate incrementally
A full rewrite is risky: nothing runs reliably until the new version is done, and subtle old behavior often gets lost along the way. Incremental migration is the more proven approach โ a pattern known as the "strangler fig": new pieces grow around the old code bit by bit, until the old one can eventually be switched off.
Where AI agents help most
An agent can quickly summarize large, undocumented modules and propose candidate characterization tests โ work that's normally very costly without documentation. What still matters: understand and secure first, only then change.
EXAMPLE
Prompt: 'This 1,800-line module has no tests and no docs. First summarize what it does functionally. Then write characterization tests for the five most important functions that capture the CURRENT behavior โ even if it looks odd. Don't change any code yet.'
๐ ๏ธ EXERCISE โ TRY IT YOURSELF
Take an untested, tangled module from one of your own (or an open-source) projects and lock it down with characterization tests before changing anything.
- Have the agent first summarize what the module does functionally, without changing any code.
- Together, identify 3-5 typical inputs/calls and have the agent write tests that capture the current outputs as expected values.
- Only then: make one small, isolated change and check whether the characterization tests are still green.
โ SELF-CHECK
- โ Do the tests cover the most important paths, not just the simplest case?
- โ Did you deliberately capture the CURRENT behavior instead of already 'improving' it while testing?
- โ Is everything still green after the first change โ or does a failing test show exactly what changed?
QUICK QUIZ
What is a characterization test?
SOURCES
- Characterization test โ Wikipedia โ en.wikipedia.org
- Legacy code โ Wikipedia โ en.wikipedia.org
- Strangler Fig Application โ martinfowler.com โ martinfowler.com
- Strangler Fig pattern โ Microsoft Learn โ learn.microsoft.com
- Legacy Seam โ martinfowler.com โ martinfowler.com