Portfolio Services Company Contacts Blog Get a Quote
uaruen
Mnemosyne organises a book, documents and a dependency map in a marble archive.
Technology

AI for legacy code: how to explore, document and refactor an unfamiliar system

Ivan Deineka
Ivan Deineka
CEO at BotLabs
· Updated 11 min read
Key takeaway: Use AI to map an unfamiliar legacy system, capture its behavior in tests, document assumptions and refactor in small, verifiable steps.

AI can help with legacy code, especially when a team is first learning how a system works. It can explain what a function does, where a call comes from, which tables are read and which external services are involved. It can also draft documentation and suggest small changes. But a model’s explanation is a hypothesis about code, not knowledge of the business. Independent checks must confirm that a refactor preserves behavior; the same model saying “nothing changed” is not enough.

A safer sequence is to map the system first, capture its observed behavior in tests, and only then change the code in small steps. This article helps you choose tasks for AI, distinguish verified facts from assumptions, decide what evidence to require before accepting a refactor and recognize when to stop.

What AI can learn from code

Code contains many answers that would take a person a long time to find manually. AI can help with:

  • Call chains: who calls a function, what it calls next and where request handling ends.
  • Dependencies: which libraries, modules and external services are used and where.
  • Data: which tables, files and queues are read or changed and which fields feed a calculation.
  • Likely purpose: a short explanation such as “this function appears to calculate wholesale-customer discounts,” based on names, comments and logic.

The last item is the riskiest. Code shows what happens, but not always why. If a function skips commission when a region equals 7, a model may plausibly say it is a regional benefit. In reality, it could be a temporary exception for an old partner agreement or a workaround for a bug in another system. That business context may not be in the code, and AI cannot recover it. People may know it: process owners, finance, support, or perhaps only an old email archive.

Whether AI speeds up the work is a separate question without a universal answer. In one randomized study in early 2025, 16 experienced developers completed 246 tasks in open-source projects they knew well. When AI tools were allowed, tasks took 19% longer on average, even though participants expected a 24% speedup beforehand and believed afterward that they had been 20% faster. This was a snapshot of the tools available at the time in one specific setting, not an estimate for all teams or today’s systems; the authors later described the result as outdated. In a follow-up assessment published in 2026, repeating the measurement became harder: some developers declined to work without AI, and 30–50% of respondents said they had withheld some tasks they did not want to do without it. New estimates pointed more toward acceleration, but the authors called the evidence very weak. For a legacy project, do not plan from someone else’s average or rely on team perceptions; measure your own tasks.

How to rebuild a system map

Before making changes, map what is in the system and what matters most. AI can help draft the map, but a person must verify every item.

Entry points. Where requests enter: web pages, APIs, schedulers, queue handlers or file imports. Ask AI to find route registrations, scheduled jobs and message handlers, then compare the list with server and scheduler configuration. External jobs, such as a system scheduler on another server, may not appear in the code at all.

Critical operations. Which actions involve money, legal documents, personal data or inventory. AI can suggest candidates, but process owners decide what is critical.

External services. Payment providers, delivery services, accounting software and email platforms. For each one, find out what the system sends and receives and what happens if the service does not respond.

Data owners. Who decides how a calculation should work and who is responsible for a table or reference list. If there is no owner, that is an important finding.

Where state lives. Databases, files, caches, environment variables and admin-panel settings. Pay particular attention to behavior that depends on data outside the repository.

A useful map is a table with columns for component, purpose, evidence and who confirmed it. The last column may start mostly empty. That makes unverified knowledge visible.

How to capture behavior

The main risk of legacy refactoring is losing behavior that nobody knew about but something or someone depends on. Characterization tests help prevent this. They record how the system works now, not how it should work. If current behavior is odd, the test still captures it; whether it is a bug is a separate question.

A practical process:

  1. Choose the function or scenario you plan to change.
  2. Gather inputs: typical values, boundaries, empty and invalid data, negative numbers and very large values. AI can suggest edge cases a person may overlook.
  3. Run the current code with those inputs in an approved environment and record the actual results. Run it; do not ask a model to predict the result.
  4. Turn the input/result pairs into tests.
  5. De-identify test data. Real names, phone numbers and account numbers do not belong in test fixtures.

Also record side effects: which database rows appear, which emails are sent and which files are created. External services may need stubs, but build them from recorded responses rather than guesses about how the service ought to respond.

How to write documentation

Confident wording can easily make legacy documentation misleading. “This function calculates loyalty rewards” sounds like a fact but may be a model’s guess based on a variable name. A year later, no one may remember that nobody checked it.

Tie each documented fact to evidence: a file, function, test, observation or confirmation from a specific person. Label unverified claims as hypotheses. A template for describing a function or module:

FieldWhat to recordExample
PurposeWhat it does, marked “confirmed” or “hypothesis”Hypothesis: calculates wholesale-customer discounts
InputsParameters, data sources and settingsOrder amount, customer type, pricing table
OutputsWhat it returns and in what formatInteger number of cents
Side effectsDatabase writes, emails and service callsAdds a row to the discount log
EvidenceWhat supports each itemCharacterization tests for 14 inputs; process owner confirmed the threshold
UnknownsWhat could not be establishedWhy region 7 receives no discount

“Unknowns” is not a formality. It identifies risky parts of a refactor and creates a concrete question list for process owners. You can ask AI to fill in the template, but require a code location for every claim. Unreferenced claims should go into the hypothesis column.

How to refactor

Refactoring is safer when you work in small steps:

  • One kind of change at a time. Rename separately from extracting a function or updating syntax. A mixed diff is harder to review.
  • Keep the diff small. If a reviewer cannot understand it in one pass, split it up.
  • Test boundaries before changing code. Characterization tests should pass before and after.
  • Check compatibility. Review data formats, APIs used by other systems and behavior under load.
  • Plan rollback. Know how to restore the previous version quickly if a problem appears after release.

Treat model self-review with caution too. One unreviewed 2026 preprint described 1,980 model calls to modernize 60 Python 2 snippets using 11 models from seven families. Every change was checked with a strict behavioral test. Behavior changed in 39.7% of snippets with semantic traps, compared with 7.0% in control snippets without traps. The models then judged whether behavior had been preserved. Of 262 behavior changes, the same model endorsed 83, or 31.7%, as correct. Results varied substantially: five models had no such misses, while one missed all of them. Some models described the Python 2/3 distinction that broke their output and then said behavior had been preserved.

The study has clear limits: short snippets in one language and one task type, not full enterprise systems. It does not tell you how often errors will occur in your project. Its practical lesson for legacy work is that a convincing model explanation cannot replace an independent behavior check.

A learning example: division when moving from Python 2 to Python 3

This is a teaching example of the method. In Python 2, / between two integers performs floor division: 7 / 2 gives 3, while -7 / 2 gives -4. In Python 3, the same operator performs true division: 7 / 2 gives 3.5. Two conditions change the picture. If a Python 2 module imports from __future__ import division, / already behaves as it does in Python 3. And if either operand is a float, Python 2 returns a float too: 7.0 / 2 gives 3.5.

Consider common “fixes.” Leaving / unchanged changes integer results from 3 to 3.5. Replacing it mechanically with // preserves integer behavior, but if the function ever received floats, 7.0 // 2 gives 3.0 instead of the former 3.5. Wrapping the expression in int(a / b) gives -3 for negative values instead of -4, because int truncates the fractional part rather than rounding down.

Require three things from anyone making the change, human or AI:

  1. The original behavior, obtained by running the old code with several inputs: positive and negative integers, floats, a zero denominator, and a check for division imported from __future__.
  2. The expected contract: which types actually reach the function in production and whether the result must remain an integer.
  3. A test after the change that produces the same results for the same inputs.

“I accounted for Python 2 and 3 differences” is not evidence. A table of inputs and outputs before and after is.

When to stop

Not every part of a legacy system should be refactored with AI, even in small steps. Some situations need a separate discussion with process owners.

Unknown calculations. If a function calculates money, taxes, accruals or penalties and no one can explain the rules, first establish the rules instead of producing a new version of the code.

Data migrations. Changing table structures or storage formats affects accumulated data as well as code. Rolling back a migration is difficult once new data has been written in the new format.

External side effects. Payments, customer emails and documents sent to government systems cannot be undone by rolling code back.

No reproducible check. If behavior cannot be captured in tests because there is no test environment or the needed data is inaccessible, any refactor is a blind bet.

AI can still help in these cases by mapping the system, explaining code, listing questions and drafting tests. But do not change the code until a meaningful check exists.

Summary and first steps

AI can shorten the path to understanding a legacy system, but it does not make that understanding automatically correct. A model explanation is a hypothesis; documentation without evidence is a risk; and refactoring without an independent behavior check is a bet, however confident the model sounds.

On your project, you can:

  1. Ask AI to draft a system map of entry points, critical operations, external services and state storage. Record who confirmed each item.
  2. Choose a small module and write characterization tests with de-identified data by running the real code.
  3. Document the module using a template for purpose, inputs, outputs, side effects, evidence and unknowns.
  4. Make the first refactor with one kind of change and a small diff, with a rollback plan.
  5. List stop zones — unknown calculations, migrations, irreversible actions and areas without checks — and write a question for the process owner for each.
  6. Compare actual time spent with expectations so future estimates use your own data.

If you need to define a technical pilot — where to start, which behavior checks to capture and who will maintain integrations after changes — BotLabs can review the system with you and suggest a realistic first step.

Frequently asked questions

You can, but the risk of losing unknown behavior rises. Tests written after a rewrite check the new version, not how the system worked before. If the old function had a subtle behavior, such as a particular rounding rule or an exception for certain customers, post-rewrite tests will not capture it. It is safer to create independent checks for important contracts on the old code before changing it.

Label them honestly as unknowns or hypotheses. Tie confirmed facts to code, test results, observations in an approved environment or a specific process owner’s confirmation. Keep hypotheses in a separate question list and work through it with people who know the process, such as finance, support or sales. An AI explanation does not become knowledge just because it is written down.

It may help with individual steps: mapping dependencies, explaining code, drafting tests and making small transformations. But a large migration is safe only if behavior can be checked, dependencies between components are understood, data has a migration plan and every stage has a rollback path. Without those, even a capable assistant cannot make the migration safe.

Request a consultation

15 min · specialist consultation

Legacy code pilot consultation

In 15 minutes with a BotLabs technical specialist, discuss one legacy module, known business rules and how its behavior can be tested. Identify the evidence needed before changing the code and the first step in preparing a pilot.

15 minutes with a specialist.

A BUSINESS CONSULTATION
LEGACY MODULE → BEHAVIOR CHECKS → NEXT STEP

Legacy module
Behavior checks

15 minutes with a specialist to define a module boundary and the behavior checks needed before refactoring.

technical consultation15 min · specialist consultation
… click to support
Ivan Deineka
Ivan Deineka
CEO at BotLabs
Ivan Deyneka is an entrepreneur and founder of BotLabs Agency, with over 8 years of experience launching and scaling digital products in the field of business automation.
← Back to Blog

Recommended articles

Pilot for a legacy module15 minutes with a specialist.Request a consultation