2026. 07. 28. · CK

Bun 대규모 포팅의 핵심: 실패 큐와 검증 게이트

Bun의 Zig에서 Rust 포팅 사례는 규모와 속도로 관심을 끌었다. Anthropic의 공식 설명에 따르면 Jarred Sumner는 2주가 안 되는 기간에 백만 줄 규모의 코드를 만들었고, Bun의 기존 테스트 전체가 CI에서 통과한 뒤 병합했다. 병합 후에는 회귀 19건이 발견됐고 팀은 모두 수정했다.

비용도 작지 않았다. Anthropic은 이 마이그레이션이 캐시되지 않은 입력 토큰 59억 개와 출력 토큰 6억9천만 개를 사용했고 API 가격 기준 약 16만5천 달러에 해당한다고 적었다. 개인 프로젝트가 에이전트 수와 토큰 사용량을 따라 할 이유는 없다. 기존 코드가 명세 역할을 했고 테스트가 객관적인 판정 기준을 제공했으며, 실패를 작업 큐로 바꿀 수 있었다는 구조를 봐야 한다.

마이그레이션 목적을 수치로 고정한다

언어를 바꾸는 작업은 새 코드가 컴파일되는 것으로 끝나지 않는다. 사용자는 기존 명령과 API가 같은 결과를 내기를 기대한다. 팀은 투자할 비용과 얻을 효과를 먼저 적어야 한다.

현재 문제: 메모리 누수, 빌드 시간, 유지보수 인력
유지할 동작: CLI, 파일 형식, 오류 코드, 성능 범위
허용할 차이: 폐기할 기능과 호환성 예외
예산: 사람 검토 시간, 토큰, 인프라 비용
중단 조건: 일정, 회귀 수, 비용 상한
롤백: 기존 바이너리와 배포 경로

Anthropic은 Bun 포팅 후 측정 가능한 결과도 공개했다. 반복 빌드 벤치마크의 메모리 사용량이 줄었고 Linux와 Windows 바이너리는 19% 작아졌으며, 일부 실제 워크로드에서 2~5% 빨라졌다고 설명했다. 공개된 수치는 마이그레이션을 시작하기 전 기준선과 같은 조건으로 비교해야 의미가 있다.

내 프로젝트에서도 리팩터링 전에 현재 출력과 소요 시간을 저장한다. 샘플 입력과 결과 파일, 오류 메시지를 fixture로 만든다. 변경 후 구조가 깔끔해 보여도 사용자가 의존한 동작이 사라지면 실패로 판정한다.

기존 코드를 번역 규칙집으로 바꾼다

대규모 포팅에서 원본 코드는 가장 상세한 명세다. 원본을 그대로 에이전트에 던지면 파일마다 다른 해석을 만들 수 있다. 팀은 반복되는 번역 결정을 규칙집으로 정리한다.

원본 타입과 대상 타입 매핑
메모리 소유권과 수명 규칙
오류 반환과 예외 처리 방식
플랫폼별 조건부 코드
외부 C/C++ 경계
테스트와 벤치마크 명령
금지된 우회 구현

첫 파일을 옮기면서 발견한 예외를 규칙집에 반영한다. 다음 에이전트는 최신 규칙을 읽고 작업한다. 규칙을 바꾸면 이미 변환한 파일 가운데 영향을 받는 목록을 다시 검사한다.

규칙집에는 승인자도 둔다. 에이전트가 새로운 매핑을 임의로 표준으로 만들지 않게 한다. 하나의 편의를 위해 unsafe 범위를 넓히거나 오류를 무시하는 선택은 사람이 영향과 대안을 확인한다.

작업 단위를 작고 재개 가능하게 만든다

긴 세션 하나에 마이그레이션 전체를 맡기면 중간 상태를 다음 세션이 이해하기 어렵다. 파일과 모듈, 테스트 묶음처럼 독립적으로 판정할 수 있는 단위로 나눈다.

{
  "id": "crate-parser-014",
  "source": "src/parser.zig",
  "target": "src/parser.rs",
  "status": "failed",
  "rulebook_version": "2026-08-17.2",
  "checks": {
    "compile": "passed",
    "unit": "failed",
    "parity": "pending"
  },
  "last_error": "fixture-27 output mismatch"
}

에이전트가 작업을 시작할 때 큐 항목을 가져가고, 완료 후 산출물과 검사 결과를 기록한다. 프로세스가 종료돼도 다음 실행이 마지막 실패에서 이어갈 수 있다. 완료 상태는 에이전트의 선언으로 정하지 않는다. 대상 파일과 검사 결과가 존재해야 완료로 바뀐다.

두 작업이 같은 타입이나 공통 모듈을 바꾸면 독립 단위가 아니다. 공통 계약을 먼저 옮기고 병합한 뒤 하위 작업을 시작한다. 병렬화 전에 의존 그래프를 확인해야 논리 충돌을 줄일 수 있다.

실패를 다음 작업의 입력으로 쓴다

컴파일러와 테스트, parity 검사는 실패를 구체적인 작업으로 만든다.

실패 수집
오류 유형과 영향 파일 분류
작은 작업 묶음 생성
수정과 동일 게이트 실행
결과 기록
반복 오류를 규칙집에 반영

컴파일 오류는 파일과 줄, 타입 정보를 제공한다. 테스트 실패는 입력과 기대값, 실제값을 큐에 넣는다. 성능 회귀는 벤치마크 환경과 기준값을 함께 기록한다.

같은 오류가 여러 파일에서 발생하면 각 에이전트가 임시 패치를 만들게 두지 않는다. 원인을 공통 변환 규칙이나 도구에서 찾는다. 규칙집을 수정한 뒤 해당 유형의 작업을 다시 실행한다. 병렬 에이전트가 같은 실수를 대량 복제하는 상황을 여기서 막는다.

검증 게이트를 층으로 나눈다

한 종류의 테스트가 사용자 동작을 모두 보장하지 않는다. 마이그레이션에는 여러 게이트가 필요하다.

게이트확인할 내용실패 시 행동
컴파일타입, 링크, 플랫폼 빌드해당 작업으로 반환
단위·통합모듈 동작과 경계fixture와 원본 비교
parity기존 구현과 같은 출력차이를 승인 또는 수정
성능시간, 메모리, 바이너리 크기기준 초과 원인 분석
보안unsafe, 입력 검증, 의존성전문가 검토
제한 배포실제 사용 경로의 회귀트래픽 중단과 롤백

앞 게이트를 통과해도 다음 게이트에서 실패할 수 있다. Bun 사례의 병합 후 회귀 19건은 CI가 잡지 못한 실제 사용 경로가 있었다는 뜻이다. 테스트 통과를 최종 증명으로 과장하지 않고 제한된 배포와 모니터링을 준비해야 한다.

parity 차이가 의도된 변경이면 승인 기록을 남긴다. 테스트 기대값만 새 결과에 맞추면 호환성 결정을 숨길 수 있다. 사용자 문서와 변경 로그에도 같은 내용을 반영한다.

구현자와 검토자의 증거를 나눈다

구현 에이전트는 자신의 접근이 맞다는 전제로 작업한다. 검토 세션에는 구현 대화 전체를 주지 않는다. 목표와 규칙집, diff, 검사 결과, 알려진 위험을 전달한다.

검토자는 다음 항목을 찾는다.

  • 원본 코드에서 옮기지 않은 분기와 플랫폼 조건
  • 테스트가 없는 오류 경로와 경계값
  • 규칙집을 벗어난 타입과 메모리 처리
  • parity 차이를 테스트 수정으로 숨긴 부분
  • 성능 개선을 위해 안전 검사를 제거한 부분
  • 작업 범위 밖에서 바뀐 공통 코드

발견 사항은 파일과 재현 입력, 영향 범위로 작성한다. 주관적인 코드 스타일은 자동 포매터에 맡기고 회귀 위험에 검토 시간을 쓴다.

병합 후 관찰과 롤백을 설계한다

새 구현을 병합한 시점부터 실제 입력이 들어온다. 오류율과 지연, 메모리, 충돌 보고를 이전 버전과 비교한다. 오류 로그에는 새 구현과 기존 구현을 구분할 버전을 넣는다.

가능하면 일부 트래픽이나 내부 사용자부터 시작한다. 회귀가 기준을 넘으면 새 배포를 중단하고 기존 바이너리로 돌아간다. 데이터 형식까지 바뀌면 양쪽 버전이 읽을 수 있는 전환 기간과 역마이그레이션 절차가 필요하다.

병합 후 발견한 오류는 테스트와 규칙집에 추가한다. 수정 커밋만 남기면 다음 마이그레이션에서 같은 유형을 반복한다. 회귀 19건은 테스트 범위를 넓힐 입력으로 사용한다.

작은 프로젝트에서 가져올 구조

개인 프로젝트는 모듈 하나로 범위를 좁힐 수 있다.

  1. 변경 전 대표 입력과 출력을 fixture로 저장한다.
  2. 목표와 호환성 예외, 비용 상한을 한 페이지로 적는다.
  3. 파일 한 묶음을 옮기고 모든 게이트를 실행한다.
  4. 구현과 검토를 다른 세션에서 진행한다.
  5. 반복된 실패는 규칙과 validator에 반영한다.
  6. 배포 전 백업과 롤백 명령을 확인한다.

에이전트 수를 늘리기 전에 작업 한 개가 독립적으로 완료되고 재시작되는지 본다. 한 에이전트의 실패를 구조화할 수 없다면 여러 에이전트의 실패도 합칠 수 없다.

Bun 포팅 사례에서 가져올 부분은 백만 줄이라는 결과보다 원본 코드와 테스트를 기준선으로 사용한 과정이다. 규칙집과 작업 큐가 맥락을 전달하고, 검증 게이트와 실제 운영이 회귀를 찾았다. 개인 프로젝트에서도 같은 구조를 작은 단위로 적용할 수 있다.

참고자료

Bun 대규모 포팅의 핵심: 실패 큐와 검증 게이트 · iamlazyck