목차
1인 개발을 진행하고 있는데 Github에 모노레포(Monorepo) 형태로 구현을 하고 있었습니다. 그런데 구현을 하다보니 연관성이 많이 떨어지는 디렉토리 구조를 가지고 있다보니 분리를 할까? 라는 고민에 빠지게 되었습니다. 근데 굳이? 라는 생각이 들었고 어떤 장단이 있는지 한번 비교 분석해보겠습니다.
모노레포(Monorepo)의 장단점
장점:
- 일관된 코드베이스 유지: 모든 코드를 하나의 저장소에서 관리하므로 항상 전체 시스템이 연동된 올바른 상태를 유지할 수 있습니다. 여러 부분의 코드가 함께 버전 관리되기 때문에, 프로젝트 간 버전 불일치나 충돌이 줄어듭니다.
- 코드 재사용 및 공유 용이: 공통으로 사용하는 모듈이나 라이브러리를 복사하지 않고도 한 곳에서 공유할 수 있어 중복 코드가 감소합니다. 예를 들어 프론트엔드와 백엔드가 동일한 유틸리티 함수를 필요로 할 때, 모노레포(Monorepo)에서는 해당 함수를 한 번만 구현해 같이 활용할 수 있습니다.
- 의존성 관리 단순화: 모든 프로젝트가 동일한 저장소에 있으므로 패키지 버전과 의존성을 한꺼번에 관리하기 쉽습니다. 외부 라이브러리 업그레이드도 일관되게 적용할 수 있어 Dependency Hell을 줄여줍니다.
- 원자적 변경(Atomic Changes): 여러 서비스나 모듈에 걸친 기능 수정도 한 번의 커밋으로 일괄적으로 처리할 수 있습니다. 예를 들어 API 변경 시 백엔드와 프론트엔드 코드를 하나의 PR로 수정・배포하면, 각 부분을 따로 관리할 때 생길 수 있는 호환성 문제를 줄일 수 있습니다.
- 통합된 개발 워크플로우: 한 저장소에서 모든 코드가 관리되므로 코드 리뷰와 테스트를 일관되게 수행할 수 있습니다. CI/CD 파이프라인도 하나로 통합해 운영할 수 있어 전체 배포 과정의 동기화가 수월합니다. 작은 팀이나 단일 팀 내 협업에서는 이러한 통합으로 개발 효율이 높아집니다.
단점:
- 빌드/테스트 시간 증가: 여러 프로젝트를 한꺼번에 빌드하고 테스트하므로 CI 빌드 및 테스트 시간이 길어지고 저장소 용량도 커질 수 있습니다. 코드량이 많아지면 로컬 개발 환경 설정이나 IDE 인덱싱도 느려질 수 있습니다.
- 복잡한 저장소 관리: 하나의 저장소에 폴더별로 여러 프로젝트가 들어있으므로 폴더 구조를 체계적으로 잡지 않으면 관리 복잡성이 증가합니다. 권한 설정이나 브랜치 전략 수립도 어려워질 수 있고, 무분별하게 프로젝트 간 의존성이 연결될 위험도 있습니다.
- 부분 배포의 어려움: 특정 서비스만 수정되어도 전체 저장소를 기준으로 버전이 올라가기 때문에, 개별 프로젝트만 독립적으로 배포하거나 버전 관리하기가 까다롭습니다. 서비스별로 완전히 독립적인 릴리스 사이클을 갖기 어려워지는 측면이 있습니다. 이를 해결하려면 워크스페이스 도구(Nx, Lerna 등)나 브랜치 전략으로 각 부분만 빌드/배포하도록 추가 설정이 필요합니다.
- 툴링 필요성: 프로젝트 규모가 커질수록 모노레포(Monorepo)를 관리하기 위한 전용 도구나 스크립트가 필요할 수 있습니다. 빌드 속도 향상을 위한 캐시 도구, 변경 영향 범위만 빌드하는 CI 설정 등 추가 투자가 요구됩니다. 작은 규모에서는 간단한 스크립트로도 충분하지만, 아주 대규모가 되면 구글처럼 자체 관리 도구까지 고려해야 합니다.
레포지토리 분리(멀티레포-Multirepo)의 장단점
장점:
- 명확한 경계와 오너십: 서비스나 모듈별로 별도 저장소를 두면 팀별 책임 범위가 명확해집니다. 각 저장소에 전담 관리자가 생기므로 코드 소유권이 분명해지고, 한 부분의 문제가 다른 저장소에 바로 영향을 주지 않아 안정성이 높아집니다.
- 간결한 저장소와 빠른 CI: 개별 저장소는 코드베이스가 작기 때문에 빌드 속도나 CI 실행이 상대적으로 빠릅니다. 변경 범위가 작아 Git Hook이나 파이프라인도 가벼워지고, 이력 관리도 단순합니다. 필요에 따라 서비스별로 다른 개발 스택이나 배포 주기를 독립적으로 운영하기도 수월합니다.
- 독립적인 버전 관리: 각 서비스가 자체 릴리스 주기를 가질 수 있어, 하나의 기능을 다른 서비스와 별개로 배포하거나 롤백할 수 있습니다. 예를 들어 모바일 앱과 웹 서비스를 별도로 버전 관리하면 한 쪽의 배포 지연이 다른 쪽에 영향을 주지 않습니다 (단, 이 경우 인터페이스 변경 시 호환성에 유의해야 합니다).
단점:
- 코드 중복 및 재사용 어려움: 저장소가 나뉘면 공통 코드를 공유하기 어려워져 중복 구현이 발생할 수 있습니다. 다른 저장소의 유틸리티를 사용하려면 패키지로 만들어 배포하는 등 별도의 작업이 필요하며, 이는 작은 팀에 부담이 될 수 있습니다.
- 복잡한 변경 작업: 하나의 기능 개선에 여러 저장소를 수정하고 배포해야 할 수 있어 개발 작업이 번거롭습니다. 예를 들어 API 스키마 변경 시 백엔드와 프론트엔드 저장소에 각각 변경 사항을 반영하고 따로 배포를 진행해야 합니다. 이 과정에서 어느 한쪽의 변경을 깜빡할 위험도 있습니다.
- 버전 불일치와 의존성 문제: 분리된 레포지토리들은 각자 버전을 가지므로, 동시 수정이 필요한 변경에서 호환성 문제가 발생하기 쉽습니다. 한 저장소의 변경이 다른 쪽에 즉시 전파되지 않아 인터페이스 불일치나 버전 충돌이 일어날 수 있습니다. 이를 관리하려면 각 서비스 간 명확한 API 계약과 의사소통이 필수입니다.
- 분산된 CI/CD와 코드 리뷰: 저장소별로 별도 파이프라인을 구축하고 관리해야 하므로 초기 설정과 유지보수가 늘어납니다. 또한 기능 하나에 대한 수정이 여러 PR로 나뉘어 코드 리뷰가 분산되고 전체 변경 흐름을 한눈에 파악하기 어렵습니다. 작은 수정도 여러 곳에 PR을 보내야 하는 번거로움이 생깁니다.
1인 개발 및 분산 배포 환경에 유리한 구조
혼자서 개발하고 구성 요소들(데몬, 백엔드, 프론트엔드 등)을 관리하는 경우 모노레포(Monorepo) 방식이 대체로 유리한 것으로 평가됩니다. 실제로 프로젝트 규모가 크지 않고 단일 팀이 여러 파트를 담당하는 상황에서는 모노레포로 얻는 이점이 더 크다는 의견이 많습니다.
- 유지보수 용이성: 하나의 저장소에서 모든 코드를 다루면 변경 사항을 추적하고 이해하기 쉽습니다. 프론트엔드와 백엔드가 한 목적을 위해 tightly 연동되어 있을 때, 한 곳에서 코드를 보면 전반적인 맥락 파악이 수월합니다. 반대로 레포지토리를 나누면 저장소별로 이슈와 코드를 오가야 해 혼자 모든 것을 관리하는 부담이 늘어날 수 있습니다.
- 통합된 배포 관리: 모노레포(Monorepo)에서는 한 번의 커밋으로 전체 시스템 버전을 올릴 수 있기 때문에 각 부분의 배포 시점을 맞추기가 쉽습니다. 예를 들어 API 변경을 커밋 하나에 담아두면 프론트/백엔드를 동시에 배포하거나, 최소한 같은 소스 기준으로 빌드하게 되어 호환성을 보장하기 수월합니다. 서버리스로 배포된 프론트엔드는 모노레포 내 특정 디렉토리만 배포하도록 설정할 수 있고, 백엔드/데몬도 동일 레포지토리에서 필요한 코드만 가져가 구동하도록 스크립트를 짤 수 있습니다. CI 도구 설정을 통해 폴더별로 빌드/배포 조건을 걸어두면, 레포 분할 없이도 각 구성요소를 개별적으로 배포 관리할 수 있습니다.
- 개발 효율: 단일 개발자가 여러 저장소를 전환하지 않고 하나의 리포지토리에서 작업하므로 맥락 전환 비용이 줄어듭니다. 환경 설정(예: 의존성 설치, 린트/포맷 규칙 등)도 통일하기 쉬워 개발 경험이 일관적입니다. 따라서 작은 프로젝트나 사이드 프로젝트에서는 굳이 레포를 쪼개서 복잡도를 늘리기보다는 모노레포(Monorepo)로 간소하게 유지하는 편이 실용적입니다.
⚠️ 예외 상황: 각 구성 요소가 기술 스택이 완전히 다르거나 전혀 별개로 동작하여 연관성이 낮다면, 레포지토리를 분리해 관리 이점을 얻을 수도 있습니다. 예를 들어 모바일 앱과 서버가 매우 독립적으로 개발되거나, 공개 오픈소스로 배포할 라이브러리 모듈이 있다면 별도로 분리하는 것을 고려해볼 수 있습니다. 하지만 이 경우에도 공통되는 부분(예: API 스키마 정의, 공용 유틸 등)이 있다면 모노레포가 여전히 편리할 것입니다.
실무 사례 및 권장 관행
실제 사례: 대규모 기업에서는 두 접근 방식 모두 활용되고 있습니다. 구글(Google)은 거의 모든 코드를 단일 저장소에서 관리하는 대표적인 모노레포(Monorepo) 사례로, 2016년 기준 86TB에 달하는 소스를 하나의 리포지토리로 운영했습니다. 이를 통해 전사적인 코드 재사용과 일관성을 얻었지만, 자체 개발한 도구로 관리할 정도로 규모가 방대합니다. 반면, 네이버와 같이 각기 다른 서비스(뉴스, 지도, 카페 등)를 여러 팀이 운영하는 조직은 서비스별 멀티레포를 사용하는 것으로 추정됩니다. 분야에 따라 Facebook도 내부적으로 거대한 모노레포(머큐리얼 기반)를 운용하고, Uber는 초기에 모노레포였다가 마이크로서비스 증가로 멀티레포로 전환했다가 다시 부분적으로 모노레포로 회귀하는 등 여러 변화가 있었습니다. 스타트업의 경우 초기엔 모노레포(Monorepo)로 개발 속도를 올리고, 서비스가 많아지면 영역별로 분리하는 유연한 접근을 취하기도 합니다.
권장 관행: 최적의 레포지토리 구조는 팀 규모, 프로젝트 복잡도, 배포 전략에 따라 달라집니다. 아래와 같은 판단 기준을 활용해볼 수 있습니다:
- 팀 규모와 협업 형태: 참여 인원이 적고 한 팀에서 모든 부분을 담당하면 모노레포가 유리합니다. 여러 팀이 각기 독립적으로 움직이는 큰 조직이라면 멀티레포로 팀 경계를 분리하는 편이 효율적입니다.
- 코드 공유와 의존성: 프로젝트 간 공통 모듈이 많고 기능 상호 의존도가 높다면 모노레포로 관리하는 것이 중복을 막고 일괄 변경에 용이합니다. 반대로 구성요소 간 결합도가 낮고 독립성이 크다면 레포 분리를 고려할 수 있습니다. 이때도 변경 사항이 다른 서비스에 영향주는지 잘 파악해야 합니다.
- 배포 및 릴리스 주기: 모든 구성요소를 한꺼번에 배포하거나 단일 제품처럼 버전 관리한다면 모노레포가 적합합니다. 각 서비스별로 별도 출시 주기가 있고 개별적으로 배포돼도 무방한 구조라면 멀티레포가 어울릴 수 있습니다. 다만 서비스 간 API 변경처럼 동시 배포가 필요한 경우가 잦다면 모노레포 쪽이 리스크 관리에 유리합니다.
결국 프로젝트의 목적과 운영 방식에 맞춰 선택하는 것이 중요합니다. 현재 사용자의 상황(혼자 개발하는 라이프 어시스턴트 프로젝트)에 비추어 보면, 모노레포(Monorepo)로 유지하여 개발 편의성과 일관성을 얻는 쪽이 실용적일 것으로 보입니다. 이후 프로젝트가 확장되어 여러 사람이 참여하거나 모듈별로 완전히 분리된 발전을 하게 되면, 그때 멀티레포로 전환을 검토해도 늦지 않을 것입니다. 자신만의 작업 흐름에서 어떤 구조가 생산성을 높여주는지 꾸준히 점검하며 유연하게 대응하는 것이 최선의 접근입니다.