시작하기 전에
이런 분들이 읽으시면 좋을 것 같아요.
- 각기 다른 기술과 레거시 코드로 이루어진 여러가지 프로젝트를 동시에 유지보수하고 있는 개발자
- 모노레포에 대해 궁금한 개발자
- 모노레포를 도입하고 싶지만 어떻게 시작해야할지 모르는 개발자
프론트엔드 불모지에 들어서다
저는 2024년 8월 말, 보안과 해킹을 전문으로 하는 스타트업에서 웹 개발팀을 꾸린다는 소식에 지원 공고를 썼고, 몇 차례 채용 프로세스를 거쳐 첫 번째 정식 FE 개발자로 임명되었습니다.
지금까지 이렇다 할 웹 개발팀 없이 사업을 굴려 왔던 개발 조직에서 첫 번째 프론트엔드 엔지니어로 임명되었다는 것은 앞으로 펼쳐질 수많은 레거시 코드와 들어보지도 못한 기술들을 마주하게 되리라는 것을 의미했습니다.
- 프로젝트마다 다른 노드 환경
- 프로젝트마다 다른 기술 스택과 제각각인 프레임워크/라이브러리 버전
- 코드 정적 검사 및 테스팅 부재
- 존재하지 않는 코드 컨벤션
- 프로젝트마다 다른 스타일 방식
- deprecated된 빌드 도구와 빌드 방법의 차이
- 상태가 매우 심각한 UI/UX
타노스의 핑거스냅, 신창섭의 정상화가 필요했습니다.

하지만 당시 열정이 충만한 신입 개발자였던 저는 어려운 조건에서도 수많은 레포지토리와 버전 브랜치를 쉼 없이 넘나들고, 천차만별인 기술 스택을 초월하여 하루하루 고객사들의 이슈에 대응하고, 성능과 UI/UX를 개선했습니다.
하지만 얼마 지나지 않아 이러한 방식으로는 업무 효율성이 점점 떨어져 결국 같은 일에 더욱 많은 시간과 노력을 들여야 한다는 사실을 깨닫습니다.
기술 부채의 엄청난 무게로 새로운 기술을 적용하긴 힘들어지고, 낡아 버린 환경과 라이브러리의 아주 특별한 케이스를 위해 스택 오버플로를 뒤지고.. 더욱 트릭키한 방식의 개발을 하게 됩니다. 이는 결과적으로 프로젝트의 유지보수 용이성을 저하하고 잠재적으로 회사의 성장과 개발자의 성장 모두를 막는 요소가 됩니다.
무언가 변화가 필요했습니다.
어느 퍼즐부터 맞춰야할까
1. UI 컴포넌트 스타일 방식
우선 당장 사업에 큰 영향을 끼치지 않으면서, 코드 가독성을 심하게 훼손시키는 것이 무엇인지 파악해보았을 때, 가장 먼저 제 눈에 띈 것은 UI 컴포넌트였습니다.
분명 사용 방법과 UI는 매우 유사했지만, 그 구현 방식은 프로젝트마다 전부 달랐고, Emotion, TailwindCSS, ChakraUI 등의 다양한 스타일링 방식을 사용 중이었습니다.
🔗 같지만 다릅니다. 같지만 다릅니다.
이들을 모두 하나의 스타일링 방식으로 통합하여, Storybook을 통해 컴포넌트의 사용법을 명시하고, 테스팅한 뒤 해당 코드들을 모든 프로젝트에서 공유해 사용했습니다.
결과적으로 공통 컴포넌트를 만들 때 더 이상 여러 가지 스타일링 방식을 사용하지 않아도 되었으며, 사내 디자이너는 Storybook을 통해 당장 활용이 가능한 UI 컴포넌트들을 확인할 수 있어 이를 통해 더 빠르게 작업을 진행할 수 있었습니다.
분명히 기존에 비해 개선된 것은 맞지만, Storybook 프로젝트의 코드를 모든 프로젝트에서 공유하는 것이 아닌 각각의 프로젝트에서 별도로 관리하고 있어 Storybook 레포의 UI 변경 사항을 일일이 옮겨와야 했고, 혹여나 각각의 프로젝트에서 요구 사항이 조금씩 달라 조금씩 UI 컴포넌트를 수정할 경우 이를 모두 추적하기가 쉽지 않았습니다.
이를 해결하기 위해 npm 라이브러리로 만들어 변경사항이 생길 때마다 빌드 및 배포하여 모든 프로젝트에서 공유하는 방법을 생각해보았지만, 사내에서 홀로 여러 프로젝트를 넘나들며 동시에 유지보수하는 로컬 개발 환경에서는 작업 속도와 효율이 떨어져 더 나은 방법을 찾고자 했습니다.
2. Node 환경과 라이브러리 버전
유지보수를 맡게된 프로젝트들은 모두 다양한 시기에 각기 다른 개발자에 의해 개발되었고, 각각 다른 버전의 Node, React, TypeScript를 사용하고 있었습니다.
또 마침 새로 런칭 준비 중이었던 인도네시아 신사업은 아예 새롭게 진행할 프로젝트였기 때문에 LTS 노드 환경에서, 최신 버전 라이브러리들을 사용하기로 했습니다.
그 결과, Node 12, 16, 18, 20 등 시대를 뛰어넘는 다양한 노드 환경으로, 이슈 해결을 위해 프로젝트를 넘나들 때마다 NVM으로 노드 버전을 바꿔줘야 하는 번거로움이 생기고야 말았습니다.
🔗 흔한 NVM 스위칭 흔한 NVM 스위칭
Project | Node | React | Style | State Management |
---|---|---|---|---|
서비스 A | 12.22.12 | 17 | Emotion | Redux + RTKQuery |
서비스 B | 16.16.0 | 17 | ChakraUI | Redux + RTKQuery |
서비스 C | 18.20.0 | 18 | ChakraUI | Zustand + ReactQuery |
신규 서비스 | 20.17.0 | 18 | TailwindCSS | Zustand + ReactQuery |
프로젝트마다 Node 12부터 20까지 서로 다른 버전을 사용하다 보니, 새로운 라이브러리 도입이 어려웠고, 때로는 CommonJS와 ES Modules 호환성 문제로 빌드가 깨지는 등 예상치 못한 이슈들이 발생했습니다.
마찬가지로 React도 17과 18 버전을 혼용하다 보니 동일한 코드가 프로젝트마다 다르게 동작하는 때도 있었습니다. (예를 들어 React 17에서는 이벤트 핸들러 내부의 여러 setState
가 자동으로 배치 처리되지만, Promise
나 setTimeout
내부에서는 개별적으로 처리되어 불필요한 리렌더링이 발생했습니다. 반면 React 18에서는 이러한 비동기 업데이트도 자동으로 배치 처리되어 성능 차이가 발생한 적이 있습니다.)
즉 프로젝트에는 React를 비롯해 TypeScript, Axios, Redux, RTK-Query, React-Router, React-Query 등 수많은 라이브러리의 다양한 버전을 사용하고 있었고, 이는 해당 프로젝트의 노드 환경에 종속적이었기 때문에 무엇하나 먼저 업그레이드하기가 쉽지 않았습니다.
3. 컨벤션, 린팅
개발 환경, 다양한 기술 스택의 다양한 버전, 스타일 방식 다양성에 한 술 더 떠, 컨벤션과 린팅도 프로젝트마다 다르게 적용되어, 프로젝트를 넘나들며 저장을 누를 때마다 늘 새로운 코드 스타일이 절 반겼습니다.
이토록 복잡하게 얽히고 꼬여 무거워진 기술부채를 해결하기 위해, 과감한 변화가 필요했습니다.
상황 정리
지금까지 각각의 프로젝트는 모두 각 레포지토리에서 독립적으로 관리되어 환경, 라이브러리 버전, 컨벤션, 스타일 방식 등 다양한 요소들이 프로젝트마다 다르게 적용되어 있었습니다.
따라서 시간을 들여 하나의 프로젝트를 LTS 노드와 최신 라이브러리 버전으로 과감히 교체한다고 해도, 다른 프로젝트에서 같은 작업을 반복해야 합니다.
모든 프로젝트에서 안정된 노드 환경과, 라이브러리 버전 업그레이드가 필요했고, 프로젝트마다 통일된 라이브러리 버전과 컨벤션을 사용하는 것이 적은 인원으로 유지 보수하는 데 쉬울 수밖에 없습니다.
그렇게 회사의 미래를 위해, 나의 미래를 위해, 모노레포라는 비장의 무기를 꺼내게 됩니다.
모노레포란?
모노레포(Monorepo)는 여러 개의 프로젝트를 하나의 레포지토리 내에서 관리하는 소프트웨어 개발 전략입니다. (Wikipedia)
모노레포를 도입할 경우 기존 멀티레포 방식과 비교했을 때 다음과 같은 장점이 있습니다.
- 외부 패키지 매니저 없이 프로젝트 간 공통 코드(UI 컴포넌트, 유틸함수 등)를 공유할 수 있다.
- 프로젝트 간 공통 라이브러리나 의존성 패키지의 버전을 중앙에서 관리할 수 있다.
- 프로젝트 간 컨벤션을 간단하게 통일할 수 있다.
- 프로젝트 간 빌드 및 배포를 한 번에 진행할 수 있다.
- 전체 프로젝트에 쉽게 접근 가능하며 프로젝트 간 작업 이동이 간편하다.
하지만 단점도 몇 가지 존재합니다.
- 태깅을 통한 프로젝트별 버전 관리 방식을 포기해야 한다.
- 엄격한 접근 권한 관리가 필요할 경우 추가적인 관리 방법이 필요하다.
checkout
시 모든 프로젝트를 동시에 체크아웃해야 하므로 더 많은 저장 공간이 필요하다.
이건 마치.. 하늘에서 내려온 동아줄과 같았습니다. 단점에 비해 취할 수 있는 장점이 너무나도 많았고, 정말 딱 원했던 것들이었습니다. 도입을 마다할 이유가 없었습니다.
곧바로 개발팀장님께 상황을 설명드려 모노레포 도입을 제안했고, 승인을 받아 모노레포 도입을 시작했습니다.
한 번도 경험해본 적 없는 새로운 도전이었지만, 상상 속 아주아주 깔끔하고 찬란한 프로젝트 구조를 바라보며 한 걸음씩 나아가기 시작합니다.
🔗 상상 속, 그리고 미래의 모노레포 다이어그램 상상 속, 그리고 미래의 모노레포 다이어그램
그럼, 모노레포 도입 여행기 시작합니다.