AI-Assisted Code Migration and Modernization
Overview
Your organization is sitting on 2 million lines of Python 2 code. It's completely deprecated. The language is no longer supported. Security vulnerabilities won't be patched. Everyone on the board is asking when you're going to do something about it.
Manual migration? That's three to five years of engineering effort. You'd need to pull engineers off every other initiative. The cost would be tens of millions of dollars. And at the end, you'd have code that's slightly less broken, but still carrying all the architectural debt and organizational knowledge gaps from the original system.
This is the modernization nightmare every CTO faces: massive legacy systems that need updating, but the cost of updating them manually is so high that doing nothing starts to look reasonable.
AI changes the equation completely. You can migrate millions of lines of code in weeks, not years. Not perfectly. There will be edge cases that need human review. But good enough that the remaining work becomes manageable iteration, not fundamental rewrite.
The core insight: code migration is mostly pattern recognition and pattern replacement. It's the exact kind of repetitive, high-volume work that AI excels at. Humans can't do 10,000 files consistently. AI can. And what AI gets wrong, humans can fix methodically, learning and improving as they go.
This lecture is about the real-world mechanics of AI-assisted migration. How companies are actually doing this. What works. What doesn't. And how to plan a migration strategy that actually ships.
Why Traditional Code Migrations Fail
Before we talk about how AI fixes migration, we need to understand why migrations are so hard in the first place.
The Volume Problem
A migration from Python 2 to 3 isn't complex per file. Each change is simple: remove print statements, fix imports, update string handling. A good engineer can migrate a single file in an hour or two, including testing.
But here's the problem: there are 10,000 files. One engineer working full-time would need 5,000 weeks. That's 96 years of engineering time. You can't hire 96 engineers to do this. The overhead alone would sink you.
This is what kills most migrations: not technical complexity, but sheer volume. The work is straightforward, but there's too much of it.
Consistency at Scale
Even if you could somehow parallelize the work across multiple engineers, you'd hit another problem: inconsistency. One engineer might handle error cases one way, another engineer a different way. Someone might miss an edge case. Someone might make an assumption that's wrong in 20% of the codebase.
By the time you finish, you've migrated the code but introduced subtle inconsistencies that cause production issues. Your tests catch some of them. Some make it to production.
AI doesn't get tired. It doesn't make assumptions that vary based on mood. It applies the same rule consistently to all 10,000 files.
Knowledge Extraction
The worst part about traditional migrations: the knowledge dies. Someone figures out how to handle a tricky case. They fix 50 instances manually. That knowledge is in their head. Six months later, they leave the company. A new engineer encounters the same problem and has to figure it out again.
With AI-assisted migration, you're building explicit rules that get applied everywhere. The knowledge is captured in transformation logic, not in people's heads.
Test Coverage Gaps
You can't test your way out of migration problems if you haven't written tests. And the systems most needing migration usually have terrible test coverage. They're 15 years old. Nobody wrote automated tests for them.
So you can't just migrate the code and run the tests. You have to write tests as you go, or accept that some migrations will fail in production.
AI can help with this too. It can generate tests as it migrates. Not perfect tests, but better than nothing.
Types of Migrations AI Can Accelerate
Language and Runtime Upgrades
Python 2 to 3. Java 8 to 17. Ruby 2.4 to 3.0. Node 12 to 18. These are the most common migrations. The syntax changes are systematic. The API changes are well-documented.
AI can handle these migrations almost automatically. Feed it the language documentation. Feed it your code. It maps old patterns to new patterns and applies the transformation.
Success rate: 85-95% on the first pass. The remaining 5-15% are edge cases or code that's doing weird things you don't want it to do anyway.
Framework Migrations
Django 2 to 3. Rails 5 to 6. Express 4 to 5. React class components to functional components with hooks. These are harder than language upgrades because the API changes are more dramatic.
But they're still systematic. You're replacing one set of patterns with another. AI can learn the mapping.
Success rate: 70-85% on the first pass. Framework migrations have more context-dependent logic, so more edge cases.
Library Migrations
Moving from one ORM to another. One test framework to another. One logging library to another. These are usually smaller in scope, but equally painful because they're scattered throughout the codebase.
AI excels at these. All 500 places where you call the old logging API get updated to the new one simultaneously.
Success rate: 90%+ because library APIs are well-defined and consistent.
Database Schema Changes
Migrating from MongoDB to PostgreSQL. Reshaping data from one format to another. Migrating from a monolithic database to a sharded architecture. These involve both code changes and data transformations.
AI can help with the code migration side. You'll still need database engineers for the data transformation itself, but AI accelerates the application code changes.
Success rate: 75-85%, mostly limited by the complexity of data transformations.
Architecture Migrations
Moving from monolith to microservices. Extracting services from a monolith. Breaking dependency chains. These are the hardest because they require decisions, not just transformations.
AI can't fully automate these. But it can automate 50% of the work: extracting code, refactoring dependencies, handling the mechanical parts of service extraction. Humans still make the decisions about boundaries and dependencies.
Success rate: 50-60% because these require human judgment about architecture, not just pattern replacement.
Rule of thumb: If the migration can be expressed as "replace pattern A with pattern B," AI can handle 80%+ of it. If the migration requires architectural decisions, AI can handle 50% of it. If the migration is something no one has ever done before, AI is less useful (but can still help with the pattern parts).
The Five-Phase AI-Assisted Migration Process
Phase 1: Assessment and Scoping (2-3 weeks)
This is the most critical phase. You need to understand what you're migrating before you start.
Start by analyzing your codebase with AI. Don't ask it to migrate anything yet. Ask it to understand.
Feed it representative samples from each major component. Ask: "What patterns do you see? What's consistent? What's unusual? What will be hard to migrate?"
At the same time, you're running static analysis tools to get the scope. How many files? How many lines of code? How many instances of the pattern you're trying to change? How many external dependencies? How many test files?
The output of phase 1 should be a detailed migration map: here's what needs to change, here's how many places need to change, here's the risk level for each type of change.
This phase also includes talking to the team. What parts of the codebase are fragile? What parts have weird workarounds? What's the business impact if a migration introduces bugs? Which teams need to be involved in validation?
You should exit phase 1 with: (1) a detailed scoping document, (2) a list of high-risk areas that need manual review, (3) buy-in from the team, and (4) a clear definition of success.
Phase 2: Build and Validate Transformation Rules (2-3 weeks)
This is where you translate the migration map into executable rules. You're not migrating yet. You're building the migration logic.
Start with a small, well-tested subset of your codebase. Maybe 5% of files. Define the transformation rules in that subset. Get them working. Get them validated by humans.
The rules are typically expressed in one of three ways:
1. Regex-based transformations: For simple text replacements. "Replace import old_lib with import new_lib".
2. AST-based transformations: For code structure changes. Parse the code into an abstract syntax tree, modify it, regenerate. Good for language upgrades and framework migrations.
3. AI-assisted transformations: For complex logic. Feed the code to Claude, ask it to apply the transformation, review the output, keep the good ones.
In practice, you'll use all three. Simple stuff with regex. Structure changes with AST manipulation. Complex logic with AI and human review.
Validate on your 5% sample. Get humans to review the output. Do the migrated code and original code behave the same? Are tests passing? Are there subtle differences?
Iterate until you're confident the rules work. Then document them.
Phase 3: Bulk Apply at Scale (1-2 weeks)
Now you apply the rules to the entire codebase. This is the scary part. But if you've done phases 1 and 2 right, it's mechanical.
Use your transformation tools to apply the rules in bulk. Regex for simple replacements. AST tools like libcst (Python) or babel (JavaScript) for structure changes. Custom scripts wrapping AI for complex logic.
The output: your entire codebase migrated. All 10,000 files transformed.
This phase should take a few hours to a few days, depending on codebase size. Mostly waiting for tooling to run.
Now you commit all the changes. Yes, all 10,000 files at once. You'll deal with review in phase 4.
Phase 4: Test and Fix (3-6 weeks)
This is where things get real. Run your test suite. See what breaks.
Some things will break because the migration is wrong. Some things will break because the code had bugs you didn't know about. Some things will break because the tests themselves need updating.
You're now running AI through a secondary pass on everything that failed. "Here's the error. Here's the code. Can you fix it?" Sometimes it gets it right. Sometimes you need humans to review.
Create a bug tracking system. Tag each failure by category: transformation error, test needs update, code had a latent bug, environmental issue. This helps you identify patterns and fix multiple instances at once.
As failures get fixed, run the tests again. You're aiming for all tests passing. Don't settle for 95% passing. That's the 5% that will crash in production.
You'll also want humans to do a second review on high-risk areas. Database interactions. Security-sensitive code. Performance-critical paths. These should be reviewed by a human engineer, even if tests pass.
Budget more time for this phase than anything else. Testing and fixing is where your migration succeeds or fails.
Phase 5: Staged Deployment (2-4 weeks)
You've got a migrated codebase that passes tests. Now you deploy it to production, but carefully.
Week 1: Deploy to staging. Run load tests. Compare behavior to production. Look for issues.
Week 2: Deploy to a canary (5% of traffic). Monitor. If issues, roll back. If clean, expand.
Week 3: Deploy to 50% of traffic. Monitor for a week.
Week 4: Deploy to 100%. Keep monitoring for two weeks.
Throughout this process, you're watching metrics: error rates, latency, resource usage, business metrics. You want to catch any issues before they become production incidents.
This phase is insurance. If you did phases 1-4 right, nothing should go wrong. But if something does, you catch it before it affects all your users.
Success criterion: All tests passing. High-risk code reviewed by humans. Zero regressions detected in production after one week at 100% traffic.
Tools and Frameworks for AI-Assisted Migration
Semgrep for Pattern Matching and Transformation
Semgrep is a static analysis tool that can find patterns and transform them. You write rules in YAML. It scans your codebase and applies transformations.
Best for: library migrations, simple API changes, consistent pattern replacements.
Example: migrate all calls from db.query(sql) to db.query_safe(sql). Semgrep can do this in seconds across your entire codebase.
Limitation: Semgrep is good at straightforward replacements, but struggles with context-dependent logic.
AST Manipulation Tools
For language-specific work, use AST tools. libcst for Python. Babel for JavaScript. tree-sitter for multiple languages.
These tools parse code into an abstract syntax tree, let you modify the tree, then regenerate code.
Best for: language upgrades, syntax changes, refactoring that requires understanding code structure.
Example: Python 2 to 3. Parse the code into an AST. Find all print statements. Convert them to print() function calls. Regenerate.
Claude for Complex Transformations
For migrations that can't be expressed as simple rules, use Claude. Feed it code and a transformation requirement. Ask it to apply the transformation. Review the output. Keep the good ones.
Best for: framework migrations, refactoring that requires understanding intent, moving to new idioms.
Example: React class components to hooks. Claude understands the semantic mapping between class lifecycle methods and hook equivalents. It can do the conversion intelligently.
Workflow: Batch your code into files. For each file, ask Claude to transform it. Save the output. Have humans review. Accept good ones, iterate on bad ones.
Custom Scripts and Orchestration
Most real migrations use a combination of tools. You write a script that:
- Runs Semgrep for simple transformations
- Runs AST tools for structural changes
- Runs Claude for complex logic
- Validates the output (syntax checking, running tests)
- Reports what succeeded and what needs human review
This script becomes your migration engine. You can run it on different parts of your codebase, iterate on the rules, and progressively improve the success rate.
Tools like GitHub Actions or Gitlab CI can orchestrate this. You commit your migration rules. The CI runs them. You get a report of what changed and what failed.
Version Control as Your Safety Net
All of this only works if you're using version control. Before you migrate, branch. Apply all transformations on the branch. Run tests. Review. Merge when confident.
If something goes wrong, you rollback. Your production systems are unaffected.
Git's diff and blame tools help you understand what changed and why. This is critical for code review and debugging.
Handling Edge Cases and High-Risk Areas
Pure automation will never reach 100%. There will be edge cases, weird patterns, and code doing things that violate the normal rules.
Category 1: Code Doing Unusual Things
Someone wrote code that uses a library in a way that's not documented. They're calling private APIs. They're using reflection. They're doing metaprogramming.
AI and automated tools might miss these. Identify them in phase 1. Flag them for manual review in phase 4.
Category 2: Context-Dependent Logic
The correct transformation depends on context. If you're in a web handler, transform one way. If you're in a background job, transform differently. If you're in a test, transform a third way.
Humans are good at understanding context. AI is getting better at it. But you should still review these.
Category 3: Code with No Tests
If code has no tests, you can't be confident the migration is correct. You're flying blind. Add tests first (or have AI generate tests). Then migrate. Then validate.
Strategy for High-Risk Areas
Identify high-risk code in phase 1. Database interaction code. Authentication and security code. Critical business logic. Performance-sensitive code.
For these areas, have humans do the migration. Or have AI do the first pass and a human review every single change.
It's slower, but you're buying confidence. The cost of a bug in high-risk code is much higher than the cost of slower migration.
Allocate maybe 20% of your effort to high-risk code. It's usually 5-10% of the codebase, but gets a disproportionate share of your attention.
Critical: Security-sensitive code should always be reviewed by humans. Authentication. Authorization. Cryptography. Secret management. Don't let AI do the first pass on these and hope for the best. Humans review, even if it's slower.
Real-World Cost and Timeline Estimates
How long does an AI-assisted migration actually take? How much does it cost?
Small Migration (100K lines of code, one language or framework)
Timeline: 6-8 weeks
Cost: 2-3 person-months of engineering time (so 2-3 engineers for a month, or 1 engineer for 2-3 months)
Manual equivalent: 3-6 months of engineering time
Medium Migration (500K-1M lines, moderately complex)
Timeline: 10-14 weeks
Cost: 4-6 person-months of engineering time
Manual equivalent: 12-18 months of engineering time
Large Migration (2M+ lines, very complex)
Timeline: 16-24 weeks
Cost: 8-12 person-months of engineering time
Manual equivalent: 3-5 years of engineering time
Cost Breakdown
AI API costs (Claude, etc.): usually $5-20K for the entire project, even for large migrations. Negligible.
Engineering time: $150-250K per person-month (rough estimate). So a medium migration costs $600K-1.5M in labor.
Opportunity cost: You're pulling engineers off other work for 2-4 months. That's real cost, even if it's not in the budget.
The math: a medium migration that would take 12-18 months manually now takes 2-3 months. You save 9-15 months of engineering time. That's $1M-$2M in labor cost saved.
So if the migration costs $1M and saves you $1.5M, it pays for itself. Plus you get modern code, which has value too (easier to hire, easier to maintain, fewer security issues).
Hidden Costs to Budget For
Testing and validation: usually 40-50% of the total effort. Don't budget this as an afterthought.
Deployment and monitoring: 10-20% of effort. Staged rollout takes time and attention.
Learning the tooling: first migration, budget 20% extra. You're learning how to do this. By the second migration, you're 20% faster.
Unexpected issues: always budget 20% for things you didn't anticipate. Something will go wrong. You want slack in the timeline.
So your timeline estimate should be: (base estimate) * 1.5. If you think a migration will take 10 weeks, plan for 15.
What to Do Monday Morning
Identify your migration: What framework, language, or library are you behind on? What's the business case for updating? Can you quantify the cost of staying behind?
Scope it with AI: Feed your codebase to Claude. Ask it: "How much work would it be to migrate this to [new version]?" Ask it to identify high-risk areas. Ask it to estimate what percentage can be automated.
Get a sample transformation working: Pick a small file. Ask Claude to migrate it manually. Does the output work? Is it close? This tells you whether AI-assisted migration is viable for your specific case.
Identify your high-risk code: What parts of your codebase have the most risk if migration goes wrong? Database code? Security code? Critical business logic? Plan to give these special attention.
Build your toolchain: Whether it's Semgrep, custom AST scripts, or Claude, start building the tools you'll use. Test them on 5-10% of your codebase first.
FAQ
Q: If AI does the migration, how do I know the code is correct?
A: You don't, at first. That's why phase 4 (testing and validation) is so critical. Run your full test suite. Have humans review high-risk code. Deploy to staging first. Monitor in production. You're not trusting AI blindly. You're trusting AI to do 80% of the mechanical work, then validating the output.
Q: What if the migration breaks something in production?
A: That's the whole point of staged deployment and monitoring. You catch issues before they affect all your users. You roll back if needed. The cost of a 1-hour outage is usually less than the cost of a slow migration that drags on for a year.
Q: Can AI migrate our monolith to microservices?
A: Partially. AI can't design the service boundaries for you. That requires human judgment. But AI can help with the mechanical parts: extracting code, refactoring dependencies, creating service stubs. So you're looking at 50% automation, not 80%.
Q: What if our code has almost no tests?
A: Write tests first. Or have AI generate tests. Then migrate. It's slower, but you need to know the code works after migration. If there are no tests, you have no confidence.
Q: How do we handle migration of the database schema at the same time?
A: Do them separately. Migrate the code first. Get it running against the old schema. Then migrate the schema. This is safer because you can roll back each piece independently.
Q: What if we get stuck halfway through?
A: You have a version control system, right? You can roll back to the old code. You're not committed. If migration is taking too long or hitting too many issues, you can pause, regroup, and try again with a different strategy.
Key Insight
Code migration is mostly pattern replacement at scale. AI excels at this. What AI can't do is make architectural decisions or understand subtle business logic. So the winning strategy is: let AI handle the volume (80% of transformations), humans handle the judgment (high-risk code, edge cases, validation). This turns a 12-month migration into a 2-3 month project. The infrastructure supporting this (testing, staging, monitoring) is the real work. Build that, and the migration becomes manageable.
On This Page
Watch the Lecture
Why Migrations Fail
Types of Migrations
Five-Phase Process
Tools and Frameworks
Handling Edge Cases
Cost and Timeline
Monday Morning Action
FAQ
Chapter Details
Part ofChapter 7
Skill.re