[Architecture] 멀티모듈(Multi-Module)이란?
소프트웨어 개발이 복잡해지며, 하나의 거대한 코드베이스로 애플리케이션을 관리하는 모놀리식(monolithic) 구조는 초반 개발 속도는 빠르지만 규모가 커지며 배포, 유지보수, 협업 과정에서 병목 현상이 발생해 개발 생산성이 저하됩니다. 또한, 코드의 변경이 전체 시스템에 영향을 미치며 유지보수 비용이 증가하는 등의 여러 한계를 가지고 있습니다.
이러한 문제를 해결하기 위한 방법 중 하나가 멀티모듈(Multi-Module) 구조입니다. 멀티모듈은 하나의 프로젝트를 여러 개의 모듈로 나누어, 각 모듈이 독립적으로 개발되고 유지보수될 수 있도록 합니다.
이번 포스팅에서는 멀티모듈이란 무엇인지, 개념과 모듈을 나누는 기준, 멀티모듈 설계 시 주의할 점에 대해 알아보도록 하겠습니다.
멀티모듈(Multi-Module)이란?
Java에서 `모듈이란 패키지의 한 단계 위의 집합체이며, 독립적으로 배포될 수 있는 코드의 단위`를 의미합니다.
멀티 모듈 프로젝트는 상호 연결된 여러 개의 모듈로 구성된 프로젝트를 의미하는데, 멀티 모듈 프로젝트의 각 모듈은 전체 서비스의 구성요소로서 동작합니다.
`각 모듈을 독립적으로 빌드`할 수 있는 것이 특징이며, `한 프로젝트에서 특정 모듈은 Java Spring 스택을 사용할 때, 다른 모듈은 Kotlin Spring 스택 또는 SpringBoot를 특정 모듈에서는 2.x.x 버전을, 다른 모듈은 3.x.x 버전을 사용`할 수도 있습니다.
멀티모듈을 사용하는 이유에 대해 알아보기 전 모놀리식, 싱글모듈 멀티 프로젝트, 멀티모듈 싱글 프로젝트에 대해 먼저 알아보도록 하겠습니다.
모놀리식(Monolithic)
`모든 코드가 하나의 프로젝트에 집중되어 있는 구조`입니다. 모든 기능이 하나의 코드베이스 안에 존재하며, 전체 프로젝트를 빌드하고 배포합니다.
하나의 서비스 또는 애플리케이션이 하나의 거대한 아키텍처를 가질 때, 모놀리식(Monolithic)하다고 합니다.
모놀리식의 장점
- `단순한 구조`: 프로젝트의 초기 개발이 간단하고 빠르게 진행할 수 있습니다. 하나의 코드베이스에서 모든 기능을 처리할 수 있어 설정이 복잡하지 않습니다.
- `직관적`: 작은 프로젝트에서는 구조가 직관적이고 이해하기 쉬워 관리가 수월합니다.
- `통합된 배포`: 여러 기능이 하나의 애플리케이션 내에 포함되어 있어, 배포가 간편하며 서비스가 연동되는 방식에 대한 고민이 적습니다.
모놀리식의 단점
- `확장성 문제`: 프로젝트가 커지면 하나의 코드베이스가 너무 방대해져 관리가 어려워집니다. 한 명의 개발자가 여러 기능을 동시에 수정해야 할 경우 코드충돌이나 불필요한 복잡성이 생길 수 있습니다.
- `변경의 리스크`: 애플리케이션의 작은 수정도 전체 시스템에 영향을 미칠 수 있습니다. 한 모듈의 버그 수정이 다른 모듈에 영향을 미치는 문제가 발생할 수 있습니다.
- `배포 리스크`: 프로젝트가 커질수록, 전체 애플리케이션을 재배포해야 하므로 배포가 느려지고, 오류 발생 시 시스템 전체에 영향을 줄 수 있습니다.
`작은 프로젝트나 빠르게 개발이 필요한 경우` 모놀리식 아키텍처가 적합할 수 있습니다.
싱글모듈 멀티 프로젝트
싱글모듈 멀티 프로젝트 구조는 `여러 개의 독립적인 프로젝트가 존재하지만, 각 프로젝트는 공통의 모듈에 의존하는 구조`입니다.
즉, 각 프로젝트는 하나의 독립적인 모듈을 가지며, 이들이 공통된 모듈을 참조하며 기능을 확장해 나갑니다. 보통 각 프로젝트는 별도의 애플리케이션이 되며, 공통 모듈을 통해 서로 연결됩니다.
싱글모듈 멀티 프로젝트의 장점
- `모듈화`: 각 프로젝트가 독립적으로 개발되고 배포되므로, 각 프로젝트의 관리가 용이합니다. 팀별로 프로젝트를 나누어 작업할 수 있기 때문에 협업이 수월합니다.
- `유연성`: 한 프로젝트에서 발생한 문제를 다른 프로젝트로 전파하지 않아, 변경사항이 다른 프로젝트에 미치는 영향을 최소화할 수 있습니다.
싱글모듈 멀티 프로젝트의 단점
- `프로젝트 간 의존성 관리`: 여러 프로젝트 간에 공통 모듈을 의존하고 있기 때문에, 공통 모듈의 변경이 여러 프로젝트에 영향을 미칠 수 있습니다.
- `배포 복잡성`: 각 프로젝트가 독립적으로 배포되기 때문에, 전체 시스템의 버전 관리와 배포 프로세스가 복잡해질 수 있습니다. 예를 들어, 하나의 프로젝트 버전이 업그레이드되면, 관련된 다른 프로젝트들도 함께 업데이트해야 할 수 있습니다.
- `중복 코드에 대한 휴먼 에러`: 같은 도메인에 대해 별도의 여러 프로젝트로 구성되어 있어 중복되는 코드가 많이 발생하게 됩니다. 예를 들어, Member 도메인 모델에 대한 코드를 Member API, Member Admin, Member Batch 프로젝트에 모두 작성해 주어야 하며, Service, Repository도 마찬가지입니다. 이런 구조에서 요구사항이 변경된다면, 3개의 프로젝트에 작성된 공통 코드를 모두 변경해주어야 합니다.
멀티모듈 싱글 프로젝트
멀티모듈 싱글 프로젝트는 `하나의 프로젝트 내에 여러 개의 모듈이 존재하는 구조`입니다. 각 모듈은 독립적인 기능을 담당하며, 모든 모듈이 하나의 프로젝트로 묶여 빌드되고 배포됩니다. 각 모듈은 서로 연결되지만, 하나의 빌드 시스템을 통해 전체 프로젝트가 관리됩니다.
멀티모듈 싱글 프로젝트의 장점
- `모듈화 된 코드`: 각 모듈이 독립적으로 개발되기 때문에, 기능이 분리되어 가독성이 높고 관리가 용이합니다. 각 모듈은 독립적으로 수정, 확장할 수 있습니다.
- `통합된 관리`: 프로젝트가 하나로 관리되어, 빌드나 배포 설정이 일관성 있게 처리됩니다. 모든 모듈이 하나의 프로젝트로 관리되므로 전체 시스템을 한 번에 관리할 수 있습니다.
- `유지보수 용이`: 각 모듈이 독립적으로 개발되어, 유지보수가 쉽고, 기능을 독립적으로 테스트할 수 있습니다.
멀티모듈 싱글 프로젝트의 단점
- `복잡한 의존성 관리`: 모듈 간 의존성 관계가 복잡질 수 있습니다. 예를 들어, 하나의 모듈이 다른 모듈에 의존할 경우, 의존성 충돌이 발생할 수 있습니다.
- `초기 설정 복잡성`: 여러 모듈을 관리하기 위한 초기 설정이 복잡할 수 있습니다. 각 모듈 간의 의존성을 정확히 설정하고, 빌드 시스템을 설정하는 데 시간이 필요할 수 있습니다.
멀티모듈(Multi-Module)을 사용하는 이유
`단일모듈 구조`는 소프트웨어 개발 초기에 간단하고 빠른 개발을 가능하게 하지만, 규모가 커지거나 프로젝트가 복잡해질수록 여러 한계가 드러나게 됩니다. 규모가 커지는 프로젝트에서 발생하는 복잡성과 문제들을 해결하기 위한 방법 중 하나가 `멀티모듈(Multi-Module) 구조`입니다.
1. 독립적인 빌드 및 배포
멀티모듈 구조에서는 각 모듈이 독립적으로 빌드되고 배포될 수 있습니다. 이는 `특정 모듈에만 변경이 있을 때 다른 모듈에 영향을 주지 않아, 전체 시스템을 재빌드하거나 재배포할 필요 없이 효율적인 작업`이 가능합니다.
예를 들어, 하나의 모듈을 업데이트한다고 해서 다른 모듈을 함께 업데이트할 필요가 없기 때문에, 개발자들이 각자의 모듈에 집중할 수 있는 환경이 구성됩니다.
2. 유지보수와 효율성
`모듈이 독립적이고 작은 단위로 나뉘어 있기 때문에 각 모듈에 대한 변경이나 버그 수정이 다른 부분에 영향을 미치지 않습니다.` 이로 인해 코드의 유지보수가 용이하고, 개발자가 수정할 때 전체 시스템의 안정성에 영향을 줄 가능성이 낮아집니다.
그리고 모듈 별로 테스트가 가능하기 때문에 개별적인 단위 테스트 및 디버깅 또한 용이합니다. 문제 발생 시 전체 시스템을 확인하는 대신, 문제가 발생한 모듈만 집중적으로 확인할 수 있어 더 빠르고 정확한 문제 해결이 가능합니다.
3. 기술 스택의 유연성
멀티모듈 구조에서는 `각 모듈이 독립적으로 관리되기 때문에 서로 다른 기술 스택을 사용`할 수 있습니다.
예를 들어, 하나의 모듈은 Java Spring, 또 다른 모듈은 Kotlin Spring, 다른 모듈은 SpringBoot 2.x.x 버전, 혹은 SpringBoot 3.x.x 버전을 사용할 수 있습니다. 이는 다양한 기술 스택을 필요로 하는 복잡한 프로젝트에서 큰 장점이 됩니다.
4. 협업의 용이성
`대규모 프로젝트에서 여러 팀이 동시에 작업할 때, 멀티모듈 구조는 각 팀이 독립적으로 작업할 수 있는 환경을 제공`합니다.
한 팀은 A 모듈을, 다른 팀은 B 모듈을 작업하고, 각 팀은 서로의 코드에 최소한으로 영향을 주며 작업할 수 있습니다. 이로 인해 협업이 원활해지고, 각 팀은 자신이 담당하는 모듈이 집중할 수 있습니다.
5. 스케일링
프로젝트의 규모가 커지면, 여러 팀과 다양한 서비스가 연계되어 작업하게 됩니다. 멀티모듈 구조는 이러한 복잡한 시스템을 관리하는데 유리하며, 각 모듈을 독립적으로 확장하거나, 업데이트할 수 있는 유연성을 제공합니다.
모듈을 나누는 기준
멀티모듈 구조를 효과적으로 활용하려면, 어떤 기준으로 모듈을 나눌지가 중요합니다. 단순히 기능별로 나누는 것이 아니라, 유지보수성, 확장성, 성능 등을 고려한 설계가 필요합니다.
잘못된 모듈 분리는 오히려 의존성 문제를 유발하거나 개발 속도를 저하시킬 수 있기 때문에, 적절한 기준을 설정하는 것이 필수적입니다.
모듈을 나누는 기준에 대해서는 정답이 존재하지 않으며, 프로젝트의 성격과 요구사항에 맞게 유연하게 적용해야 합니다.
DDD(Domain-Driven Design)의 Bounded Context와 멀티모듈(Multi-Module)의 관계
DDD(Domain-Driven Design)
DDD(Domain-Driven Design)는 복잡한 비즈니스 도메인을 효과적으로 관리하기 위한 소프트웨어 설계입니다.
- `Bounded Context`: 도메인을 논리적으로 구분하는 단위
- `Aggregate`: 일관성을 유지해야 하는 객체들의 군집
- `Entity / Value Object`: 상태를 가지는 객체(Entity)와 상태가 변하지 않는 객체(Value 객체)
- `Domain Service`: Entity나 Value 객체가 가지기 어려운 비즈니스 로직을 담당하는 서비스
DDD와 멀티모듈을 함께 사용하면, 도메인 경계를 물리적으로 분리하여 관리할 수 있습니다.
- DDD에서 각 `Bounded Context`는 특정 비즈니스 영역을 책임집니다.
- 이를 독립적인 모듈로 분리하면, 관심사의 분리를 유지하면서 결합도를 낮출 수 있습니다.
DDD(Domain-Driven Design)에서 `Bounded Context(경계 컨텍스트)`는 특정한 도메인의 개념과 규칙이 일관되게 적용되는 경계를 의미합니다.
즉, 하나의 Bounded Context는 독립적인 모델을 가지며, 그 내부에서는 명확한 의미를 공유하지만, 다른 Bounded Context와는 다른 의미를 가질 수도 있습니다.
예를 들어, `상품`이라는 개념이 `주문 관리` 컨텍스트에서는 `구매 가능한 아이템`을 의미할 수 있지만, `재고 관리` 컨텍스트에서는 `창고에 있는 물품`으로 다르게 해석될 수 있습니다.
실전! 멀티 모듈 프로젝트 구조와 설계 | 인프콘 2022, 네이버 김대성님
특정한 컨텍스트 문맥하에서 완전한 의미를 갖는 경계의 기준을 잘 나누는 것이 멀티모듈 프로젝트 구조를 설계하는데 중요한 역할을 합니다.
- BOOT(Server) 그룹
- batch, admin, api
- Server 애플리케이션으로 코드의 변화가 가장 자주 일어남
- DATA(Domain) 그룹
- meta, user, chart
- Server모듈과 밀접한 관계
- 연동모듈(Infra) 그룹
- and, vod, photo, billing
- 유관 부서 및 업체 연동을 위한 그룹 모듈
- 구현 후 변화는 적지만 버전업이 된다면 코드에 큰 변화를 가져옴
- Cloud(System) 그룹
- Config, Gateway, Discovery
- AWS, GCP, AZURE
- 서버 관리를 위한 그룹 모듈 (컨테이너 환경, 트래픽 관리)
- 변화 적음
이 네 개의 멀티 그룹은 각자 고유의 성격과 특성 사이클을 가지고 있으며, 그 기준으로 경계를 나누고 프로젝트를 구성할 수 있습니다.
모듈을 나누는 기준에 대해서만 간단하게 정리하였는데, 영상을 한 번씩 시청해 보시는 것을 추천드립니다.
멀티모듈(Multi-Module) 설계 시 주의점
멀티모듈 구조에서 `공통 모듈`을 사용하는 것은 매우 중요합니다. 하지만 중복을 제거하고자 이 공통 모듈에 모든 핵심 기능이나 공통 코드를 계속해서 추가하게 되면, 모듈이 점점 커지고 의존성 또한 복잡해집니다. 이는 `의존성 덩어리`로 변질되어, 여러 모듈들이 공통 모듈에 의존하게 되어 버립니다.
공통 모듈에 대부분의 핵심 또는 공통 코드들을 없애고자 공통 모듈에 계속해서 추가하게 된다면 어느새 공통 모듈은 걷잡을 수 없이 커져있고 이는 `의존성 덩어리`가 되어버립니다. 그 결과 코드가 꼬리에 꼬리를 물고 결국 하나의 코드만 수정해도 전체가 영향받는 현상이 일어날 수 있습니다.
마무리
멀티모듈 아키텍처는 대규모 프로젝트에서 관리의 용이성, 협업의 효율성, 그리고 기술 스택의 유연성을 제공합니다. 각 모듈이 독립적으로 개발되고 배포될 수 있어, 팀 간의 충돌을 최소화하며, 프로젝트 확장이 용이합니다.
그러나 멀티모듈 설계에는 의존성 관리와 모듈 간의 관계 설정 등 등 몇 가지 고려해야 할 사항이 있습니다. 잘못된 모듈 분리나 공통 모듈의 과도한 의존은 시스템의 복잡도를 증가시키고, 유지보수 비용이 높아질 수 있습니다.
멀티모듈 아키텍처 도입 시 `도메인 중심 설계(DDD)`를 활용해 각 모듈을 논리적으로 구분하고, 명확한 의존성 관리를 통해 모듈 간 결합도를 최소화하는 것이 중요합니다.
참고
[우아한테크세미나] 190829 우아한멀티모듈 by 우아한형제들 권용근님
https://techblog.woowahan.com/2637
멀티모듈 설계 이야기 with Spring, Gradle | 우아한형제들 기술블로그
멀티 모듈 설계 이야기 안녕하세요. 배달의민족 프론트 서버를 개발하고 있는 권용근입니다. 멀티 모듈의 개념을 처음알게 되었을 때부터 현재까지 겪었던 문제점들과 그것을 어떻게 해결해나
techblog.woowahan.com
우리는 이렇게 모듈을 나눴어요: 멀티 모듈을 설계하는 또 다른 관점 | 인프콘 2023, 네이버 클라우드 조민규님
https://mangkyu.tistory.com/304
[Server] 멀티 모듈을 설계하는 관점과 고려사항 with Spring & Gradle
이번에는 유지보수하기 좋은 멀티 모듈 구조를 설계하는 기준과 그에 따른 고려사항에 대해 알아보도록 하겠습니다. 아래의 내용은 절대적인 기준이 아니며, 상황에 따라 달라질 수 있음을 참
mangkyu.tistory.com