이번 글에서는 왜 Monorepo와 Docker를 선택했는지에 대해서 설명하려 한다.
이전 글에서 이번에 만들 앱에서 자원을 아끼는 것이 여러 목표 중 하나라고 설명했다.
이 목표를 위해 나는 우선 어떤 자원을 아껴야할지에 대해 고민했다.
그 중 첫번째로 떠오른 것이 공수의 절약이다.
참고로 필자는 중복되는 것을 정말 싫어한다.(정말정말정말...!)
때문에 함수를 제작할 때 두번만 겹쳐도 바로 모듈화시켜버리는데 이번에 개발하게 될 두개의 앱에서도 중복되는 행동을 최소화하고 싶었다.
예를 들면 아래와 같은 것이 있을 것이다.
즉, 불필요한 공수 작업이 중복되는 것을 피하고 싶었다.
이를 위해서는 효율적인 레포지토리 관리가 필요하다고 생각했고 여러 전략을 찾아보게되었다.
대중적인 레포 관리 방식
아마 대부분의 개발자들이 이 환경에서 개발 경험을 쌓았을 것이다.
모노리스 방식은 크게 공수가 들어갈 필요가 없다. 말 그대로 하나의 레포지토리에서 서버뿐만 아니라 앱 하나를 모두 통으로 관리하는 방식이기 때문이다.
이 방식의 장점은 구현이 쉽다는 점, 하나의 레포지토리에서 관리하기 때문에 관리의 자유도가 높다는 점이 있다.
하지만 이 관리의 자유도가 높다는 점 때문에 오히려 관리가 힘들어지는 케이스들도 있다.
또, 가장 큰 단점 중에 하나가 너무 무겁다.
모노리스 즉, 하나의 레포지토리에서 점점 커져나갈 앱을 모두 관리하다보니 굉장히 빨리 비효율적으로 무거워진다.
뿐만 아니라 패키지간의 의존도가 너무 높아져 나중에는 기술적인 도전을 하기 어려워지는 관리 방식 중의 하나라고 할 수 있겠다.
이렇게 적고 보니 모노리스를 비추천하는 것처럼 쓰인 것 같은데, 이러한 단점을 다 덮을 정도로 구현이 쉽다는 점이 큰 장점이기 때문에 처음 개발을 접하는 사람들에게는 아마 나도 이 방식을 추천할 것 같다.
이 방식은 사용해본적도 없고, 아마...? 사용해볼일도 없을 것 같아서 간단히 내용만 정리하려 한다.
멀티레포는 말 그대로 개발자들이 정한 모듈 단위로 레포지토리를 모두 분리해서 관리하는 방식이다.
이 방식이 나오게 된 계기는 앞서말한 모노리스 방식의 단점인 하나의 앱이 너무 무거워지고 의존성 관리가 힘들다는 점을 극복하기 위해 나오게 된 것으로 알고있다.
하지만 이 방식 역시도 당연히 단점은 존재한다, 하나의 앱 자체는 가볍고 의존성 관리도 모노리스에 비해 쉽지만, 관리포인트가 너무 늘어나게되어 모노리스의 큰 장점이었던 관리가 용이하다는 점을 완전 반대로 뒤집은 방식이다.
이 때문에 이 방식도 그리 대중적으로 사용되지는 않는 것으로 알고 있다.
이 방식이 사용되는 것은 알고 있지만, 실제로 하이브리드라는 단어로 쓰여지는지에 대해서는 잘 모르겠다.(😅)
사실 굳이 말하자면 멀티레포 방식이기 때문이다.
해당 관리 방식에 대해 짧게 설명하자면 멀티레포에 비해 덜 쪼갠(?) 레포 관리 방식이다.
예를 들어 멀티레포가 3개의 앱을 가지고 있고 모듈 단위로 사용하는 패키지용 레포지토리가 2개 있다면 총 5개의 레포지토리를 관리하는 것이지만, 하이브리드 방식은 앱은 하나로 패키지 단위로 관리하는 레포지토리를 2개 혹은 1개로 관리하며 큰 단위의 역할분리만 하는 것이다.
사실 상 멀티레포와 개념자체는 똑같지만 관리하는 측면에서 모두 쪼개버리는 멀티레포에 비해서는 관리가 용이하기 때문에 나름대로 분리를 해보았다.
이 방식도 나는 나름 좋아보여서 실제로 이번에 구축하려는 앱에 적용하려고 했던 방식이기도 하다.
하지만 본인 기준 굉장히 크게 느껴진 단점 때문에 포기했는데, 그것은 바로 버전관리이다.
해당 단점이 크게 다가왔던 순간은 겨우 버튼 하나 만들 때였다.
패키지용 레포지토리에서 버튼을 만들고 테스트하는 과정은 패키지용 레포지토리 안에서는 매우 쉽다.
의존성 관리만 잘 해놔도 크게 걱정할 요소가 없기 때문이다.
하지만 단점은 늘 예상치 못한 곳에서 온다.
버튼에 깜빡하고 border-radius
를 안넣고 0.0.1
버전을 게시했다고 치자, 그럼 정말 사소한 요소 하나 때문에 수정 작업 후 버전을 0.0.2
로 올려야된다.
뿐만 아니라 코어 앱 개발 중 만약에 필요한 컴포넌트가 있어서 만들려고 해도 바로 적용할 수 없다.
패키지용 레포에서 새로운 컴포넌트를 만들고 테스트하고 버전 업해서 게시하는 일련의 과정을 또 거쳐야된다.
물론 이 과정은 패키지로 관리하는 이상 어쩔 수 없는 요소이기는 하다.
하지만 공수의 절약을 원했던 나는 이 방식을 사용했을때 공수가 오히려 불어날 것이라는 생각을 갖게 되어 이 방식도 버리게 되었다.
드디어... 모노레포에 대해 설명할 시간이다.
모노레포는 정말 생각해내고 개발해주신 분들께 절을 올리고 싶다.
필자가 불편하게 느껴졌던 요소를 완벽하게 해소했다고 생각하기 때문이다.
모노레포의 개념만 간단히 설명하자면 하나의 레포에서 모든 앱을 관리하지만 의존성을 독립적으로 관리할 수 있고, 하나의 node_modules
를 공유하기 때문에 용량도 가볍다.:)
또한 위에서 설명한 하이브리드 방식(멀티레포)에서 크게 느꼈던 버전 관리에 대한 불편함도 전혀 없다.
늘, latest
최신 버전으로 커스텀 패키지를 관리할 수 있기 때문이다.
필자가 그려본 모노레포를 이해하기 위한 그림이다.
간략히 설명하자면 하나의 큰 node_modules
에는 모든 패키지들이 들어 있다.
다만 main app
, admin app
을 빌드할 때는 그림대로 각각 main app: p1, p2
, admin app: p3, p4
에 해당하는 패키지만 사용하기 때문에 불필요한 의존성 관리를 줄일 수 있다.
필자는 위에서 그린 모노레포 그림을 보며 docker
를 사용해야겠다는 생각을 했다.
아마도 생활코딩 강의 중 docker
강의를 들은 사람이라면 한번 쯤 본 이미지일 것이다.
위의 그림과 일치한다고 말은 하지 않겠다. 하지만 자원을 공유한다는 개념이 너무 비슷하지 않은가?
필자는 이 그림을 보며 아래 그림과 같이 앱을 구축해보고 싶어졌다.
말 그대로 repository의 자원을 활용하는 구조가 그대로 인스턴스에 1:1 매칭 형식으로 구현하려 한 것이다.
사실 뭐 그리 대단한거냐고 할 수도 있는데, 필자는 해당 방식을 생각해내고 개발에 성공했을 때 굉장히 뿌듯했다.
다음 글 부터는 이제 정말로 어떻게 구현했는지에 대한 내용을 담으려 한다.
이 글은 필자의 노력을 스스로 잊지 않기 위해 기록하는 글이다.