Vercel 팀이 Turborepo의 Go 코드베이스 약 7만 줄을 Rust로 이식하는 15개월 프로젝트를 마무리했다. 단순한 언어 전환이 아닌, Go Sandwich 아키텍처, 해시 안정성 문제, Capnproto 직렬화 도입 등 대규모 언어 마이그레이션에서 생기는 실제 공학적 도전을 상세히 기록했다.
핵심 포인트- 7만 줄 Go 코드를 15개월에 걸쳐 점진적으로 Rust로 이식했으며, Turborepo 1.11이 최초 전 Rust 버전으로 출시됐다
- Go Sandwich 아키텍처로 Go와 Rust 컴포넌트가 공존하는 하이브리드 단계를 거쳐 점진적 이식이 가능했다
- 언어 간 해시 동등성 보장을 위해 Capnproto 직렬화 포맷을 도입해 두 코드패스 결과를 바이트 단위로 비교·검증했다
- Rust 타입 시스템으로 Go의 문자열 기반 타입을 enum으로 교체해 컴파일 타임 정확성을 확보했다
- 사내 CI에서 실험적 Rust 코드패스를 72시간 도그푸딩한 뒤 카나리 릴리즈로 점진적 배포했다
상세 정리- 이식 동기: 성능 향상, 안정성 개선, 향후 Vercel DX 플랫폼과의 깊은 통합을 위해 Go에서 Rust로 전환 결정.
- Go Sandwich 패턴: 초기에는 Go가 외부 인터페이스를 담당하고 내부 컴포넌트만 Rust로 교체하는 샌드위치 구조 채택. 점진적 이식을 가능하게 했지만, 비동기·멀티스레드 코드 경계에서 한계에 봉착.
- 이식된 주요 컴포넌트: 패키지 그래프(의존성 관계), 프룬 명령(컨테이너화용 의존성 격리), 파일 해싱 시스템(캐시 비교용 지문 생성), 락파일 분석, 캐시 서명 검증.
- 해시 안정성 문제: Go와 Rust가 동일 입력에 동일 해시를 출력하지 않으면 기존 사용자 캐시가 전부 무효화된다. 이를 해결하기 위해 Capnproto 도입.
- Capnproto 도입: 크로스플랫폼 직렬화 포맷으로 바이트 단위 정의가 보장됨. CI에서 Go·Rust 양쪽 코드패스 결과를 비교해 미묘한 해시 불일치 버그를 조기에 발견.
- Rust 타입 개선 예시: Go에서 워크스페이스 루트를 지칭하던 문자열 기반 특수값(//)을 Rust enum으로 교체 — 컴파일 타임에 잘못된 경로 사용을 차단.
- 테스트 전략: --experimental-rust-codepath 플래그로 Rust 코드패스를 내부 CI에서 먼저 실행. 로그 줄 단위·출력 단위로 Go와 비교 후 72시간 내부 도그푸딩, 그 다음 카나리 릴리즈.
- 회고 교훈: Capnproto를 처음부터 선택했어야 했고, JSON→Protobuf→Capnproto 반복으로 시간이 낭비됐다. 이식 전 코드 품질·문서화·테스트 강화가 이식 속도를 올린다.
- 향후 계획: Rust 기반으로 Vercel DX 플랫폼, Conformance, Code Owners 기능을 엔터프라이즈 규모로 통합 예정.
왜 읽나대규모 Go-to-Rust 마이그레이션을 고려하거나, 빌드 도구·CLI 툴의 언어 이식 전략과 실전 함정을 알고 싶은 시스템 엔지니어·인프라 엔지니어.