Anthropic이 Claude Code를 활용한 대규모 코드 마이그레이션을 수행하다
요약
Anthropic 개발자들이 Claude Fable 5와 Opus 4.8을 활용하여 대규모 코드 마이그레이션을 성공적으로 수행했습니다. Bun 프로젝트는 Zig에서 Rust로, Anthropic Labs의 Python 코드는 TypeScript로 각각 수만~수십만 라인 규모를 단기간에 포팅하며 AI 에이전트 기반 개발 프로세스의 혁신성을 입증했습니다.
핵심 포인트
- AI 코드 마이그레이션은 에이전트를 이용해 대규모 코드베이스를 새로운 언어로 포팅하는 과정입니다.
- Claude Code는 수만~수십만 라인 규모의 코드를 단기간에 성공적으로 마이그레이션할 수 있게 합니다.
- 핵심은 단순히 코드를 고치는 것이 아니라, 코드를 생성하고 검증하는 프로세스(루프)를 개선하는 것입니다.
코드 마이그레이션(Code migrations), 즉 운영 환경의 코드베이스를 새로운 언어로 포팅하는 프로젝트는 최근까지 수년에 걸친 노력이 필요했습니다.
지난 한 달 동안, Anthropic의 개별 개발자들은 Claude Fable 5, Claude Opus 4.8 및 동적 워크플로우(dynamic workflows)를 사용하여 수만에서 수십만 라인에 달하는 코드로 구성된 10개의 코드 패키지를 마이그레이션했습니다. 본 기사에서는 이 프로젝트들로부터 얻은 모범 사례와 함께 두 가지 예시를 다룰 것입니다.
Bun의 공동 설립자이자 Anthropic의 기술 스태프 멤버인 Jarred Sumner는 Claude Code를 사용하여 Bun을 Zig에서 Rust로 마이그레이션했습니다. 2주도 안 되는 기간에 백만 라인의 코드가 생성되었으며, 병합(merge) 전에 기존 Bun 테스트 스위트의 100%가 CI 환경에서 통과했습니다. 병합 후 19개의 회귀(regressions)가 발견되었고 모두 수정되었습니다. Rust 포트는 지난 6월 Claude Code 내에서 배포되었습니다.
Anthropic Labs의 공동 리드인 Mike Krieger는 주말 동안 Python 코드베이스를 165,000 라인의 TypeScript로 마이그레이션했습니다. 여기에는 수백 개의 에이전트(agents), 8개의 단계 게이트(phase gates), 3번의 적대적 검토 라운드(adversarial review rounds)와 모든 명령어의 출력을 Python 원본과 비교하는 최종 동등성 확인(final parity check)이 포함되었습니다.
Claude Code의 새로운 기능들은 이러한 장기간 미뤄졌던 프로젝트들의 계산 방식을 변화시키고 있습니다. 아래는 이 마이그레이션들로부터 배운 내용을 바탕으로 현재 저희가 사용하는 6단계 프로세스입니다.
핵심 통찰은 코드를 고치는 것이 아니라, 코드를 생성한 프로세스(루프)를 고친다는 것입니다.
AI 코드 마이그레이션이란 무엇인가?
AI 코드 마이그레이션은 AI 에이전트를 사용하여 운영 환경의 코드베이스를 새로운 언어나 프레임워크로 포팅하는 것을 의미합니다. 엔지니어들이 파일을 수동으로 번역하는 대신, 마이그레이션 규칙과 검증 루프(verification loops)를 작성하고, 에이전트가 이를 번역, 컴파일, 테스트하여 새 코드의 동작이 원본과 일치할 때까지 반복함으로써 수년간 걸리던 프로젝트를 몇 주 만에 압축합니다.
언어 마이그레이션 시기 및 이유
*방법(how)*을 바로 논하기 전에, 이 프로젝트들과 관련된 가정들이 발전했기 때문에 *시기(when)*와 *이유(why)*를 논하는 것이 가치가 있습니다.
팀들은 초기 빌드와 현재 프로젝트 간의 환경 변화 때문에 마이그레이션을 시작합니다. 알려진 트레이드오프가 제한적이게 되었거나, 더 나은 접근 방식이 등장했거나, 혹은 원래 생태계가 축소되었기 때문입니다.
예를 들어, Jarred는 처음에는 Zig를 선택했습니다. 이는 C 레벨 성능을 극도의 단순성과 결합하여 제공했기 때문에, LLM 이전 오클랜드의 비좁은 아파트에서 'Bun을 1년 만에 작성하는' 솔로 창업가에게 이상적이었습니다. 이 단순성은 알려진 트레이드오프를 수반했으며, 그는 여기서 이에 대해 글을 쓰고 있습니다.
시간이 흘러 2026년이 되었습니다. Bun의 CLI는 월간 다운로드 수가 1,000만 개를 넘어서고 있으며 Claude Code 내에서 광범위하게 사용되고 있습니다.
불과 지난 분기까지만 해도, 그러한 트레이드오프만으로는 로드맵을 동결하고 수분기에 걸친 프로젝트에 자원을 투입할 만큼 충분하지 않았습니다. 언어를 마이그레이션하는 것은 더 작고, 빠르며, 안전한 시스템을 제공할 수 있지만, 아무도 그 비용을 지불하고 싶어 하지 않습니다.
소프트웨어 엔지니어들은 또한 이러한 과거의 초대형 프로젝트에 내재된 경력 위험과 싸워야 했습니다. 몇 분기 또는 몇 년 동안 두 개의 병렬 코드베이스를 유지할 수 있었고, 최종 결과가 90% 수준의 동등성(parity)을 갖추더라도, 시작했을 때보다 더 큰 골칫거리를 안게 되었습니다.
이제 최악의 시나리오는 브랜치를 삭제하고 다시 시도하는 것입니다.
여전히 정당화할 수 있는 비즈니스 케이스가 필요합니다. 백만 라인 규모의 마이그레이션이 4년 프로젝트 기간 동안 엔지니어링 자원으로 $3에서 $4백만 달러를 더 이상 소모하지는 않지만, 실행하는 데 여전히 수만 달러에서 수십만 달러 이상의 비용이 듭니다. 예를 들어, Bun 마이그레이션은 캐시되지 않은 입력 토큰 59억 개와 출력 토큰 6억 9천만 개를 소비했으며, 이는 API 가격으로 약 $165,000에 해당합니다. Mike의 포트(port) 주요 부분은 2,700만 개의 토큰이었습니다.

하지만 마이그레이션 케이스가 더 이상 실존적일 필요는 없습니다. 변경 로그에서 1년 동안 메모리 버그 패치가 발생하거나, 만성적인 병목 현상 하나만으로도 충분히 정당화할 수 있게 되었습니다.
컴파일 단계가 Mike의 프로젝트 동기가 되었습니다. 그의 팀이 작업하는 내부 도구는 사용자에게 단일 바이너리로 배포됩니다. 이 바이너리를 Python 툴체인으로 생성하는 데 플랫폼당 약 8분이 걸렸고, 이는 모든 릴리스에서 빌드 매트릭스 전체에 걸쳐 총 30분의 대기 시간을 발생시켰습니다. 포팅 후에는 동일한 컴파일이 이제 약 2분 만에 완료되며, 바이너리 시작 속도는 6배 빨라졌고, 팀은 별도의 배포 파이프라인을 폐지할 수 있었습니다.
AI가 코드 마이그레이션의 계산 방식을 바꾸는 이유
Claude Fable 5는 저희가 보유한 가장 유능하고 일반 사용 가능한 모델입니다. Fable과 Opus 4.8은 특히 서브 에이전트와 함께 병렬 작업 흐름을 위임(delegating), 지시(directing), 검증(verifying)하는 데 능하며, 명시된 목표를 향해 여러 경로를 찾는 데 탁월합니다.
대규모 코드 마이그레이션은 이러한 고급 모델의 특히 효과적인 사용 사례인데 그 이유는 다음과 같습니다:
작업이 병렬적입니다. 작업은 파일이나 크레이트(crates)와 같은 수천 개의 독립적인 단위에 걸쳐 실행될 수 있으므로, 에이전트들이 서로 기다리는 대신 동시에 작업을 수행할 수 있습니다. 컨텍스트가 명확하고 포괄적입니다. 기존 코드는 모델에게 훌륭한 사양서(spec) 역할을 합니다. 또한 번역 에이전트가 따라야 할 가이드를 만드는 핵심 참조 자료 역할도 합니다. 내장된 심판관이 있습니다. 많은 대규모 코드베이스에는 에이전트들이 작업을 검증하는 데 사용할 수 있는 테스트 스위트가 포함됩니다. 모델은 인간의 품질 중재 없이 며칠 동안 그라운드 트루스(ground truth)와 맞서 싸울 때 최고의 성능을 발휘하므로, 검증이 객관적일 때 에이전트들이 가장 잘 작동합니다. 대기열이 스스로 작성됩니다. 컴파일러나 테스트 실행에 실패하면, 그것이 에이전트가 수정해야 할 다음 항목이 됩니다. 일관성과 엣지 케이스(edge case) 처리가 필요합니다: 이 프로세스는 드리프트(drift)가 숨을 곳이 없도록 구축되었습니다. 검토자들은 모든 발견의 근거 규칙을 인용하므로, 위반 사항은 조용한 편차 대신 대기열 항목이 됩니다. 그리고 에이전트가 엣지 케이스에 도달하면, 그 수정 사항은 이후 모든 에이전트가 따르는 규칙이 됩니다.
아래에서 보듯이, Mike와 Jarred는 마이그레이션 과정의 핵심 단계에 Fable을 사용했으며, 특히 토큰 소비를 최적화하기 위해 여러 모델 클래스를 활용하는 **어드바이저리 패턴(advisory pattern)**을 사용했습니다.
대규모 코드 마이그레이션을 위한 6단계
아래 프로세스는 여러 언어와 시나리오에 적용 가능하도록 일반화되었습니다. 추가 세부 정보는 Jarred의 블로그를 참고할 수 있습니다. 또한, 마이그레이션 스타터 키트(Migration starter kit)도 이용할 수 있습니다. 참고: 이 스타터 키트는 위의 프로세스를 일반화한 템플릿일 뿐이며, 특정 포팅 작업에서 사용된 것은 아닙니다.
사전 조건 (Prerequisites)
마이그레이션 프로젝트를 시작하기 전에 필수적인 것은 강력한 '판단자(judge)'를 마련하는 것입니다. 그렇지 않으면 종료 조건이나 성공 측정 기준을 가질 수 없습니다.
이 판단자는 원본 코드와 목표 코드를 동등하게 평가할 수 있어야 합니다. 원본 언어로 작성된 테스트 스위트(Test suites)는 종종 목표 코드에는 존재하지 않을 내부 함수에 의존하기 때문입니다.
판단자를 구축하는 방법:
1. 기존 테스트 분류: Claude를 사용하여 어떤 테스트가 외부 호출로 표현 가능한지, 그리고 어떤 테스트가 포팅되지 않을 내부 기능에 의존하는지를 식별합니다.
2. 이식성을 위한 재작성: 외부를 향하는 테스트들을 원본과 포팅된 코드 모두에서 실행할 수 있는 단언(assertions)으로 변환합니다. 적대적 에이전트(adversarial agents)를 사용하여 재작성된 테스트가 단언을 약화시키지 않는지 검증합니다.
3. 판단자 검증: 원본 코드를 대상으로 실행하여 통과하는지 확인합니다. 그런 다음 의도적으로 깨진 코드(deliberately broken code)를 대상으로 실행하여 실패하는지 확인해야 합니다. 결함을 잡아내지 못하는 판단자는 진정한 판단자가 아닙니다.
Jarred는 제3의 언어(TypeScript)로 작성된 대규모 테스트 스위트를 가지고 있었지만, 이는 대부분의 프로젝트에 해당하지 않을 것입니다. 그의 Python-to-TypeScript 포팅의 경우, Mike는 7가지 실제 시나리오의 패리티 하네스(parity harness)를 만들었고, 어떠한 동작 변화도 수정해야 할 버그로 간주했습니다.
각 단계에 들어가기 전에, 이 그래픽이 따라가기 쉽게 도와줄 것입니다. 이것은 주로 Jarred의 방법론을 따르며, 각 단계마다 검토와 게이트(gates)를 거칩니다. Mike는 유사한 전체 구조를 사용하고 비슷한 루프 워크플로우를 사용했지만, 전체 마이그레이션을 처음부터 끝까지 실행했고, 결과에 따라 규칙과 워크플로우를 수정했으며, 세 번째 실행 때까지 매번 출력을 폐기했습니다.

1단계 — 규칙서(rulebook), 의존성 맵(dependency map), 그리고 격차 목록(gap inventory) 생성

이 단계에서 우리는 마이그레이션의 기반을 만듭니다. 단순히 번역되어야 할 곳이 아니라 리팩토링(refactored)되어야 할 코드 위치에 대한 재고, 코드를 어떻게 번역할지에 대한 규칙서, 그리고 우리의 마이그레이션 구현 워크스트림을 순서화하기 위한 의존성 맵입니다.
순서가 중요합니다. 규칙서는 격차 목록보다 먼저 와야 합니다. 격차 목록은 규칙서의 기본값(defaults)이 커버하지 못하는 부분에 의해 정의되며, 이 두 가지는 공동 감사(joint audit)에서 함께 테스트됩니다.
규칙서(Rulebook)
규칙서의 정확한 형태는 시작할 때 내릴 수 있는 주요 아키텍처 결정에 따라 달라집니다. 그중 가장 중요한 것은 새로운 코드가 동일한 구조를 따를지, 아니면 완전히 재설계될 것인지입니다.
만약 전자의 경우(Jarred), 규칙서는 주로 유형과 관용구(idioms)를 언어 간에 번역하는 조회 테이블(lookup tables)이 될 것이며, 더 번역하기 어려운 구성 요소에 대해서는 격차 목록을 가리킬 것입니다. 만약 후자의 경우(Mike), 그것은 설계 문서(design document)가 될 것입니다.
Jarred는 Claude와 채팅하며 규칙서를 만들었고, 모호한 각 영역에 대한 정책을 수립했습니다. 그는 또한 자신의 직관에 기반하여 8가지 다른 일반적인 실패 모드(common failure modes)를 검토하도록 특별히 설계된 8개의 서브 에이전트(subagents)도 사용했습니다.
의존성 맵(Dependency map)
병렬 마이그레이션을 위해 작업 흐름을 효과적으로 분할하려면 파일 의존성을 이해해야 합니다. 그래야 어떤 파일을 먼저 마이그레이션하고 어떤 파일을 같은 배치에 포함시켜야 할지 알 수 있습니다. 일부 언어와 코드베이스는 명시적인 매니페스트(manifest)를 가지고 있어 이 과정이 쉽지만, 레거시 코드베이스나 C/C++, Python과 같은 많은 인기 언어의 경우 이러한 의존성은 발견하고 매핑해야 합니다.
Claude Code는 에이전트를 배포하여 결정론적 스크립트를 생성하고 실행함으로써 이러한 맵을 만들 수 있습니다. 마이그레이션 키트의 프롬프트는 검토 및 수정 루프(review-and-fix loop)를 생성하는 워크플로우를 사용합니다. 참고: 스타터 키트는 이 게시물에 설명된 프로세스의 일반화된 템플릿이며, 특정 포트에 적용된 것이 아닙니다.
갭 인벤토리 및 회의적 검토자(skeptic reviewers)
새로운 언어는 이전 언어와 다른 요구 사항을 충족해야 합니다. Zig에서 Rust로 넘어갈 때 차이점은 수동 메모리 관리였습니다 (C와 C++는 동일하게 작동합니다). 예를 들면:
Zig
fn readConfig(allocator: std.mem.Allocator) ![]u8 {
const buf = try allocator.alloc(u8, 1024);
// ...buf 채우기...
...
Rust
fn read_config() -> Vec<u8> {
let buf = vec![0u8; 1024];
// ...buf 채우기...
...
Python에서 TypeScript로 넘어갈 때의 차이는 인터페이스와 계약(contract)이었습니다. Python은 객체가 어떤 형태일지, 또는 무엇을 반환할지에 대한 계약을 요구하지 않지만, TypeScript는 그렇습니다. 예를 들면:
Python
def register(handler):
handler.setup()
return handler.run({"retries": 3})
...
TypeScript
interface RunResult { ok: boolean }
interface Handler
{
setup(): void;
...
Jarred와 Mike는 이러한 암묵적인 지식을 포착하는 갭 인벤토리 파일(gap inventory files)을 만들었습니다. Jarred는 이 갭들을 사전에 인벤토리를 작성했고, 이것이 우리가 여기서 하는 일이며, Mike는 먼저 번역한 다음 나중에 감사(auditing)를 통해 갭 인벤토리를 만드는 것을 선택했습니다. 두 가지 모두 필요할 수 있습니다.
갭 인벤토리 파일을 생성하는 데 사용할 수 있는 샘플 Claude Code 프롬프트를 확인해 보세요.
2단계 — 규칙 스트레스 테스트

이 단계는 대규모 마이그레이션을 위한 ‘예비 점검’ 역할을 하는 미니 마이그레이션입니다.
이 단계에서 Jarred는 하나의 에이전트를 사용하여 규칙집(rulebook)을 이용해 세 개의 파일을 번역했고, 또 다른 에이전트로는 '선임 Rust 엔지니어처럼' 세 개의 파일을 번역했으며, 마지막으로 하나의 에이전트는 diff를 사용하여 새로운 번역 규칙을 만들었습니다. 이 단계에서 그는 1,448개 파일 전체에 걸쳐 문제가 발생했을 경우 수많은 문제를 일으켰을 두 가지 중요한 문제점을 발견했습니다.
프롬프트는 다음과 같아 보일 수 있습니다.
이러한 유형의 스트레스 테스트는 **구조를 보존하는 마이그레이션(structure-preserving migrations)**에만 작동하며, 여기서 동일 파일에 대한 두 번역본은 라인별로 비교 가능해야 합니다. 만약 규칙집 자체가 리디자인이라면 — Mike의 경우처럼 — 이에 상응하는 테스트는 적대적 리뷰어(adversarial reviewers)를 이용해 디자인 문서 자체를 공격하고, 이를 일회성 엔드투엔드 실행으로 검증하는 것입니다.
어쨌든, 번역된 파일은 모두 버리십시오. 목표는 점진적인 진척을 이루는 것이 아니라 규칙을 정교화하는 것입니다.
3단계 — 모든 것을 번역하기

남은 단계들에 대해서는 동일한 다중 에이전트 루프 아키텍처(multi-agent loop architecture): 구현(implement), 검토(review), 수정(fix)을 실행합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN Code Generation의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기