얼마전 회사 테크톡 시간에 모노레포에 대한 발표를 진행했습니다.
이 기술이 우리 회사의 상황과 가지고 있는 자원으로 적용 가능한가에 대한 고민을 해봤으며 그떄의 발표를 각색해서 작성하려고 합니다.
모노레포란 버전 관리 시스템에서 두 개 이상의 프로젝트 코드가 동일한 저장소에 저장되는 소프트웨어 개발 전략
우선 모노의 어원을 들여다보면 “모노(mono)는 "하나"를 의미하는 그리스어의 접두사이다.“, 즉 여러개의 레포지토리를 하나의 레포지토리로 운영하는것이다.
프론트엔드 레포지토리로 쉽게 예를들면 현재 여러개의 서비스가 있고 디자인시스템 레포지토리가 있는데 모노레포를 이용하면 디자인시스템을 install 하지 않고 직접 모듈을 전해받아 사용 가능하다.
// npm 배포한 라이브러리 install
import Button from '@design-system'; // 400kb
const index = () => {
return (
<div>
<Button></Button>
</div>
);
};
export default index;
// 모노레포
import Button from '@design-system';
const index = () => {
return (
<div>
<Button></Button>
</div>
);
};
export default index;
멀티레포는 현재 대부분의 애플리케이션을 개발하는 표준적인 방법이다. 업계는 팀의 자율성이라는 큰 이유 때문에 이 방식을 선호한다. 팀은 애플리케이션 개발의 라이프사이클을 스스로 결정하기를 원한다.
예를들어 프론트엔드 개발자 A는 혼자 B라는 서비스를 개발했고 독자적인 eslint 규칙, 아키텍쳐, 배포 파이프라인, 패키지를 가지고 있었다.
물론 이렇게 개발하면 독자적인 레포지토리에서 본인의 입맛에 맞게 프로젝트를 생성하고 유지보수가 가능하기에 유리할때도 있다.
예를들어 사내에 디자인 시스템이 도입됐다.
실제로 디자인시스템이 도입돼서 UI의 일관성과 작업효율이 늘어났다.
하지만 디자인시스템을 도입하니 문제가 생겼다. 이를 어떻게 관리하냐인데 예를들어 사내에 디자인시스템을 적용하여 서비스를 운영중인게 5개이다.
멀티레포환경에서 도입하기 위해 각각 install 해야하고 만약에 디자인쪽에서 요구사항이 생겨 특정 컴포넌트의 변경이 생긴다면 개발자는 현재 디자인시스템을 사용하고있는 레포지토리마다 모두 방문해서 디자인 시스템을 버젼 업 해주어야 하며 이는 현재 깃플로우 전략에 의해 3번의 Pull Request가 있어야하므로 3 * 현재있는 레포지토리수 만큼의 Pull Request를 날려서 Merge해야한다.
하지만 이는 휴먼에러를 일으킬 확률이 있으며 만약에 하나의 레포지토리를 까먹었다면 우리 서비스를 마주할 유저는 서로 다른 UI를 경험하게 될것이다.
디자인 시스템 뿐만 아니라 사용중인 서비스마다 라이브러리의 버젼 또한 모두 다르다.
이 외에도 프론트엔드에서는 비즈니스로직을 재사용하기 쉽게하기 위해 CustomHook을 사용하는데 하나를 개발하면 그 hook이 필요한 모든 레포지토리에 가서 해당 코드를 추가해야한다.
혹은 린트룰을 하나 바꾸고 모두 적용해야 한다면 이 또한 번거로울 것이다.
앞선 거의 모든 문제를 모노레포를 사용한다면 해결할 수 있다.
우선 하나의 거대한 레포지토리 안에 Workspace를 만들고 각각의 레포지토리를 넣어준다.
그리고 상위 레포지토리에서 서비스에 필요한 의존성을 설치해주고, 각각의 서비스에서 필요한 작업을 해준다. design-system에서는 각 서비스에 필요한 UI를 개발해주고 필요하다면 스토리북을 이용하여 Test를 해준다. 그리고 필요한 비즈니스 로직은 core에서 처리해준다.
이러면 각각의 서비스는 필요한 UI와 비즈니스로직을 각각의 패키지에서 주입받아 실제로 필요한 코드를 남길 수 있다.
이렇게 하면 패키지 관리도 수월할 뿐더러 관심사의 분리도 가능해져서 더욱 좋은 코드 생산이 가능하다.
이 외에도 모노레포를 사용하면 CI/CD 파이프라인을 상당히 단순화 시킬수 있다.
5번은 코드 리뷰 통합에서는 장점일 수 있으나 적절한 PR 컨벤션이 없다면 서비스들이 혼재돼 오히려 혼란을 초래할 수 있다.
CI 속도 저하 가능성 → 하나의 레포지토리의 크기가 매우 커지기 때문
형상 관리 경험 저하 → 하나의 레포지토리에서 Pull Request가 올라오기 때문에 만약 동시에 다른 서비스를 여러개 작업중인 상태라면 적절한 Pull Request Template이 존재하지 않는다면 혼선이 있을 수 있음
좋을것만 있을것 같은 모노레포 그럼 어떻게 개발해야하는지에 대해서 설명하겠다.
뭐든지 기술은 거저 주는것이 아니다.
모노레포를 통합 후에 각 서비스는 어떤식으로 배포해야할지 정해야하며 기존에 멀티레포로 돼있는 각 레포를 모노레포로 마이그레이션 하는 비용이 들고 이를 학습하기 위한 비용까지 들기에 결코 쉬운 작업이 아니다.
아래는 2021,2022년 패키지 매니저 사용률이다.
. Lerna가 1등에서 3등까지 내려왔고 터보레포가 무서운 기세로 점유율이 올라오고 있다. 필자도 터보레포로 공부했는데 사용하기 편리했고 Vercel에서 만들었다.
Apps폴더에서 필요한 서비스들을 두고 packages에서 필요한 UI나 비즈니스 로직을 처리한다. 자세한건 터보레포 공식홈페이지를 확인 바란다.
정말 많은 기업에서 모노레포를 도입해 서비스를 개발하고 있다.
이 외에도 많은 기업에서 모노레포를 도입했다.
우리회사에서는 선생님과 학생이 만나 화상수업을 진행하는 호두클래스라는 서비스가 있다.
이 서비스는 학생과 선생님이 만나 공통된 UI에서 각자 다른 권한을 가지고 서비스를 진행하며 선생님은 백오피스쪽에서 접속하고 학생은 회사 플랫폼쪽에서 접속을 하여 각각 필요한 api 통신을 처리한다.(ex: 수업 시작, 수업 종료, 슬랙 알림 등)
상당히 비슷한 UI 구조를 가지고 있고 권한에 따라 UI가 다른게 특징인데 그럼에도 중복되는 레이아웃이나 컴포넌트가 많이 있다.
만약 우리 서비스에서 모노레포를 도입할 수 있다면 적절한 관심사 분리와 함께 중복되는 UI로직을 제거할 수 있을거라고 생각했다.
첫번째 사진이 기존 아키텍쳐이고 두번째 사진이 모노레포를 도입하게 된다면 적용될 아키텍쳐이다.
그리고 회사가 성장하는만큼 다양한 신규 서비스들을 런칭할 예정인데 서비스가 많아지고 복잡할수록 모노레포가 가진 장점때문에 꼭 필요할거라 생각했다.
하지만 아직까지는 여러서비스에서 공통적으로 가지는 기능은 많지 않고 디자인시스템은 현재 NPM배포로 적용하고 있다. 그리고 모노레포같은 기술은 수단일뿐이기에 팀원들과의 충분한 협의를 거쳐 필요한 시점에 도입해야된다는 결론이 났다.
lerna 보다 turborepo가 엄청 좋더라고요