생산적인 모노레포를 만들기 위한 필수 요소

1 week ago 4

  • 모노레포 도입은 조직의 일관성, 코드 공유, 공동 툴링 환경 강화 등 장점이 있으나, 빅테크 사례를 그대로 따라가면 새로운 문제와 도전에 직면하게 됨
  • 성공적인 모노레포를 위해서는 모든 주요 작업을 O(repo)가 아닌 O(change) 로 만드는 원칙을 지켜야 하며, 빌드·테스트·CI/CD 각 단계에서 이에 맞는 도구와 전략이 필요함
  • 소스 컨트롤은 git을 시작으로 규모가 커질수록 sparse checkout, 가상 파일시스템 등 점진적 확장 고려 필요
  • 빌드 시스템은 가능한 한 단일 언어 유지, 각 언어의 기본 빌드 툴로 최대한 버티고, 꼭 필요할 때 Bazel/Buck2 등으로 점진적 전환 권장
  • 테스트·CI/CD는 변화 영향 범위만 빠르게 감지하여 빌드·테스트·배포해야 하며, 대규모 모노레포에서는 테스트 자동 재시도, flaky test 격리 등 신뢰성 확보 전략도 필수

서론: 모노레포를 향한 여정의 시작

  • 새로운 Developer Productivity 팀에 있는 엔지니어라면, 모노레포 도입 결정 이후 어떤 준비와 노력이 필요한지 고민이 커짐
  • Google, Meta, Uber 등 대기업의 모범 사례는 근사해 보이지만, 현실적으로 그들과 동일한 수준의 결과는 불가능함
  • 각 조직은 자기만의 이유와 필요성에 맞춰 모노레포 도입을 결정해야 하며, 그 과정에서 일관성(consistency), 조직적 통합, 공동 툴링 등에서 이점을 추구할 수 있음

모노레포의 필요성을 명확히 하기

  • 대기업 사례는 결과적으로 도달한 모습일 뿐, 초기에 참고할 근거로 삼기에는 부적절함
  • 실제로는 새로운 문제들이 발생하며, 기존 여러 레포 관리 체계와는 다른 유형의 이슈가 발생함
  • 모노레포의 도입 목적은 일관성 유지, 조직 전반에 걸친 툴링 통합, 엔지니어링 표준 및 컨벤션 적용 등에 있음
  • 각 팀은 자체 문화와 방향에 맞는 목표를 명확히 하여야 효과적인 결과를 얻을 수 있음

골든 룰: O(change)의 원칙

  • 모든 저장소 관련 도구들은 빠른 동작을 위해 O(repo) 가 아니라 O(change) 복잡도를 가져야 함
  • 실제로 대규모 모노레포가 클수록 기존 도구들의 비효율성이 두드러지므로, 성능 문제를 극복하는 구조적 설계가 필수임
  • 대기업 기술 블로그에서 언급되는 혁신 역시, 대부분 O(repo)로 인한 비효율 극복에 집중되어 있음

소스 컨트롤

  • 대부분 소프트웨어 조직은 Git을 기본으로 사용하나, Git은 중앙집중식 모노레포 환경에서 대규모로 확장될 때 성능 한계가 있음
    • 현실적으로 대부분의 조직은 git+GitHub로 상당히 오래 버틸 수 있음
  • 성장이 빨라질수록, sparse checkout(부분 클론) 기능과 가상 파일시스템(필요시 파일을 서버에서 동적으로 다운로드) 같은 구조가 필요해짐
  • 대기업은 이에 맞춰 Git을 포킹하거나 별도의 시스템을 개발함 (Microsoft: 자체 Git 포크, Meta: Mercurial 포크, Google: Piper 등)
    • Jujutsu 등 차세대 소스컨트롤도 고려할 만함
  • 규모가 작을 때는 Git을 무리없이 사용 가능하나, 성장 과정에서 확장 전략을 염두에 둘 필요가 있음
  • 소스코드에 IDL(Interface Definition Language) 로 생성된 코드가 포함되면 저장소 크기가 기하급수적으로 증가하는 현실적인 문제도 존재함

빌드 시스템

  • Bazel, Buck2 등은 대표적인 모노레포 빌드 툴로 다수 언어와 복잡한 빌드 그래프를 지원함
    • 강력하지만 복잡성/운영 부담 큼
  • 빌드를 단일 언어로 유지하면 삶이 훨씬 편해지며, 각 언어별 빌드 시스템(예: Maven, Gradle, Cargo, Go 등) 역시 높은 확장성을 가짐
  • 빌드 시스템의 핵심 역할은 “지정한 빌드 타겟을 효율적으로 빌드(효율적 아티팩트 생성)”하고 “변경된 파일로 인해 영향받는 타겟을 신속하게 산출”하는 것임
  • 이를 위해 target determinator(타겟 결정 도구) 개념이 필요하며, Rust, Go, Bazel 등 생태계에는 이미 다양한 해결책이 있음
  • Remote execution과 캐싱은 초대형 규모에서만 실제적으로 필요하며, 일반적인 기업에선 target determination이 더 실용적으로 활용됨

테스트

  • 전체 테스트를 매번 실행하는 것은 비효율적이므로, 변경 영향 범위만을 테스트하는 시스템이 요구됨
  • 플레이키(Flaky) 테스트는 대규모 테스트 시스템에서 더욱 심각한 이슈가 될 수 있음
  • 테스트 시스템은 자동 재시도, 테스트 영향 범위 자동 판단, 플레이키 테스트 격리 등이 필요함
  • 일부 언어(예: Rust의 nextest, Java의 JUnit 등)는 이러한 고급 기능을 기본이나 확장으로 제공함
  • 모노레포의 테스트 체계는 빌드 시스템과 밀접히 통합되어야 효과적임

지속적 통합(CI)

  • CI 시스템은 변경사항에 따라 필요한 빌드 아티팩트유효성 검증을 자동 수행해야 함
  • Target determinator 성능과 효율성이 CI 파이프라인의 핵심 요소로 작동함
  • 현대 CI는 “Merge Queue” 등 다양한 전략을 사용해, 코드 품질 유지와 병합 속도 최적화 간의 균형을 찾아야 함
    • 단일 커밋/PR 마다 모든 검증 작업을 실행할지, 일부만 선별할지, 여러 PR을 배치 처리할지 등
  • Throughput(처리량), Correctness(정확성), Tail latency(최대 대기 시간) 간의 트레이드오프를 자체적으로 정의하고 설계해야 함
  • 대용량 모노레포의 병합 관리와 CI 효율성 강화는 아직까지도 완벽한 해법이 없는 도전 과제임
  • Rust(bors), Chromium, Uber 등은 각자 다른 병합/검증 전략을 선택함

지속적 배포(CD)

  • 모노레포 내 모든 변경이 원자적으로 배포될 것이라는 환상은 현실과 다름
  • 하나의 PR로 다수 서비스의 인터페이스와 구현, 클라이언트까지 한꺼번에 변경할 수 있지만, 결국 실제 배포(Deploy)는 비동기적으로 진행되어 배포 시점에 문제 발생 가능
  • 서비스 간 계약(Contract)을 깨뜨리는 변경은 배포시 심각한 장애를 유발할 수 있음
  • 효과적인 모노레포 CD 전략은 배포 시스템 주기, 서비스 계약 검증, 문제 발생 시 신속감지 및 대응 능력 등이 필요함

결론

  • 모노레포는 조직적 일관성과 엔지니어링 문화 강화를 위한 강력한 도구이나, 지속적인 엔지니어링·툴링 투자가 필요
  • 각 단계별로 O(change) 원칙에 맞춘 자동화·도구·문화 구축이 핵심
  • 성장과 함께 도구 또한 지속적으로 진화시키며, 조직 목표와 문화를 반영하는 체계적인 관리 노력이 중요함
  • 충분한 각오와 헌신, 지속적 투자가 있다면, 모노레포는 궁극적으로 그만한 가치를 만들어줌

Read Entire Article