본문 바로가기

IT & AI

Bun의 53만 줄 재작성, 11일보다 먼저 봐야 할 설계

728x90

Bun의 53만 줄 재작성, 11일보다 먼저 봐야 할 설계

AI 뉴스 썸네일
AI 뉴스 썸네일

JavaScript 런타임 Bun은 주석을 뺀 Zig 코드 535,496줄을 Rust로 옮겼어요. 64개 AI 작업을 병렬로 돌려 계획부터 병합까지 11일이 걸렸고, 6,500개 커밋이 만들어졌어요. 숫자만 보면 코드 생성 속도가 먼저 보이지만, 실제 성패를 가른 것은 600줄짜리 이식 규칙과 단계별 검증이었어요. 1

핵심 요약

구분핵심왜 볼 만한가요
전환 이유Bun은 반복되던 메모리 누수와 충돌을 줄이려고 Zig에서 Rust로 옮겼어요언어 변경의 목표가 유행이 아니라 운영 안정성으로 구체적이었어요
사전 설계3시간 동안 이식 원칙을 정리해 600줄짜리 `PORTING.md`를 만들었어요수십 개 작업이 같은 판단 기준을 공유할 수 있었어요
병렬 처리4개 worktree에 16개씩, 모두 64개 AI 작업을 배치했어요파일 변환과 검토를 병렬화하되 Git 충돌은 작업 규칙으로 막았어요
검증 과정파일별 이식 뒤 컴파일 오류, 로컬 테스트, CI 실패를 순서대로 줄였어요생성된 코드의 양보다 기계적으로 판정할 수 있는 관문이 중요했어요
비용API 가격 기준 약 16만 5,000달러가 들었어요빠른 재작성도 강한 테스트와 큰 토큰 예산이 있어야 반복할 수 있어요

1. 11일 만의 재작성은 어떻게 가능했나요

메모리 문제를 줄인다는 목표가 분명했어요

Bun은 번들러, 패키지 관리자, 테스트 러너와 Node.js 호환 기능을 함께 제공해요. 월간 다운로드는 2,200만 건에 이르고 Claude Code와 OpenCode도 Bun에 의존해요. 이 정도 규모에서는 작은 메모리 누수나 간헐적 충돌도 많은 사용자에게 퍼질 수 있어요. 2

Bun 팀은 Zig 컴파일러를 손보고 종단 간 메모리 누수 테스트도 추가했지만, 가비지 컬렉션 값과 수동 관리 값의 수명을 함께 다루는 문제가 계속 남았어요. Rust의 안전한 영역에서는 use-after-free와 double-free가 컴파일 오류로 잡히고, 오류 경로의 정리는 `Drop`으로 맡길 수 있어요. 팀은 이 차이를 재작성 비용을 감수할 근거로 삼았어요. 3

코드를 만들기 전에 이식 규칙부터 썼어요

첫 3시간은 코드를 옮기는 데 쓰지 않았어요. Zig의 패턴을 Rust에서 어떻게 표현할지 논의한 뒤 600줄짜리 `PORTING.md`로 고정했어요. Bun이 자체 이벤트 루프와 시스템 호출을 유지하도록 `tokio`, `rayon`, `hyper`와 일부 표준 I/O 모듈을 금지했어요. 빌림 검사기 충돌을 원시 포인터로 덮지 말고, 값과 빌림 범위를 다시 구성하라는 기준도 넣었어요. 2

전체 1,448개 파일 가운데 3개만 먼저 옮겼어요. 변환을 맡지 않은 별도 검토자가 결과를 두 차례 공격적으로 확인했고, 시험 결과에서 찾은 문제를 규칙에 되돌렸어요. 대량 작업을 시작하기 전에 잘못된 판단이 1,448개 파일에 복제되는 일을 줄인 셈이에요.

728x90

64개 병렬 작업은 Git 규칙부터 손봤어요

처음에는 여러 작업이 같은 저장소에서 `git stash`, `stash pop`, `reset --hard`를 실행해 서로의 변경을 건드렸어요. 모든 작업에 별도 worktree를 주면 저장소 크기 때문에 디스크 공간이 부족했고, 마지막에는 변경분을 한데 모아 컴파일해야 했어요.

팀은 4개 worktree를 만들고 각각 16개 작업을 배치했어요. 특정 파일을 바로 커밋하는 명령 외에는 위험한 Git 명령을 금지했고, 파일 변환 단계에서는 `cargo`처럼 오래 걸리는 명령도 막았어요. 이틀 동안 파일 변환을 마친 뒤에야 crate 단위 컴파일로 넘어갔어요. 병렬 처리 범위와 비싼 검증 단계를 분리했기 때문에 작업끼리 충돌하는 시간을 줄일 수 있었어요. 2

컴파일과 테스트가 종료 조건을 만들었어요

파일 변환이 끝났을 때 코드는 컴파일되지 않았어요. 팀은 crate마다 `cargo check` 결과를 파일별로 묶고, 오류 수정과 두 차례 검토, 검토 결과 반영을 반복했어요. 자료에는 초기 약 1,600개 오류와 순환 의존성을 푸는 과정에서 드러난 약 16,000개 오류가 함께 언급돼요. 두 숫자는 범위가 다르므로 같은 집계로 보면 안 돼요. 1

컴파일 뒤에는 로컬 테스트를 실행할 수 있게 만드는 데 약 이틀을 썼어요. 이어서 실패한 테스트를 고치고 CI를 통과시키는 데 수일이 더 들었어요. 11일이라는 기간에는 파일 번역만이 아니라 컴파일 복구와 테스트 안정화도 포함돼요.

비용은 작은 실험 수준이 아니었어요

전체 작업에는 비캐시 입력 59억 토큰, 출력 6억 9,000만 토큰, 캐시 입력 읽기 720억 토큰이 쓰였어요. API 가격으로 환산하면 약 16만 5,000달러예요. 미국 중급 소프트웨어 엔지니어의 연간 기본급과 비슷한 규모지만, 엔지니어 한 명이 11일 안에 같은 양을 옮기기는 어려워요. 2

비용 비교에는 빠진 항목도 있어요. Bun은 코드베이스를 깊이 아는 엔지니어와 기존 테스트, CI, 파일 단위로 나눌 수 있는 구조를 이미 갖고 있었어요. 이런 기반이 약한 프로젝트라면 토큰을 더 써도 같은 결과를 내기 어려워요.

왜 중요한가요

Bun 사례는 대규모 코드 이전에서 사람이 맡을 일이 사라졌다는 뜻이 아니에요. 엔지니어는 언어 변경의 이유를 정하고, 기존 구조를 어디까지 보존할지 결정했어요. 작업 충돌이 생기자 Git 사용 범위를 다시 설계했고, 컴파일과 테스트 결과를 다음 수정 단계로 연결했어요. 3

비슷한 작업을 검토하는 팀이라면 코드 줄 수보다 판정 기준부터 확인해야 해요. 원본과 새 구현을 같은 테스트로 비교할 수 있는지, 컴파일 단위를 독립적으로 고칠 수 있는지, 잘못된 변환 규칙을 전체 작업에 다시 반영할 수 있는지가 먼저예요. 테스트가 약하면 많은 코드를 빠르게 만든 뒤 사람이 확인해야 할 범위만 커질 수 있어요.

전면 재작성은 여전히 비싼 선택이에요. 반복되는 메모리 오류나 생태계 제약처럼 언어를 바꿀 이유가 뚜렷하고, 제품 개발을 장기간 멈추는 비용이 더 클 때 계산이 맞을 수 있어요. 작은 프로젝트나 검증 기준이 모호한 서비스라면 문제 구간을 단계적으로 교체하는 방식이 더 현실적일 수 있어요.

참고 자료

  1. AI로 11일 만에 끝낸 Bun의 Zig→Rust 재작성에서 배울 점 — GeekNews
  2. The Pulse: What can we learn from Bun’s rapid Rust rewrite with AI? — The Pragmatic Engineer
  3. Bun is now mostly written in Rust — Bun
728x90