모노레포(Monorepo)와 저장소 방식의 진화

date
Jun 29, 2023
slug
monorepo
summary
저장소가 모노리식, 폴리레포 그리고 모노레포로 오기까지를 살펴보기
thumbnail
status
publish
notion image

모노리식 (monolithic)


모노리식 (monolithic)은 하위 프로젝트들을 하나의 큰 프로젝트로 관리하는 방식이다. 즉, 모듈화 없이 하나의 큰 프로젝트로 설계된 것
작은 서비스가 아닌 거대한 서비스 자체가 모듈화를 하지 않는다면 어떻게 될까? 관심사 분리가 일어나지 않고 리팩토링 및 설계에서 프로젝트 이해에 필요한 리소스가 상당할 것이다.

장점

서로 직접 의존하기 때문에 코드 재사용이 용이하다.빌드 / 배포가 구조가 단순하다.

단점

코드가 서로 직접 의존하기 때문에 관심사 분리가 되지 않는다.설계 / 리팩토링 / 배포 등의 작업에서 모듈화가 되지 않아 수정 범위, 단위가 커지므로 비효율이 발생한다.

폴리레포 (멀티레포)


모노리식 저장소의 단점을 극복하기 위해 공통 소스코드를 재사용할 수 있도록 모듈화한다. 모듈화된 공통 모듈이 새로운 프로젝트가 되고 독립적인 저장소에서 관리한다면 멀티 레포가 된다.
각각의 저장소마다 프로젝트 코드를 독립적으로 관리하기 때문에 자율성이 높다.
자율성이 높다는 건 해당 저장소를 관리하는 팀의 자율성 (team autonomy) 이 크다는 얘기, 해당 저장소는 팀마다 고유의 설정 및 의존성을 갖고 저장소를 구성되어 간다.

장점

프로젝트가 독립적이기 때문에 다른 프로젝트와 의존성을 가지지 않아, 자율성이 보장된다.독립적으로 분리되었기 때문에 프로젝트의 크기가 가볍다.

단점

고도화된 폴리레포를 구현하기 위해서는 라이브러리화 리소스가 추가로 든다.
예를 들어 Project A와 비슷한 구조의 Project B를 시작한다고 해보자. CI/CD / lint / test 등의 설정과 Project A에서 재사용하고 싶은 코드가 있을 경우에는 해당 코드를 라이브러리화 해야한다.
만약 라이브러리화된 패키지가 업데이트됐을 경우 해당 라이브러리를 의존하는 모든 프로젝트에서 의존성을 맞춰야한다.
서비스가 커지면서 프로젝트가 많아지면 유지보수 어려움이 있다.
결국 같은 이슈를 수정하기 위해 각각 프로젝트에 이슈 반영을 위한 커밋, PR이 필요하다.
제각각의 툴링(CI/CD / lint / test) 으로 일관성 없는 개발자 경험 (DX) 이 제공된다.프로젝트 생성 비용이 커진다.
저장소마다 지나친 자율성은 프로젝트를 고립시키게 만들고 고립은 협업을 방해할 수 있다.
notion image

폴리레포가 대부분의 애플리케이션에서 사용되어 왔던 이유?

💡 주관이 많이 들어간 부분입니다.
각각의 기능 개발을 맡은 팀이 저장소를 관리하는 형식이 많았기 때문에
notion image
어찌보면 기능조직이 하나의 프로젝트 관리를 하기 보단, 목적조직으로 나뉘어 참여하고 있는 기능조직 일부가 프로젝트 저장소를 관리하는 형식은 당연하다고 생각되어 왔을 것이다.
요즘 업계에서는 Spotify 조직도에 착안하여 챕터(기능조직), 스쿼드(목적조직) 으로 많이 운영하는 것 같다.
자율성에 의한 고립은 회사 내부의 프로젝트 규칙 (lint, 프로젝트 설정 문서화) 및 모듈 패키지 화를 통해 충분히 가능했기 때문에 여기서드는 한가지 의문이 있다. 폴리레포를 구성하고 있는 많은 회사에서 모든 개발자에게 동일한 개발자 경험(DX)를 제공하고 있을까? 가령 한 프로젝트에서 의존성이 추가될 경우 동일한 개발자 경험(DX)을 주기 위해 기존의 저장소 프로젝트들에 연관된 부분을 모두 수정해야한다. 예를 들어 디자인 시스템이 업데이트 될 경우 연관된 프론트엔드 프로젝트들의 패키지를 일괄적으로 업데이트해야 한다.기존의 잘 작동되고 있고 배포, 테스트 구조가 잡힌 프로젝트를 새로운 프로젝트 구조(모노레포)로 옮기는건 양날의 검. 🗡️ 어찌보면 리스크를 안고 프로젝트를 새로운 프로젝트 구조(모노레포)로 옮길 이유가 없다. 😅 이 부분이 실제 대규모 비즈니스 프로젝트를 운영하고 있는 입장에서는 가장 큰 이유가 될 것이다.

모노레포


mono + respository 하나의 저장소에서 여러 프로젝트를 저장해 관리하는 개발 전략이다.
단순하게 기존의 폴리레포로 관리하던 프로젝트를 전부 하나의 저장소에서 관리한다고 생각하면 된다.

장점

하나의 수정으로 여러 프로젝트에 반영, 대규모 리팩토링이 가능하다.브레이킹 체인지에 대한 빠른 감지를 통해 대규모 리팩토링이 가능하다. 대규모 리택토링은 소프트웨어 전체 구조를 지속 가능한 환경을 만들어 가는데 키포인트라고 생각.
유사한 기능 추상화가 가능, 공유 패키지화를 통해 중복 작업을 줄일 수 있다. lint, tsconfig, test, 배포 관련 yml등의 재사용을 위한 파일들을 최상위 디렉토리에서 관리하고 공유 패키지를 쉽게 다른 레포에서 접근이 가능해진다.
멀티 레포의 경우 공유 패키지화를 위해 NPM 패키지를 관리하고 버저닝에 신경써야 한다.
사람들이 모든 것을 보고 더 많이 저장소에 쉽게 참여하면서 모두 같이 개발한다는 느낌, 제품에 대한 소유권 발생도 가능하다. 내가 담당하는 프로젝트가 아니더라도 개선의 여지가 있다고 판단되면 자유롭게 수정 할수 있다. 이를 통해 자유롭게 코드에 기웃거릴 수 있고, 엔지니어들 간의 의견을 더 자주 교환 할수 있다.전체 레포(프로젝트들)에 대한 주인의식 생긴다.

단점

모노레포 아키텍쳐에 투자를 해야한다.
아무래도 단일 프로젝트만 관리하면 되는 폴리 레포와 달리 모노레포 환경에 대한 설정 및 배포 전략, 모듈화(패키지화)를 폴리 레포와 다르게 가져가야한다. 초기 아키텍쳐에 투자되는 리소스가 상당할 것이다.
대규모 리팩토링이 쉬워진다.
대규모 리팩토링이 가능하다는 것은 의존성이 쉽게 바뀔수 있다는 의미이다. 어떤 관점에서는 치명적인 단점으로 보일 수도 있다. 다른 프로젝트의 개발자가 공통 모듈을 수정하면 해당 모듈에 대한 의존성을 전부 확인해봐야한다.
각 패키지(서비스)별로 git 브랜치가 나눠지기 때문에 하나의 브랜치를 바라보며 공통의 코드를 계속해서 공유한다는 모노레포의 근본적인 개념이 사라질 수 있다.
이렇게 될 경우 폴리레포와 다를점이 없다. 이를 방지하기 위해 Trunk Based Development 전략을 도입하거나 브랜치 전략에 대한 논의를 해야한다.

애자일 (Aglie)

notion image
신규 프로젝트 생성시 초기 설정(CI/CD / lint / test에 드는 에너지를 줄일수록 더 좋은 유저 경험과 비지니스 모델에 깊이 고민 할수 있는 에너지가 생기게 된다. 이는 애자일한 스타트업 조직에 알맞는 구조라고 생각이 든다.
또한 다양한 프로젝트에 쉬운 접근을 통해 멀리보면 단일 진실의 원천(Single source of truth) 을 달성할 수 있다.

서로 다른 팀, 서로 다른 시스템, 하나의 진실

팀, 프로세스, 비즈니스를 알아갈수록 뭔가 부족하다고 느낄 때가 있습니다.온라인에서의 입지가 생각했던 것처럼 유기적이지 않거나, 오래전부터 업데이트가 안 된 파일로 작업을 하고 있을 수도 있죠. (중략)사람이든, 데이터든, 무언가가 분명하지 않을 때 단일 진실 공급원이 그 길을 환하게 비춰주는 역할을 하는 거죠. - '단일 진실 공급원 이란?' 아티클 일부
사실 이 글은 회사 내부에 모노레포 도입하면서 생각을 정리한 글이다. 현재 MVP(Minimum Viable Product) 를 통해 어느정도 가설을 검증했고 프로덕트를 고도화해 나가는 단계에 있다. 신규 프로젝트들을 빠르게 가져가고 대규모 리팩토링을 진행해야하는 상황이었는데, 모노레포라는 새로운 저장소 아키텍쳐가 확장성에 유연하고 내부 개발자의 DX 향상을 위해 적합하다라고 판단 및 결론이 생겼기 때문이다.
비록 모노레포를 도입하면서 새로운 Git 전략과 CI/CD 방식 및 아키텍쳐를 전체적으로 팀원들과 다시 빌딩해야겠지만, 프로덕트 기능 개발에만 몰두하는 것이 아닌 프로젝트 아키텍쳐에도 팀원들이 신경을 쓸 수 있는 계기가 될 것 같아서 꽤 흥미로운 여정이 될 것 같다는 생각이 든다. 🥳