Claude Code로 대규모 코드 마이그레이션을 수행한 방법
요약
Claude Code를 활용하여 대규모 코드베이스를 새로운 언어로 마이그레이션하는 혁신적인 워크플로를 소개합니다. 개별 코드를 수정하는 대신 생성 루프와 규칙을 개선하여 수십만 줄의 코드를 단기간에 정확하게 이전하는 방법을 다룹니다.
핵심 포인트
- 코드를 직접 수정하지 않고 생성 규칙과 검증 루프를 개선하는 방식 채택
- Bun의 Zig에서 Rust 이전 사례: 2주 만에 100만 줄 생성 및 테스트 100% 통과
- Python에서 TypeScript로의 이전: 수백 개 에이전트와 다단계 검토 활용
- 실패 시 브랜치를 폐기하고 상위 규칙을 수정하여 재시도하는 객관적 검증 루프 구축
- Anthropic 개발자들은 Claude Fable 5, Claude Opus 4.8과 동적 워크플로를 이용해 최근 한 달간 수만~수십만 줄 규모의 패키지 10개를 이전했으며, 개별 코드를 고치는 대신
코드를 생성하는 반복 과정을 개선함 - Bun의 Zig→Rust 이전은 2주 미만에
100만 줄을 생성하고 병합 전 기존 테스트를 100% 통과했으며, Python→TypeScript 프로젝트는 주말 동안 16만5,000줄을 옮기면서 수백 개 에이전트와 8개 단계 관문, 3회의 적대적 검토를 활용함 - 대규모 이전은 작업을 병렬화할 수 있고 기존 코드가 명세와 정답 역할을 하며, 컴파일·테스트 실패가 다음 작업 대기열을 자동 생성하므로
객관적인 검증 루프를 구성하기 좋음 - 판정 기준 준비부터 규칙집·의존성 지도·차이 목록 작성, 규칙 스트레스 테스트, 전체 번역, 컴파일, 실행, 동작 비교까지 단계적으로 진행하며, 반복 오류는 파일별로 수정하지 않고
상위 규칙을 고쳐 재생성함 - 비용은 여전히 수만
수십만 달러 이상이지만 실패한 브랜치를 폐기하고 다시 시도할 수 있으며, Bun 이전은 API 가격 기준 약 16만5,000달러를 사용한 뒤 메모리 사용량 감소, 바이너리 크기 19% 축소, 실제 워크로드 성능 25% 향상을 달성함
코드가 아닌 생성 루프를 개선하는 방식
AI 코드 마이그레이션은 에이전트가 프로덕션 코드베이스를 새로운 언어나 프레임워크로 옮기는 방식임
-
엔지니어가 파일을 직접 번역하는 대신 이전 규칙과 검증 루프를 작성함
-
에이전트는 새 코드의 동작이 원본과 일치할 때까지 번역·컴파일·테스트를 반복함
-
과거 여러 해가 걸리던 프로젝트를 수주 단위로 단축할 수 있음
-
Anthropic에서는 Claude Fable 5, Claude Opus 4.8과 동적 워크플로를 사용해 한 달 동안 수만~수십만 줄 규모의 코드 패키지 10개를 이전함
-
핵심 운영 원칙은 생성된 코드를 직접 수선하는 것이 아니라
그 코드를 만든 루프를 수정하는 것임
실제 마이그레이션 사례
Bun의 Zig→Rust 이전
-
Jarred Sumner는 Claude Code로 Bun을 Zig에서 Rust로 이전함
-
2주 미만에
100만 줄의 코드를 생성함 -
병합 전 CI에서 Bun의 기존 테스트 스위트를 100% 통과함
-
병합 후 발견된 회귀 19건은 모두 수정됨
-
Rust 포트는 6월 Claude Code에 탑재됨
-
Bun은 월간 다운로드가 1,000만 회를 넘고 Claude Code 내부에서도 광범위하게 사용됨
Python→TypeScript 이전
- Mike Krieger는 주말 동안 Python 코드베이스를
16만5,000줄의 TypeScript로 이전함 - 수백 개 에이전트, 8개 단계 관문, 3회의 적대적 검토를 사용함
- 모든 명령의 출력을 Python 원본과 비교하는 최종 동등성 검사를 수행함
- 전체 마이그레이션 결과를 버리고 규칙과 워크플로를 수정하는 과정을 반복했으며, 세 번째 실행 결과를 채택함
언어 이전을 다시 검토할 조건
-
최초 개발 이후 기술 환경이 바뀌어 기존 절충점이 제약으로 작용하거나, 더 나은 접근법이 등장하거나, 원래 생태계가 축소됐다면 이전을 검토할 수 있음
-
Zig는 C 수준 성능과 단순성을 제공해 혼자 Bun을 개발하던 초기 환경에 적합했지만, 그 단순성에는 알려진 절충점이 있었음
-
과거에는 언어 이전을 위해 로드맵을 중단하고 여러 분기의 자원을 투입해야 했음
-
두 코드베이스를 수분기 또는 수년간 병행 유지해야 할 수 있었음
-
최종 동작 일치율이 90%에 그치면 시작 전보다 더 큰 유지보수 문제가 생길 수 있었음
-
이제는 실패한 브랜치를 삭제하고 다시 실행하는 선택지가 생김
-
100만 줄 이전이 더 이상 4년간 엔지니어링 비용
300만~400만 달러를 요구하지는 않지만, 여전히 수만~수십만 달러 이상이 들 수 있음 -
Bun 이전은 캐시되지 않은 입력 토큰 59억 개와 출력 토큰 6억9,000만 개를 소비함
-
API 가격 기준 비용은 약 16만5,000달러임
-
Mike의 포트에서 핵심 구간은 2,700만 토큰을 사용함
-
이전의 사업적 근거가 반드시 존립을 좌우할 정도일 필요는 없어졌으며, 1년간 반복된 메모리 버그 수정이나 만성적인 병목 하나로도 정당화할 수 있음
Python 빌드 병목 해소
- Mike의 내부 도구는 사용자에게 단일 바이너리로 제공됐지만, Python 도구 체인으로 플랫폼별 바이너리를 만드는 데 약 8분이 걸렸음
- 전체 빌드 매트릭스에서는 릴리스마다 약
30분을 기다려야 했음 - TypeScript 이전 후 컴파일은 약 2초로 줄고 바이너리 시작은 6배 빨라졌으며, 별도의 배포 파이프라인도 폐기함
AI 에이전트가 이전에 적합한 이유
병렬 작업이 가능함
-
파일과 크레이트 등 수천 개의 독립 단위로 나눠 여러 에이전트가 동시에 처리할 수 있음
-
기존 코드가 명확하고 포괄적인
명세 역할을 함 -
번역 에이전트용 지침을 만드는 핵심 참고 자료로도 활용할 수 있음
-
테스트 스위트가 내장된 판정자 역할을 함
-
검증이 객관적이면 사람이 품질을 계속 중재하지 않아도 모델이 정답을 기준으로 며칠간 반복 작업할 수 있음
-
컴파일이나 테스트 실패가 자동으로 다음 작업 항목이 되므로 별도의 작업 대기열을 작성할 필요가 줄어듦
-
일관성과 예외 처리를 루프에 포함할 수 있음
-
검토자는 각 문제를 위반된 규칙과 연결함
-
예외를 해결한 방법은 이후 모든 에이전트가 따르는 규칙으로 바뀜
-
조용한 동작 불일치 대신 규칙 위반이 명시적인 작업 항목이 됨
-
Fable과 Opus 4.8은 하위 에이전트의 병렬 작업을 위임·지휘·검증하고, 목표에 도달할 여러 경로를 찾는 데 사용됨
-
여러 모델 등급을 조합하는
자문 패턴으로 토큰 사용량을 최적화함
사전 조건: 원본과 포트를 동등하게 판정하기
-
이전을 시작하기 전에 원본과 대상 코드를 같은 기준으로 평가할 강력한
판정자가 필요함 -
판정자가 없으면 성공 기준과 종료 조건도 없음
-
원본 언어의 내부 함수에 의존하는 테스트는 대상 코드에서 그대로 실행되지 않을 수 있음
-
기존 테스트를 외부 호출로 표현할 수 있는 테스트와 포트되지 않을 내부 구현 의존 테스트로 분류함
-
외부 동작 테스트는 원본과 포트 양쪽에서 실행할 수 있는 단언으로 다시 작성함
-
적대적 에이전트가 재작성 과정에서 단언이 약해지지 않았는지 검증함
-
판정자를 원본 코드에 실행해 성공하는지 확인한 뒤, 의도적으로 망가뜨린 코드에서는 실패하는지도 검사함
-
Jarred는 제3의 언어인 TypeScript로 작성된 대규모 테스트 스위트를 보유했음
-
Mike는 실제 사용 시나리오 7개로
동등성 하네스를 만들고 모든 동작 변화를 수정해야 할 버그로 취급함
1단계: 규칙집·의존성 지도·차이 목록
-
기반 산출물은 단순 번역 결과가 아니라 리팩터링할 위치의 목록, 번역 방식의 규칙집, 작업 순서를 정하는 의존성 지도임
-
작성 순서가 중요함
-
먼저 규칙집의 기본값을 정해야 그 기본값으로 처리할 수 없는 항목을 차이 목록으로 정의할 수 있음
-
규칙집과 차이 목록은 공동 감사를 통해 함께 검증함
규칙집
-
규칙집의 형태는 새 코드가 기존 구조를 유지할지 완전히 재설계할지에 따라 달라짐
-
Jarred처럼 구조를 유지하면 언어 간 타입과 관용 표현의
대응표가 중심이 되고, 번역하기 어려운 구성요소는 차이 목록을 참조함 -
Mike처럼 재설계하면 규칙집이 설계 문서 역할을 함
-
Jarred는 Claude와 대화하며 모호한 영역마다 정책을 만들고, 예상되는 8개 오류 범주를 각각 검토하도록 하위 에이전트 8개를 구성함
의존성 지도
-
병렬 이전에서는 어떤 파일을 먼저 옮기고 어떤 파일을 같은 배치에 넣을지 결정하기 위해 파일 의존성을 파악해야 함
-
명시적 매니페스트가 없는 레거시 코드와 C/C++, Python 등의 코드베이스에서는 의존성을 직접 발견하고 지도화해야 함
-
Claude Code 에이전트는 결정론적 스크립트를 작성·실행하고 검토·수정하는 루프로 지도를 생성할 수 있음
-
일반화된 예시는 의존성 지도 프롬프트에서 확인할 수 있음
언어 차이 목록과 회의적 검토자
차이 목록은 기존 코드에 암묵적으로 들어 있지만 대상 언어에서는 명시해야 하는 지식을 기록함
- Zig→Rust에서는 메모리 관리 방식이 주요 차이였음
- Zig에서는 호출자가 버퍼를 해제해야 한다는 사실이 주석에만 있을 수 있고, 해제를 빠뜨려도 컴파일되며 누수는 실행 중 발견됨
- Rust에서는 소유권이 호출자에게 이동하고 메모리가 자동 해제되며, 이동 후 사용이나 이중 해제는 컴파일되지 않음
- Python→TypeScript에서는 인터페이스와 계약이 주요 차이였음
- Python은 전달받는 객체와 반환값의 형태를 선언하지 않아도 됨
- TypeScript에서는 메서드, 인수, 반환 형태의 계약을 작성해야 컴파일됨
- Jarred는 번역 전에 차이를 목록화했고 Mike는 먼저 번역한 뒤 감사 과정에서 목록을 만들었으므로, 프로젝트에 따라 두 접근을 모두 사용할 수 있음
- 일반화된 예시는 차이 목록 생성 프롬프트에서 확인할 수 있음
2단계: 규칙 스트레스 테스트
-
전체 이전에 앞서 소규모
시험 이전으로 규칙집을 흔들어 보고 문제를 찾음 -
Jarred는 세 가지 에이전트 작업을 비교함
-
첫 번째 에이전트는 규칙집에 따라 파일 3개를 번역함
-
두 번째 에이전트는 숙련된 Rust 엔지니어처럼 같은 규모를 번역함
-
세 번째 에이전트는 두 결과의 차이를 바탕으로 새로운 번역 규칙을 작성함
-
이 과정에서 1,448개 파일 전체로 확산되기 전에 중대한 문제 2개를 발견함
-
이 방식은 동일 파일의 두 번역 결과를 줄 단위로 비교할 수 있는
구조 보존형 이전에서만 작동함 -
Mike처럼 재설계하는 경우에는 적대적 검토자가 설계 문서를 공격하고, 폐기 가능한 종단 간 실행으로 검증해야 함
-
시험에서 번역한 파일은 모두 버려야 하며, 목적은 점진적인 코드 진척이 아니라 규칙 개선임
-
일반화된 작업 예시는 스트레스 테스트 프롬프트에서 확인할 수 있음
3단계: 전체 코드 번역
-
이후 단계는 모두
구현→검토→수정의 다중 에이전트 루프를 사용함 -
대량 구현은 작은 모델에 맡기고 검토는 큰 모델이 담당할 수 있음
-
Mike는 핵심 이전을 병렬화할 때 Claude Sonnet 하위 에이전트 12개를 사용함
-
작업 대기열은 기계적으로 관리함
-
배치 스크립트가 번역 파일의 디스크 존재 여부로 완료 상태를 판단함
-
남은 파일을 구현 에이전트용 배치로 나눔
-
실행할 때마다 디스크 상태에서 대기열을 재구성하므로 기본적으로 중단 후 재개할 수 있음
-
에이전트가 지나치게 조심스럽게 적은 양만 처리한다면, 다음 단계에서 컴파일러가 오류를 잡는다는 맥락과 함께 더 직접적으로 지시할 수 있음
-
확신을 갖고 처리하지 못한 항목은
// TODO(port): <reason>
으로 표시하고 4단계에서 해결함
- 이후 작업 목록은 컴파일 오류, 스모크 테스트 충돌, 테스트 실패에서 자동 생성됨
적대적 검토와 규칙 갱신
-
독립된 컨텍스트의 적대적 검토자 2개가 구현 결과를 평가하고, 의견이 다르면 세 번째 에이전트가 판정함
-
여러 파일에서 같은 오류가 반복되면 파일을 개별 수정하지 않음
-
규칙집에 문장 하나를 추가하고 영향을 받은 배치를 다시 생성함
-
번역 단계에서도 규칙집은 계속 확장되며, 규칙과 어긋난 코드를 수작업으로 패치하지 않음
컴파일러 배치 위치
- 컴파일 시간이 짧으면 번역 루프 안에 포함할 수 있음
- Mike는 TypeScript 컴파일이 단위별로 수초 안에 끝나므로 모든 루프에서 실행함
- 컴파일이 오래 걸리면 다음 단계로 미룸
- Jarred는
cargo
실행에 수분이 걸려 번역 루프에서 컴파일러 사용을 금지함
- 이 단계부터 프롬프트는 짧아지며, 예시는 번역 시작 프롬프트에서 확인할 수 있음
4~6단계: 컴파일·실행·동작 일치
- 세 단계는 같은 루프 구조를 공유하며, 뒤로 갈수록 필요한 인간 판단이 줄어듦
- 언어와 프로젝트 규모에 따라
컴파일 단계는 전체 번역 단계에 흡수될 수 있음
4단계: 컴파일
-
Jarred는 오케스트레이터 스크립트가 전체 워크스페이스에서 컴파일러를 한 번 실행하도록 구성함
-
수정 에이전트들이 오류 목록을 병렬 처리하고 적대적 검토를 거친 뒤 다시 빌드하는 과정을 반복함
-
오류 목록 검토는 개별 오류가 아니라 시스템적 문제를 발견하는 데 사용함
-
Zig의 지연 컴파일이 허용하던 순환 임포트를 수정한 뒤 Rust 모듈 오류 수천 개가 발생함
-
어떤 의존성을 삭제·이동하거나 경계를 재구성할지 분류하는 로직을 루프에 추가함
5단계: 실행과 스모크 테스트
-
스모크 테스트에서 발생한 충돌이 컴파일 오류 목록과 같은
기계적 정답 역할을 함 -
문제를 개별 처리하지 않고 근본 원인별 범주로 묶은 뒤 적대적 하위 에이전트가 검토함
6단계: 원본과 동작 비교
-
번역·컴파일·스모크 테스트를 마친 코드를 분할하고, 사전 단계에서 준비한 테스트 스위트를 원본과 포트에 실행함
-
수정 에이전트는 실패한 테스트와 양쪽 코드베이스를 함께 검토하며, 적대적 검토자가 수정 결과를 확인함
-
빌드 데몬만 바이너리를 다시 빌드할 수 있도록 제한함
-
수정 에이전트는 패치를 작성하고, 데몬은 패치를 모아 한 번만 재빌드함
-
영향받은 테스트를 다시 실행해 결과를 반환함
-
여러 에이전트가 비싼 빌드를 각각 실행하지 않도록 작업을 직렬화함
-
같은 실패가 여러 테스트에서 반복되면 버그를 만든 상위 규칙을 수정하고, 그 규칙이 영향을 준 파일만 재생성함
테스트 스위트가 없는 경우
- Mike는 실제 시나리오 7개를 원본 Python 코드와 새 포트에 실행하고 결과를 비교하는 작은 스크립트를 Claude로 생성함
- 실패한 시나리오마다 별도 수정 에이전트를 배정하고 7개가 모두 통과할 때까지 반복함
- Claude가 자체 종단 간 테스트 스위트도 설계해 밤새 자율 실행함
- 오류를 수정하고 다시 실행하는 작업을 나흘 밤 동안 반복함
- 미리 작성한 시나리오 목록으로 예측하기 어려운 사소한 사용성 문제까지 발견함
- 기존 테스트가 없어도 원본 코드베이스를 정답으로 삼아 Claude가 판정자를 만들 수 있음
반복 실행에서 확인된 운영 원칙
-
가이드를 그대로 따르기보다 프로젝트 특성에 맞춰 Claude와 이전 계획을 세운 뒤 착수해야 함
-
개별 실패는 수정 에이전트가 처리하도록 두고, 사람은 반복되는
오류 패턴에 집중해야 함 -
검토는 적대적으로, 검증은 기계적으로 구성함
-
적대적 검토는 장시간 작업에 유용하며 추가 토큰 소비를 감수할 가치가 있을 수 있음
-
컴파일러, diff, 테스트 스위트 같은 스크립트를 최종 판정자로 사용함
-
모든 작업에 가장 큰 모델을 사용하지 않음
-
작은 모델은 대량 구현 병렬화에 활용함
-
가장 큰 모델은 검토와 다른 에이전트가 따를 규칙 작성에 집중함
-
사람의 작업 시간은 규칙집과 스트레스 테스트에
선투입해야 하며, 이후 과정은 대부분 대기열을 소진하는 작업임 -
완료 상태는 ‘출력 파일이 디스크에 존재함’처럼 기계적으로 판별할 수 있어야 하고, 대기열은 재개 가능해야 함
Bun 이전 결과와 제약
- Bun의 Rust 포트는 프로덕션에서 운영 중이지만, Rust 코드의 약
**4%가 **unsafe
블록 안에 있음
-
대부분 C/C++ 경계의 한 줄짜리 포인터 연산임
-
도구로 탐지 가능한 모든 메모리 누수를 수정함
-
빌드를 2,000회 반복한 벤치마크에서 메모리 사용량이 6,745MB에서
609MB로 감소함 -
Linux와 Windows 바이너리 크기는 19% 줄어듦
-
언어 간 최적화를 통해 HTTP 서비스와
next build
, tsc
같은 실제 워크로드 성능이 2~5% 향상됨
- 대규모 이전에서는 생성된 코드 한 줄 한 줄보다
루프가 만든 결과와 반복 패턴을 검토해야 함
관련 자료
댓글과 토론
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기