[NestJs] Workspace MonoRepo(모노레포) 에 대한 설명

NestJS로 프로젝트를 시작하면 Standard Mode와 MonoRepo Mode가 존재합니다. 개별 애플리케이션을 개발하거나 빠르게 소규모 프로젝트를 개발 및 배포를 한다면 Standard Mode를 선택합니다. 그래야 복잡한 빌드를 하지 않고 최적화 된 프로젝트를 배포할 수 있기 때문이죠.

하지만 대부분의 애플리케이션은 개발을 하면서 점점 커지는 경향이 있습니다. 그러다보니 하나의 프로젝트에 많은 기능이 들어가면서 배포가 오래걸리고, 기능을 고칠 때도 어려움을 겪을 때가 있습니다. 그래서 소프트웨어 아키텍처에서 유행했던 마이크로서비스 패턴이 나왔었습니다.

마이크로서비스 패턴도 장단점이 명확했습니다. 다양한 기능을 여러 개의 프로젝트로 쪼개서 관리하면서 기존에 있던 의존성을 많이 줄였지만, 관리에 들어가는 리소스가 증가함에 따라 개발 피로도가 올라가게 됩니다. 그래서 기존 모놀리식 아키텍처와 마이크로서비스 아키텍처의 중간이라 보여지는 모노레포 아키텍처가 나오게 됩니다.

모노레포 소개

모노레포는 다양한 프로젝트를 하나의 레포지토리에서 관리하는 아키텍처 입니다. 사용처는 하나의 서비스에서 다양한 기능을 분리해서 개발할 때 활용하게 됩니다. 즉, 하나의 폴더 안에서 모든 기능을 개발하기에는 기능이 다양하고, 그렇다고 레포지토리를 새롭게 만들어서 서로 통신하며, 개발했을 때 비용이 커진다면 모노레포를 선택하는 것이죠.

아래와 같은 멀티 레포지토리에서 겪은 문제 상황을 해결할 수 있습니다.

  1. 프로젝트마다 서로 다른 컨벤션 → 모노레포에서는 하나의 컨벤션으로 개발하기 수월
  2. 새로운 서비스(프로젝트)를 구축하기 위한 비용 증가 → 모노레포 안에서 기존 코드 사용 가능
  3. 중복된 코드와, 프로젝트 관리에 대한 비효율 → 결국 하나의 레포지토리 안에서 개발되기 때문에 상대적으로 중복 코드 및 프로젝트 관리 유용

위와 같은 문제를 해결하기 때문에 모노레포를 도입할 때, 체크해보면 좋을 것 같습니다.

모노레포 아키텍처 장단점

모노레포 장점

  • 각 기능을 모듈로 분리함으로써 캡슐화를 이룰 수 있습니다.
  • 기능이 잘 분리되어 있어 대규모 프로젝트에서 수많은 코드를 봐야할 수고를 줄입니다.
  • 소프트웨어 확장이 쉽습니다.
  • 테스트가 쉬워지고, 모듈의 대체성을 높일 수 있습니다.
  • 버전 관리가 쉽습니다.
  • 외부 의존 관리가 쉬워집니다.
  • 변경 사항을 쉽게 반영할 수 있습니다.
  • 팀 간 협업이 자유로워 집니다.

모노레포 단점

  • 개발 및 실행에 필요한 환경을 구성하는데 투자가 필요합니다.
  • 외부 모듈 의존 관리를 잘해야 합니다.
  • 코드 오너십이 분산된다. 하나의 레포에 다양한 기능이 들어가기 때문입니다.
  • 대규모 리팩토링이 쉬워지는 것이 단점이 될 수 있습니다.

NestJS에서 모노레포

NestJS에서는 MonoRepo mode를 따로 제공하고 있습니다. 이 모드는 코드 아티팩트를 경량 MonoRepo의 일부로 처리해서 개발자 팀 및 다중 프로젝트 환경에서 활용하기 좋게 합니다. 빌드 프로세스의 일부를 자동화하여, 모듈식 구성 요소를 쉽게 생성 및 구성하고, 코드 재사용을 높여줍니다. 앞서 봤었던 장점들을 전부 가져가면서 통합 테스트를 쉽게 만들고 eslint 규칙과 같은 코드 컨벤션, 기타 구성 정책을 하나의 프로젝트에서 쉽게 설정할 수 있도록 지원합니다.

NestJS에서 MonoRepo Mode는 파일에 표시되는 작업 공간 개념으로 사용되고 nest-cli.json을 사용해서 모노레포 구성 요소 간의 관계를 조정합니다. NestJS는 언제든지 standard mode로 쉽게 전환할 수 있기 때문에 언제든지 mode를 변경해서 대처가 가능합니다.

모노레포 모드 활성 방법

기본적으로 nest cli로 생성한 프로젝트는 standard mode로 만들어집니다. 보통 NestJS 프로젝트를 생성한다면 아래와 같은 명령어로 생성하게 됩니다.

nest new my-project
MonoRepo 생성


여기서 사용한 Javascript Package Manager는 yarn 입니다. npm과 pnpm, yarn 이렇게 3개 중 하나를 선택할 수 있습니다. 원하시는 패키지 매니저로 설치하면 되겠습니다. 이 때 생성되는 기본 구조는 우리가 흔히 알고 있는 구조입니다.

MonoRepo 폴더 구성


위와 같이 생성되고 이제는 monorepo로 변환해야 합니다.

cd project
nest generate app my-app

위와 같이 명령어를 치면 아래와 같이 프로젝트가 변경됩니다.

MonoRepo에서 앱추가 이미지


Untitled 3


이렇게 MonoRepo 구성을 완성할 수 있습니다. 여기서 알 수 있는 것은 nest cli 명령어에서 generate app를 통해 MonoRepo 안에 서브 앱을 추가할 수 있다는 것을 알 수 있습니다. 이러한 설정값은 nest-cli.json 안에 있습니다. 아래는 생성된 직후의 nest-cli.json 내용입니다.

Untitled 4


위와 같이 MonoRepo 설정값을 확인 할 수 있습니다. nest-cli 명령어를 통해 프로젝트를 추가할 수 있으며, 설정 값도 자동으로 채워줍니다. 그렇기 때문에 직접 폴더를 추가하는 방법보다는 nest-cli 명령어를 활용하는 것이 좋습니다.

아래는 명령어 입니다.

nest generate app <app-name> // app 생성
nest generate library <lib-name> // library 생성

모노레포를 사용할 때 앱을 새로 추가하는 일은 별로 없습니다. 대신 library는 추가할 일이 많이 있습니다. 여러 앱에서 사용할 때 library를 추가하면 되고, 라이브러리에는 공용 기능을 전부 옮겨주면 좋습니다.

라이브러리 생성 조건

보통 중복된 기능을 사용할 때는 라이브러리를 생성해서 넣어주는 것이 좋습니다. 그렇다면 어떤 기능이 중복된 기능이라 판단될까요? 필자가 생각하는 조건은 간단합니다.

두 개의 앱 이상에서 사용되는 기능

당연한 소리라고 생각할 수 있지만 이미 하나에 앱에 기능을 만든 개발자분들이라면 이 작업이 얼마나 귀찮고 위험한 일인지 생각할 수 있습니다. 특히, 이미 서비스되고 있는 기능을 옮기는 작업은 어떤 개발자라도 부담이 있는데요. 그럼에도 불구하고 라이브러리를 생성할 때는 두 개의 앱이 생성되고 공통으로 사용된다고 판단 될 때 옮기는 것이 가장 위험이 적습니다.

역으로 하나의 앱에서만 사용된다면 굳이 라이브러리로 따로 빼서 만들 필요가 없습니다. 라이브러리가 너무 방대해지면 관리가 어려워지기 때문이죠. 하나에 앱에서 만드는 것이 훨씬 쉽고, 생산성이 좋기 때문에 처음 생각할 때 하나에 앱에서만 사용된다면 라이브러리에 생성하지 않아도 좋습니다.

생성 시 아래와 같이 생성됩니다.

Untitled 5
[NestJs] Workspace MonoRepo(모노레포) 에 대한 설명 10

폴더 구조도 아래와 같이 변경되었습니다.

Untitled 6
[NestJs] Workspace MonoRepo(모노레포) 에 대한 설명 11

인증과 같은 경우 다른 앱에서 함께 사용되는 경우가 많습니다. 이러한 유틸리티 기능은 libs 안에 넣어서 여러 프로젝트에서 활용하면 좋습니다. 모노레포의 가장 큰 장점은 앱별로 따로 서버를 올릴 수 있다는 장점이 있습니다. 그렇기 때문에 저 또한 많이 활용하고 있는 NestJS에서 제공하는 Mode입니다.

공식 홈페이지 문서를 보면 다양한 상태 값을 보여주면서 설명을 해줍니다. nest-cli를 활용하면 기본 세팅을 해주며, 추가적인 사항은 홈페이지 문서의 속성 값을 보면서 custom을 진행하면 되겠습니다.

Untitled 7
[NestJs] Workspace MonoRepo(모노레포) 에 대한 설명 12

위 코드는 nest-cli.json 코드입니다. 각 lib 폴더 별로 하나씩 추가가 되는 것을 알 수 있습니다. type은 library로 들어가며 root는 폴더 위치를 알려줍니다. library가 아닌 경우 앞서 다룬 코드처럼 application type이 들어가게 됩니다.

마무리

이번 시간에는 NestJs에서 제공하는 모노레포 모드에 대해 알아봤습니다.

서비스가 커지고 다양한 앱을 만들 때, 보통 마이크로서비스를 사용하곤 합니다. 하지만 관리 포인트가 너무 많이 늘어나고, 대규모 서비스가 아닌 이상 마이크로서비스는 다루기가 쉽지 않습니다. 작은 도메인을 다루는 팀에서는 공통 코드가 많이 생성될 때 MonoRepo Mode를 통해 프로젝트를 구현하는 것은 상대적으로 적은 리소스가 투입됩니다. 또한, App 별로 다양하게 서버를 올릴 수 있다는 장점도 있습니다.

모든 방법론은 장단점이 있기 때문에 상황에 맞게 활용하면 좋겠습니다.

도움이 되시길 바랍니다.

참고 자료

https://docs.nestjs.com/cli/monorepo

Leave a Comment