Design: Large-Scale Code Migration Agent

Published:

๐ŸŽฏ Problem Statement

Design an agent system to migrate 2M lines of Objective-C to Swift across 50 modules, while 200 engineers continue landing features on the same codebase. Timeline: 6 months.

Constraints:

  • Correctness: the build can never stay red; every migrated module must pass existing tests and behave identically.
  • Incremental: big-bang rewrites are banned โ€” migrate module by module, shippable at every step.
  • Human review required: no machine-generated code lands without human sign-off.
  • Parallel development: humans keep merging; the migration must not constantly conflict.
  • Measurable: leadership wants a dashboard, not vibes.

๐Ÿ“ Architecture

flowchart TD; Queue["Module priority queue"]-->Coord["Coordinator"]; Coord-->State["Module state store"]; Coord-->Conv["Converter agent (per module, bounded)"]; Conv-->Build["Build gate"]; Build-->|fail|Conv; Build-->|pass|Tests["Unit tests"]; Tests-->|fail|Conv; Tests-->|pass|Behav["Behavioral diff (old vs new)"]; Behav-->|mismatch|Conv; Behav-->|match|Summ["Review summarizer"]; Summ-->Human["Human review"]; Human-->|changes requested|Conv; Human-->|approved|Merge["Merge"]; Merge-->Dash["Metrics dashboard"]; Merge-->State;

The verifier is the product; the converter is interchangeable. Every loop back to the converter is cheap because verification is automated.

flowchart LR; A["Phase 1: Pilot (2-3 representative modules)"]-->B["Phase 2: Scale (module-by-module queue)"]; B-->C["Phase 3: Sustain (standing process for new ObjC)"]; A-->D["Calibrate verifier, review burden, metrics"]; D-->B;

๐Ÿงญ Discussion Framework

A strong answer walks through these areas in order:

1. Phased rollout, not a flag day

  • Pilot: 2โ€“3 representative modules (one easy, one gnarly, one high-churn). Learn the failure modes small.
  • Scale: module-by-module with a priority queue (leaf modules first, or highest-churn first โ€” argue the tradeoff).
  • Sustain: the system keeps running as new ObjC lands; migration is a standing process, not a project.

2. The agent architecture

  • Per-module converter agent: reads module, plans file-by-file conversion, emits diffs. Bounded scope per run (one module, not the world).
  • Verification layer (deterministic, not LLM): build โ†’ unit tests โ†’ behavioral diff (run old vs new against recorded traffic / snapshot tests). The verifier is the real product; the converter is interchangeable.
  • Review agent / human checkpoint: summarizes the diff for the human reviewer (what changed semantically, risk areas) โ€” humans review judgment, not syntax.
  • Coordinator: schedules modules, tracks state per module (pending โ†’ converting โ†’ verifying โ†’ in review โ†’ done), handles retries.

3. Living with parallel human development

  • Migrate at module boundaries with clear ownership; coordinate via the moduleโ€™s owning team.
  • Rebase strategy: converter works on fresh checkouts; if a human lands mid-conversion, re-run (cheap if verification is automated) or diff-and-patch.
  • Generated-code hygiene: mark migrated regions, prevent the agent from โ€œre-migratingโ€ converted code (state tracking per file).

4. Token efficiency & cost

  • Internal research angle: Swiftโ€™s token efficiency vs ObjC affects agent coding cost โ€” batch related files, share context across files in one module, cache repo maps.
  • Measure $/merged module, optimize the expensive parts (usually verification + review cycles, not generation).

5. Metrics dashboard

  • Conversion rate (modules/week), build health, test pass rate on migrated code, human review burden (comments per diff, revert rate), and defect escape rate on migrated modules vs baseline.

๐Ÿ” Deep-Dive Questions

  • โ€œHow do you prove behavioral equivalence?โ€ โ†’ Layered: compiles + existing tests + snapshot/behavioral diffs + staged rollout with production monitoring. No single layer suffices; argue which catches what.
  • โ€œThe agent produces correct but unidiomatic Swift โ€” accept?โ€ โ†’ Define a style bar (linters as deterministic gates); unidiomatic-but-correct ships, with a follow-up modernization pass. Donโ€™t let perfect block the migration.
  • โ€œA module has 80% test coverage and the rest is untestable legacy โ€” migrate?โ€ โ†’ Risk-tier the modules; low-coverage modules get more human scrutiny and smaller batches, or characterization tests written first (by an agent, verified by humans).

๐Ÿ’ก What Great Looks Like

The candidate separates the non-deterministic converter from the deterministic verifier, treats human review as a designed bottleneck to optimize (summarization, risk ranking), plans for parallel development conflicts explicitly, and defines success in metrics โ€” not โ€œwe migrated everything.โ€