굳이 멀티모듈이 필요할까?
[예약 시스템] 굳이 멀티모듈이 필요한가?
개인적으로 느낀 결론부터 말하자면 변경할 확률이 적거나 크지 않으면 멀티모듈이 필요없다. 단일 모듈로도 충분하다.
처음 예약 시스템을 설계할 때는 ‘이전 회사에서 멀티 모듈로 구성했으니까 똑같이 한 번 해볼까?’라는 단순한 생각으로 설계했었다. 심플하게 하나의 멀티 모듈 안에 모든 MSA 서비스들을 모아두었다. 그리고 common, config, services들로 구분해 놓았다.
그런데 계속 진행하다 보니 의문과 문제점들이 발생했다.
문제/의문
- common의 비대화
- 각각 다른 config 내용
- MSA의 모든 서비스를 하나의 멀티모듈로 구성할꺼면 MSA 의미가 사라지지 않나?
- 만약 bach 애플리케이션을 만들면 각 서비스별로 따로 만들어야 하나?
- 공통 batch 모듈로 만들어야 하나?
이러한 문제와 의문들로 인해 내가 얼마나 무지성으로 멀티 모듈을 구성했는지에 깊게 깨달아버렸다. 1인 개발이고 소규모 프로젝트라면, 각 서비스를 나눠 놓고 서비스 내부도 멀티모듈을 할 필요도 없을 것이다. 하지만 이것 또한 경험이라는 생각으로 멀티 모듈의 장단점을 느껴보고자 억지로 넣어봤다.
MSA의 장점은 각 서비스를 작은 단위로 나눈다는 것이다. 그 이유는 빠른 확장성과 서비스간의 낮은 의존도가 있기 때문이다. 위와 같이 서비스들이 공통된 common을 바라보면 결국 서비스간의 의존도가 생기게 될 것이 뻔했다.
또 여러 서비스를 모아 놓음으로써 빌드 속도도 올라갔다. 빠른 확장성에도 방해된다.
그래서 각 서비스를 하나의 멀티모듈로 분리해 버렸다.
이제 각 서비스들은 독립적으로 관리하고 빌드/배포가 가능해졌다.
또 다른 문제?
그런데 각 서비스의 내부는 어떻게 나눠야 할까?? 모듈을 분리하기 위한 이상적인 구조를 모르기 때문에 쉽게 감이 잡히지 않았다.
해결책으로 두 가지 회사의 방법을 사용했다. 모든 서비스에 우아한 형제들, 인프콘:네이버 이 두 방법을 직접 넣어봤다. 이 두 내용에서 말하는 멀티 모듈을 구성하는 핵심은 common 모듈의 최소화와 역할과 책임이다.
common 모듈을 의존하는 모듈이 많아진다면 어떻게 될까? 중복 코드를 가지게 되어 유지보수와 확장성에 어려움을 가지게 된다. 결국엔 하나의 코드 변경이 다른 모듈들에 영향을 미치게 된다. 그렇게 점점 커지는 모듈로 인해 빌드와 배포 시간이 증가해지고 테스트 범위도 넓어지게 된다.
그래서 두 방법은 common 모듈을 완전 최소화 하고 순수 Java Class만 정의하거나 아예 공통 모듈을 사용하지 않는다. 즉, 각 모듈의 어느 정도 공통 코드를 허용시킨다.
적용해보기
우아한 형제들
우아한 형제들 링크의 구조는 크게 다섯 가지 계층으로 나뉜다.
- 독립 모듈 계층 : 이름 그대로 시스템과 전혀 상관없는 독립적인 모듈을 의미한다. 해당 서비스에 국한되지 않고 다양한 서비스에 연동이 가능한 모듈을 의미한다.
- 도메인 모듈 계층 : 시스템 중심 도메인을 다루는 모듈이다. 하나의 모듈은 하나의 인프라스트럭처에 대한 책임만 가지고 오로지 도메인에만 집중한다.
- 내부 모듈 계층 : 시스템의 내부 모듈들을 서포트해주는 위치이다. 예를 들어, 외부와 연동하기 위한 모듈이 될 수 있다.
- 공통 모듈 계층 : 가능하면 사용하지 않고 의존성을 최소화한다.
- 어플리케이션 모듈 계층 실행이 가능한 애플리케이션 모듈이다. 다른 모듈들을 조립해서 하나의 서비스 비즈니스를 완성한다.
이러한 구조에 맞게 member와 performance service를 구성했다. 실제 적용해보면서 느낀 장점은 이전에는 흐릿했던 경계가 뚜렷해 졌다는 것이다.
계층별로 책임에 맞게 분리되어 관리되기 때문에 접근이 쉬웠고 문제 위치를 특정하기도 쉬웠다. 하지만 그 만큼 관리해야할 범위도 늘어났다. 각 모듈들의 변경이 빈번하다면 유용할지 모르나. 개인 프로젝트에서는 너무 과했다.
네이버
다음은 네이버의 방법을 적용해봤다. reservation, discovery, gateway를 이 방식으로 구성했다. cloud 관련 내용은 cloud-system으로 분리했다.
사실 이렇게 구성해보며 이 구성의 장점을 한 번에 깨닫기 어려웠다. 단순 30분의 영상으로는 이점을 파악하기 어려웠는데. 강연에서 계속 강조하던 역할과 책임 그리고 이미지 상단에 있는 BOUNDED CONTEXT를 통해 어떤 의미인지 어렴풋이 깨달아갔다.
data에는 바운디드 컨택스트로 각 도메인 영역들을 분류해 놓는다. 그리고 boot 영역에는 실행되는 api와 같은 모듈을 넣어두고 필요한 도메인을 조합에 맞춰 사용한다.
마치 요리사의 만들 요리(boot-api)와 요리 재료(data)를 각 책임에 맞게 분류한 것과 같다. 지금 이 프로젝트에는 필요없지만 정말 큰 프로젝트라면 유용할거라는 생각이 든다.
느낀점
두 가지 방법을 모두 적용하면서 느낀점은 ‘정답은 없구나’ 라는 것을 느꼈다. 각각 방법의 차이일 뿐이었고 내가 만들 서비스에 맞게 구조를 만들면 되는거였다. 그리고 두 방법 모두 유용했다.
또 이 프로젝트처럼 변경 가능성이 적고 관리자가 한명이라면 굳이 멀티모듈을 구성할 필요가 없을 것이다. 두 방법은 변화하는 프로젝트의 영향을 최소화하는 방법들일 것이다. 다시금 설계의 중요성을 깨닫게 되는 시간이었다.