모노레포 도입기 - 1. 어쩌다 모노레포를 도입하게 되었을까

Dahee Kim·2022년 5월 24일
2

모노레포 도입기

목록 보기
1/3

모노레포 도입기

새 프로젝트를 진행하며 모노레포 구조를 도입하게 되어 그 과정을 포스팅으로 남겨보고자 합니다.

갑자기 웬 모노레포?

사용해보고 싶은 기술들을 이용하여 만들고 싶은 것들을 자유롭게 만들고, 하나의 URL에 배포해서 유용하게 활용하고 싶었다. 또 만든 도구들을 npm에 배포하여 다른 사람이 쉽게 사용할 수 있도록 만들고도 싶었다. 나는 이 프로젝트를 playground 프로젝트라고 명명하고, 어떻게 진행할지 구상하고 있었다.

큰 그림이 어느정도 그려져서 개발 환경을 세팅하려던 찰나 든 생각이 있었다.
'prettier, eslint등은 공통된 룰을 가져가고, 이외에는 개발할 각각의 도구마다 목적에 걸맞는 개발환경을 세팅해주고 싶은데 레포를 분리하자니 불편한 점이 있을 것 같네?'

일단 코드 린팅은 공통된 룰을 사용할건데, 레포마다 각각 설정해주어야 하니 똑같은 작업이 반복된다.

또 레포를 분리하면 아래와 같은 문제가 발생할 수 있다.

내가 개발한 도구들을 모두 모아서 보여주는 서비스A의 레포가 있다고 치자.
개발한 도구들은 각각의 목적에 걸맞는 개발환경을 가지고 있어야 하므로, 마찬가지로 별개의 레포를 가지고 있어야 할 것이다.
이 도구들은 npm에 publish하여 필요한 경우 install하여 사용할 것이다.

이제 내가 개발한 패키지A와 B가 있다고 가정해보자.

서비스A에서 이것들을 가져와 사용하는 단순한 구조에서는 아마도 큰 문제가 발생하지는 않을 것이다.

하지만 만약 패키지B에서 패키지A를 사용한다면? 새로운 서비스B를 만들었는데 여기에서도 패키지A와 B를 사용한다면?

위와 같이 프로젝트간 의존성이 존재하는 경우 그것들을 관리하는 데 큰 오버헤드가 발생할 수 있다.

예를 들어 패키지A에 새로운 기능을 추가하는 경우, 다음과 같은 작업이 반복될 수 있다.

패키지A 기능 추가 > 패키지A npm 배포 > 패키지B에서 패키지A 버전업 > 패키지B npm 배포 > 서비스A에서 패키지A, B 버전 업 > 서비스B에서 패키지 A, B 버전업

이미 프로젝트 사이에 의존성을 어느정도 고려하고 있었고, 위와 같은 문제를 방지하기 위해 모노레포 구조를 사용하는 것이 적합하다고 판단했다.

아래는 모노레포의 구조를 그림으로 나타낸 것이다.

이외에도 모노레포가 해결하는 멀티레포의 문제는 다음과 같다.

  • 더 쉬운 프로젝트 생성
    멀티레포에서 공유 패키지를 만들 때 다음과 같은 과정을 거친다.
    저장소 생성 > 커미터 추가 > 개발환경 구축 > CI/CD 구축 > 빌드 > 패키지 저장소에 publish
    모노레포에서는 저장소 생성 및 커미터 추가 과정이 필요 없고, 개발 환경, CI/CD, 빌드, 게시 등의 과정에 기존 DevOps를 이용하므로 새 프로젝트 생성에 대한 오버헤드가 없다.
  • 더 쉬운 의존성 관리
    의존성 패키지가 같은 저장소에 있으므로 버전이 지정된 패키지를 npm registry와 같은 곳에 publish할 필요가 없다.
  • 단일화된 관리 포인트
    개발환경 및 DevOps에 대한 업데이트를 한 번에 반영할 수 있다.
  • 일관된 개발자 경험 제공
    애플리케이션을 일관되게 구축하고 테스트할 수 있다. 개발자는 다른 팀의 애플리케이션에 자신 있게 기여하고 변경 사항이 안전한지 확인할 수 있다.
  • 프로젝트들에 걸친 원자적 커밋
    커밋할 때마다 모든 것이 함께 작동한다. 변경 사항의 영향을 받는 조직에서 쉽게 변화를 확인할 수 있다.
  • 서로 의존하는 저장소들의 리팩터링 비용 감소
    모노레포는 대규모 변경을 훨씬 더 간단하게 만든다. 100개의 라이브러리로 만든 10개의 앱을 리팩터링하고 변경을 커밋하기 전에 모두 작동하는지 확인할 수 있다.
    출처 : 모던 프론트엔드 프로젝트 구성 기법 - 모노레포 개념 편

도구 선택하기

모노레포 구조로 진행하는 것을 결정하고, 어떤 도구를 사용하는 것이 적합할지 고민이 필요했고, 그전에 먼저 의존성 관리도구를 선택하기로 했다.

지난 프로젝트에서 알 수 없는 이유로 node_modules가 비정상적으로 설치되어 오류가 발생하고, 해결을 위해 폴더를 밀었다가 다시 설치하기를 반복해야했는데 이런 문제를 피할 수 있다면 좋을 것 같았고, 패키지를 가볍고 빠르게 다루고 싶어 이것들을 최우선순위로 두었다.

이러한 문제를 고려해 선택한 것은 yarn berry였다. 다음과 같은 장점이 마음에 들었다.
1. PnP(Plug’n’Play) 전략으로 npm, yarn v1의 비효율적 의존성 검색문제, 환경에 따라 달라지는 동작 문제, 비효율적인 설치 문제, 유령 의존성문제를 해결한 것
2. ZipFS(Zip Filesystem)를 이용하여 빠른설치/삭제,쉬운 변경여부 감지, 가벼운 용량의 장점을 제공하는 것
3. Zero-Install(의존성을 버전관리에 포함)이 가능한 것

게다가 모노레포의 도구로 yarn berry에 내장된 workspace를 사용할 수 있다. 생각보다 공식문서도 잘 정리되어 있고, 러닝커브를 낮출 수 있어 선택하지 않을 이유가 없었다.

그래서 내가 선택한 도구는 yarn berry workspace가 되었다.

구조 잡기

아래는 우아한형제들의 모노레포 구조이다. 내가 계획한 구성과 거의 동일해서 참고하기 위해 가져왔다.

(출처 : 우아한형제들 기술블로그 )

마무리

다음편에서는 모노레포를 직접 구성한 과정에 대해 이야기합니다.

참고자료

모던 프론트엔드 프로젝트 구성 기법 - 모노레포 개념 편
https://d2.naver.com/helloworld/0923884

모던 프론트엔드 프로젝트 구성 기법 - 모노레포 도구 편
https://d2.naver.com/helloworld/7553804

Yarn berry workspace를 활용한 프론트엔드 모노레포 구축기
https://techblog.woowahan.com/7976/

node_modules로부터 우리를 구원해 줄 Yarn Berry
https://toss.tech/article/node-modules-and-yarn-berry

monorepo tools
https://monorepo.tools

Building a Monorepo with Yarn 2
https://blog.heroku.com/building-a-monorepo-with-yarn-2

profile
하루가 너무 짧아~

0개의 댓글