🗺️ Map Dependencies and Take Inventory
AI can map dependencies, explain code, document interfaces, and find dead code — reading a lot of code and summarizing its structure is where it delivers the most value. Start there: know the actual size of the problem before proposing a solution.
How to read: the entire process in one image. The cyan boxes are the evidence steps — characterize, run in parallel, compare. They turn "I think it’s the same" into proof, which is why none of them is optional.
🆕 New here?
Legacy here, it doesn’t mean "old": it means code in production that no one fully understands and that doesn’t have enough tests to be changed safely. Characterization test is a test that describes what the system does today (not what it should do). Adapter is a thin layer that translates between the old and new worlds.
Inventory
Before the plan
Dead code
Cheapest cut
Who calls whom
Defines the boundary
Risk
Decrease, don't increase
🔎 Identify Hidden Business Rules
Every legacy system carries rules that were never written down anywhere: historical exceptions, special cases for large customers, rounding with a tax-related reason, deadlines inherited from a 2014 contract. These are the ones that break during a rewrite.
⚠️ Typical legacy risks
🧪 Copyable exercise — extract the rules from the code
Objective: turn legacy code into an auditable list of rules. Choose a module you need to modernize.
Leia <caminho do módulo legado> inteiro. Não altere nada. Produza uma tabela de REGRAS DE NEGÓCIO observadas no código, com colunas: regra (em português, uma frase) | onde está (arquivo:linha) | condição que a dispara | o que acontece quando não vale | parece intencional ou acidental? Regras: - descreva o que o código FAZ, não o que deveria fazer; - inclua casos especiais, exceções, valores mágicos e datas fixas; - não invente justificativa de negócio — se não souber, escreva "desconhecido"; - ao final, liste em "PERGUNTAR AO NEGÓCIO" as regras que parecem acidentais ou que você não consegue explicar.
How to verify: take the "ASK THE BUSINESS" list to the people who operate the system. Every rule someone recognizes becomes a characterization test in the next section; every rule no one recognizes is a candidate for removal — but only after it's confirmed.
Code = truth
Docs capture old intent
Magic value
Usually a rule
Regulatory
Doesn’t get “simplified”
Ask
Before removing
🧪 Write Characterization Tests
Characterization testing records current behavior — including what seems wrong. It does not judge; it takes a snapshot. It is the safety net that makes modernization possible.
✓ Well-done characterization
- ✓Record the current output, even if it’s strange, with a comment: "current behavior, not validated"
- ✓Covers real inputs collected from production (anonymized)
- ✓Include edge cases: null, empty, negative, boundary date, maximum value
- ✓Runs against the old system before of any change
✗ Pitfalls
- ✗"Fix" the strange behavior while writing the test
- ✗Test only the happy path—the legacy system lives in edge cases
- ✗Write the expected result based on the documentation, not the execution
- ✗Use production data without anonymizing it
💡 Practical tip
Generating characterization tests at scale is one of the best uses of AI: ask the agent to produce dozens of cases from real inputs, run them against the current system, and save the output as the expected result. You review the list instead of writing the tests one by one.
Captures
Doesn’t judge
Bug included
It’s also behavior
Real input
Anonymized
Volume
Where AI shines
🕵️ Discover Hidden Integrations
The biggest cause of post-migration incidents is simple: you turned off something “nobody used”—and someone did. A script, a spreadsheet, a report that reads the database directly, a job owned by another team.
Look at access, not the code
API logs, database connections, endpoint calls, file reads. Consumers show up in the traffic, not the repository.
Observe for one full cycle
One week isn’t enough if there’s a monthly close, quarterly report, or annual routine. The most dangerous consumer is the one that only shows up on the 1st.
Turn it off in stages
Notify → deprecate (with a warning on every use) → degrade → remove. Each step gives someone a chance to show up and say, “That’s mine.”
Traffic
Reveals the consumer
Complete cycle
Monthly, quarterly, yearly
Deprecate
Before removing
Silence
Doesn’t prove disuse
🧱 Isolate Boundaries and Create Adapters
Before changing anything, create the seam: an interface between the consumer and the implementation. With the adapter in place, you can swap the engine without touching the driver—and roll back with one line.
📐 How to choose the right boundary
- •Few consumers (you can notify everyone).
- •Narrow contract: few operations, simple data.
- •Behavior already covered by characterization tests.
- •Clear value in migrating first (known pain, not just “it’s ugly”).
⚠️ Attention
Without a defined boundary, the migration becomes a rewrite: each piece pulls in another, the scope explodes, and the project ends up in that state where the new system isn’t ready and the old one is no longer maintained. That’s the worst possible place.
Stitching
Before switching
Narrow contract
Makes switching easier
Bottleneck
Piece by piece
Easy to roll back
Change the implementation
⚖️ Run in parallel and compare
Both implementations receive the same input; the old one keeps responding; the new one only logs what it would respond. Every discrepancy becomes a case to investigate. This is the strongest proof there is.
Comparison panel (illustrative recreation, not an actual screenshot)
requests compared .......... 148.302
identical ...................... 148.061 (99,84%)
divergent .................... 241
├─ cent rounding ............. 233 <- forgotten tax rule
├─ client with a 2014 contract ... 7 <- historical exception
└─ date 29/02 ................. 1 <- leap year
no customer response was changed (shadow mode)
How to read: 99,84% similarity is not approval — the 241 discrepancies are the actual content of the report. Each one is a rule the characterization tests missed. That’s why you run it in shadow mode before switching over.
Quick check: you’re modernizing an old module with no tests. What’s the first step?
Shadow mode
New means observe only
Divergence
It’s valuable information
Gradual
1%, 10%, 50%, 100%
Back
Available until the end
📌 Module Summary
Next Module:
4.2 - Agent-friendly architecture: predictable structure, AGENTS.md, and single sources of truth.