[도메인 주도 설계] (6) 기본 구성 요소 3 – 모듈

도메인 주도 설계의 기본 구성 요소인 모듈(Module)은 비슷한 의미를 가진 개념들을 묶는 단위에요. 기술이 아닌 개념 기반으로 그룹화하고, 높은 응집도와 낮은 결합도로 복잡성을 효과적으로 관리하는 구체적 방법을 확인해 보세요.

'Domain-Driven DESIGN'이라는 컬러 타이포그래피 로고. 하늘색 배경에 '도메인 주도 설계 — (6) 기본 구성 요소 3 - 모듈'이라는 텍스트가 적혀 있다.

지난 편에서 도메인 서비스의 역할과 계층별 서비스 비교를 살펴봤어요. 이번 편에서는 제품이 성장할 때 도메인을 이해 가능하게 유지하는 모듈(Module)이 무엇인지, 좋은 모듈 설계의 원칙, 모듈 간 관계 패턴, 그리고 리팩토링 시점까지 알아볼게요.


제품이 성장하면, 잘 설계된 엔티티와 서비스 집합이라도 탐색하기 어려워질 수 있어요.

그 시점에서 질문은 더 이상 “이 로직이 맞는가?”가 아니에요.

이렇게 바뀌죠.

“이 로직이 어디에 속하는가?”

이것이 도메인 주도 설계에서 모듈(Module)의 역할이에요.


1. 모듈이란 무엇인가: 개념 기반 그룹화

모듈은 도메인이 성장해도 이해 가능하게 유지되도록 조직하는 방법이에요.

모듈을 폴더나 패키지로 생각하고 싶을 수 있어요. 코드에서 그렇게 나타나니까요. 하지만 그것들은 그냥 컨테이너예요. 모듈은 구문이 아니라 의미로 정의돼요.

모듈을 생각하는 유용한 방법은 제품의 도메인 이야기에서 하나의 챕터로 보는 거예요.

각 챕터는 특정 주제나 책임에 집중하고, 대체로 독립적으로 이해할 수 있고, 다른 챕터와 제한적이고 의도적인 방식으로 상호작용해요.

예를 들어, 채용 제품에서 지원서와 면접 일정 관련 개념은 자연스럽게 하나의 모듈을 형성하고, 후보자 평가와 피드백은 다른 모듈을 형성할 수 있어요.

각 모듈이 도메인 이야기의 일관된 부분을 말해주면, 독자가 관련 없는 관심사 사이를 끊임없이 오가지 않아도 되죠.

좋은 모듈이 하는 일은 “시스템의 이 부분은 어떤 종류의 문제를 해결하기 위해 존재하는가?” 질문에 대한 공유된 답을 제공하는 거예요.

모듈은 백화점의 층별 구성과 같아요. 1층은 화장품, 2층은 여성복, 3층은 남성복, 4층은 가전처럼요. 각 층이 하나의 일관된 주제를 갖고, 고객이 원하는 것을 찾으려면 해당 층만 가면 돼요. 모든 상품을 카테고리 없이 섞어놓으면, 원하는 물건을 찾기 위해 백화점 전체를 돌아다녀야 하겠죠.


2. 좋은 모듈 설계: 높은 응집도와 낮은 결합도

모듈에서는 세 가지 원칙이 가장 중요해요.

원칙 의미 PM이 왜 신경 써야 하는가
개념 기반 그룹화 모듈이 기술 계층이 아닌 도메인 개념을 중심으로 조직됨 팀이 코드 구조 대신 제품 언어로 추론할 수 있게 도움
높은 응집도(Cohesion) 모듈 내의 개념이 밀접하게 관련되고 함께 변경되는 경향 기능이나 변경의 영향을 예측하기 쉬워짐
낮은 결합도 (Coupling) 모듈이 제한적이고 의도적인 경계를 통해 상호작용 팀 간 조율과 의도치 않은 파급 효과를 줄여줌

1) 개념 기반 그룹화

코드를 ui/, services/, database/ 같은 기술적인 언어로 그룹화하는 건 기술적으로는 편리하지만, 제품의 진짜 구조를 숨겨요. 모듈이 일정 관리리포팅 같은 개념으로 이름 지어지면, 논의가 구현 세부 사항 대신 도메인 언어에 기반하게 되죠.

2) 높은 응집도

좋은 모듈 안의 개념들은 자연스럽게 같은 대화에 속해요. 제품 변경이 일관되게 같은 개념 집합에 영향을 미치면, 경계가 올바르다는 신호예요. 작은 변경이 관련 없는 영역에 흩어지면, 모듈 경계가 잘못되었을 가능성이 높죠.

3) 낮은 결합도

잘 설계된 모듈이라도 서로의 내부에 심하게 의존하면 작업이 어려워져요. 모듈 간의 명확하고 최소한의 연결이 변경을 지역적으로 유지하고, 지속적인 정렬의 필요성을 줄여요.

이 원칙들이 함께 작용하면, 모듈이 코드베이스만이 아니라 팀의 제품 추론 능력도 확장할 수 있어요.


3. 예시: 학습 플랫폼 모듈 (카탈로그, 등록, 진행, 결제)

대기업이 직원 교육에 사용하는 기업 학습 플랫폼을 상상해 보세요.

학습 플랫폼 모듈
─────────────────────────

┌────────────────────────┐
│      Catalog (모듈)     │
│────────────────────────│
│ courses                │
│ learningPaths          │
│ prerequisites          │
└────────────────────────┘

┌────────────────────────┐
│     Enrollment (모듈)   │
│────────────────────────│
│ enrollments            │
│ eligibilityRules       │
│ capacityLimits         │
└────────────────────────┘

┌────────────────────────┐
│      Progress (모듈)    │
│────────────────────────│
│ completionTracking     │
│ assessments            │
│ certifications         │
└────────────────────────┘

┌────────────────────────┐
│      Billing (모듈)     │
│────────────────────────│
│ plans                  │
│ invoices               │
│ usageLimits            │
└────────────────────────┘

각 모듈이 제품 이야기의 일관된 부분을 말해줘요.


4. 모듈 간 관계: 업스트림/다운스트림, 공유 커널, 부패 방지 계층

모듈은 독립적으로 존재하지 않아요. 모듈들은 하나의 시스템을 이루며, 관계의 방향을 지니고 있어요.

이런 모듈 패턴은 다음과 같은 이름을 가지고 있어요.

학습 플랫폼에서 이 관계는 이렇게 나타나요.

모듈 관계 (학습 플랫폼)
────────────────────────────────────────

┌────────────────────────┐
│      Catalog (모듈)     │
└──────────┬─────────────┘
           │ 사용 가능한 학습 콘텐츠 정의
           ▼
┌────────────────────────┐
│     Enrollment (모듈)   │
└──────────┬─────────────┘
           │ 학습 기록 생성
           ▼
┌────────────────────────┐
│      Progress (모듈)    │
└────────────────────────┘

┌────────────────────────┐
│      Billing (모듈)     │
└──────────┬─────────────┘
           │ 접근 & 한도 제약
           ▼
┌────────────────────────┐
│     Enrollment (모듈)   │
└────────────────────────┘

위의 예시처럼, 어떤 모듈은 규칙을 세우고, 어떤 모듈은 그 규칙에 적응한다는 거예요.

어떤 모듈이 규칙을 소유하고, 어떤 모듈이 그 규칙에 적응해야 하는가?

이 답이 불명확하면, 규칙이 제품 전체에 조용히 떠돌기 시작해요.


5. 모듈 리팩토링

모듈 구조는 영구적이지 않아요.

제품이 성장하면, 기능이 군집되는 방식이 종종 바뀌어요. 한때 명확했던 모듈이 천천히 정체성을 잃을 수 있어요. 책임이 쌓이고, 소유권이 모호해지고, 작아야 할 변경이 여러 영역에 걸치기 시작하죠.

이렇게 되면 제품 로드맵의 범위를 잡기가 어려워지고, 팀이 더 자주 충돌해요. 제품 개발 계획에서 추정치가 많지 않는 것처럼요. 이는 작업이 어려워서가 아니라 경계가 더 이상 제품이 다루고 있는 현실과 맞지 않기 때문이에요.

모듈을 리팩토링(Refactoring)하는 건 모델이 현실을 따라잡는 과정이에요.

이것은 과거 실수의 교정이 아니에요. 새로운 이해에 대한 반응이에요.

사무실 좌석 재배치와 같아요. 초기에는 마케팅팀과 영업팀이 한 공간에 있었는데, 팀이 커지면서 영업팀이 CS팀과 더 자주 협업하게 됐어요. 그러면 영업팀을 CS팀 옆으로 옮기는 게 자연스럽죠. 처음 배치가 틀렸던 게 아니라, 조직이 진화한 거예요.


다음 편에서는 일관성 경계를 정의하는 애그리게이트(Aggregate)가 무엇이고, 루트·경계·내부 구조는 어떻게 구성되며, 크기를 어떻게 결정하는지를 살펴볼게요.

도메인 주도 설계 시리즈