모노레포 적용하기 with 🚀Turborepo (1/2)
2025-01-05

모노레포 등장배경
모노레포란 버전 관리 시스템에서 두 개 이상의 프로젝트 코드가 동일한 저장소에 저장되는 소프트웨어 개발 전략다. Google, Facebook, Microsoft, Uber, Airbnb, 그리고 Twitter 등 글로벌 테크 회사들은 이미 각자 자신들의 운영 전략 아래 대규모 모노레포를 운영하고 있다.

모노레포를 알아보기 전에, 멀티레포를 알아보자.
멀티레포(폴리레포라고도 부름)는 현재 대부분의 애플리케이션을 개발하는 표준적인 방법이다.
멀티레포 구조는 폴리레포(polyrepo) 구조라고도 부른다. 앞선 예시의 분리된 각 모듈은 멀티레포 구조에서 고유한 저장소가 있는 독자적 프로젝트가 된다.
만약, 하나의 서비스를 위해 웹과 앱이 모두 존재하며, 그 웹과 앱은 공통된 디자인시스템을 따른다고 가정하자. 그럴경우, 디자인 시스템을 라이브러리로 NPM으로 퍼블리싱하여 사용한다고 가정하자. 이 경우만 해도 하나의 서비스를위해 3가지의 리포지토리가 생성된다.
이와 같이 멀티레포는 다음과 같은 문제점이 있다.
- 번거로운 프로젝트 생성 새로운 공유 패키지를 생성할 때마다 다음과 같이 번거로운 과정을 거쳐야 한다. 저장소 생성 > 커미터 추가 > 개발 환경 구축 > CI/CD 구축 > 빌드 > 패키지 저장소에 publish
- 패키지의 중복 코드 가능성 위의 번거로움을 피하기 위해 각 프로젝트에서 공통 구성 요소를 자체적으로 작성한다면, 초기 시간을 아낄 수 있지만 시간이 지날수록 보안 및 품질 관리 부담을 증가시킨다.
- 관리 포인트 증가 늘어난 프로젝트 저장소의 수만큼 관리 포인트가 늘어난다. 린트, 테스트, 개발 모드 실행, 빌드, 게시, 배포 등의 과정을 저장소의 수만큼 반복해야 한다. (ex. 여러 프로젝트에서 사용하는 공통 컴포넌트에 대한 업데이트가 필요할 때. 모노레포는 한번에 위 일련의 과정을 실행가능)
- 일관성 없는 개발자 경험(DX) 각 프로젝트는 테스트 실행, 빌드, 테스트, 린트, 배포 등을 위해 고유한 명령 집합을 사용한다. 이러한 불일치는 여러 프로젝트에서 사용할 명령을 기억해야 하는 정신적 오버헤드를 만든다.
- 다른 패키지의 변경 사항 파악 관련 패키지의 변화를 지켜보거나 통지받지 않으면 문제가 발생할 수 있다.
- 교차 저장소의 리팩터링 비용 관련 패키지의 변화가 있을 때 여러 저장소에 걸쳐 변화를 반영하는 것은 쉬운 일이 아닐 것이다. 또한 이렇게 리팩터링된 각 패키지의 버전은 어떻게 관리해야 할까.
서비스 규모가 커질수록 리포지토리의 수는 증가하고 복잡해지며, 각 모듈 의존도에 따라 하나의 업데이트를 위해 많은 시간이 소요된다.
그렇다면 모듈을 적절히 분리하여 관심 분리를 이루면서, 동시에 분리된 모듈을 쉽게 참조하고 테스트, 빌드, 배포 과정도 쉽게 한 번에 할 수는 없을까? 이제 모노레포가 출동할 시간이다.
모노레포
모노레포(monorepo) 구조는 두 개 이상의 프로젝트가 동일한 저장소에 저장되는 소프트웨어 개발 전략이다. 앞선 예시의 분리된 모듈들은 모노레포에서 여전히 독자 프로젝트로 존재하지만 저장소는 같은 곳을 사용한다.

모노레포가 해결하는 멀티레포의 문제
- 더 쉬운 프로젝트 생성 멀티레포에서 공유 패키지를 만들 때 다음과 같은 과정을 거친다. 저장소 생성 > 커미터 추가 > 개발환경 구축 > CI/CD 구축 > 빌드 > 패키지 저장소에 publish 모노레포에서는 저장소 생성 및 커미터 추가 과정이 필요 없고, 개발 환경, CI/CD, 빌드, 게시 등의 과정에 기존 DevOps를 이용하므로 새 프로젝트 생성에 대한 오버헤드가 없다.
- 더 쉬운 의존성 관리 의존성 패키지가 같은 저장소에 있으므로 버전이 지정된 패키지를 npm registry와 같은 곳에 publish할 필요가 없다.
- 단일화된 관리 포인트 개발환경 및 DevOps에 대한 업데이트를 한 번에 반영할 수 있다.
- 일관된 개발자 경험 제공 애플리케이션을 일관되게 구축하고 테스트할 수 있다. 개발자는 다른 팀의 애플리케이션에 자신 있게 기여하고 변경 사항이 안전한지 확인할 수 있다.
- 프로젝트들에 걸친 원자적 커밋 커밋할 때마다 모든 것이 함께 작동한다. 변경 사항의 영향을 받는 조직에서 쉽게 변화를 확인할 수 있다.
- 서로 의존하는 저장소들의 리팩터링 비용 감소 모노레포는 대규모 변경을 훨씬 더 간단하게 만든다. 100개의 라이브러리로 만든 10개의 앱을 리팩터링하고 변경을 커밋하기 전에 모두 작동하는지 확인할 수 있다.
모노레포에 대한 오해
- 다른 팀이 내가 모르는 사이에 내 코드를 변경한다면? GitHub에는 CODEOWNERS와 같은 기능을 사용하여 폴더 기반으로 소유권을 구성할 수 있다.
@global-owner1 @global-owner2 ## 이 저장소에 대한 모든 PR을 소유자에게 리뷰받아야 머지할 수 있다.
packages/todo-api/* @john @jane ## todo-api 경로는 john과 jane에게 리뷰받아야 한다.
packages/i18n/* @michael ## i18n은 michael에게 리뷰받아야 한다.
- 모노레포가 멀티레포보다 항상 나은 방법인가?
그렇지 않다. 멀티레포의 단점이 모노레포의 장점이고 장단점이 교차하기 때문에 적절한 상황에서 사용해야 한다.
모노레포의 핵심적 특징은 프로젝트 사이의 관계이고, 모노레포가 적절한 상황은 다음과 같다.
- 유사한 제품의 집합
- 여러 프로젝트의 변화를 한눈에 파악해야 할 때
- 호스트 애플리케이션을 플러그인 등으로 확장할 때
- 공통 기능을 재사용하는 관련된 프로젝트의 집합
- 유사한 DevOps로 구성된 프로젝트의 집합
사실 위와 같이 글로만 모노레포를 접한다면 와닿지 않을 수 있다.
다음 글에서 Turborepo를 직접 적용해보며 모노레포가 가진 장점을 알아보자