도메인 모델과 경계

처음 도메인 모델을 만들 때 빠지기 쉬운 함정이 도메인을 완벽하게 표현하는 단일 모델을 만드는 시도를 하는 것이다. 그런데 앞장에서 말한 것처럼 한 도메인은 다시 여러 하위 도메인으로 구분되기 때문에 한 개의 모델로 여러 하위 도메인을 모두 표현하려고 시도하게 되면 모든 하위 도메인에 맞지 않는 모델을 만들게 된다.

예를 들어, 상품이라는 모델은 카탈로그에서의 상품, 재고 관리에서의 상품, 주문에서의 상품, 배송에서의 상품은 이름만 같지 실제로 의미하는 것이 다르다. 카탈로그에서의 상품은 상품 이미지, 상품명, 상품 가격, 옵션 목록, 상세 설명과 같은 상품 정보가 위주라면, 재고 관리에서의 상품은 실존하는 개별 객체를 추적하기 위한 목적으로 상품을 사용한다. 즉, 카탈로그에서 물리적으로 한 개인 상품이 재고 관리에서는 여러 개 존재할 수도 있다.

논리적으로 같은 존재처럼 보이지만 하위 도메인에 따라 다른 용어를 사용하는 경우도 있다. 카탈로그 도메인에서 상품이 검색 도메인에서는 문서로 불리기도 한다. 비슷하게 시스템을 사용하는 사람을 회원 도메인에서는 회원이라 부르지만, 주문 도메인에서는 주문자라고 부르고, 배송 도메인에서는 보내는 사람이라 부르기도 한다.

이렇게 하위 도메인마다 같은 용어라도 의미가 다르고 같은 대상이라도 지칭하는 용어가 다를 수 있기 때문에 한 개의 모델로 모든 하위 도메인을 표현하려는 시도는 올바른 방법이 아니면 표현할 수도 없다.

하위 도메인마다 사용하는 용어가 다르기 때문에 올바른 도메인 모델을 개발하려면 하위 도메인마다 모델을 만들어야 한다. 각 모델은 명시적으로 구분되는 경계를 가져서 섞이지 않도록 해야 한다. 여러 하위 도메인의 모델이 섞이기 시작하면 모델의 의미가 약해질 뿐만 아니라 여러 도메인의 모델이 서로 얽혀 있기 때문에 각 하위 도메인별로 다르게 발전하는 요구사항을 모델에 반영하기 어려워진다.

모델은 특정한 컨텍스트(문맥)하에서 완전한 의미를 갖는다. 같은 제품이라도 카탈로그 컨텍스트와 재고 컨텍스트에서 의미가 서로 다르다. 이렇게 구분되는 경계를 갖는 컨텍스트를 DDD에서는 BOUNDED CONTEXT라고 부른다.

BOUNDED CONTEXT

BOUNDED CONTEXT는 모델의 경계를 결정하며 한 개의 BOUNDED CONTEXT는 논리적으로 한 개의 모델을 갖는다. BOUNDED CONTEXT 용어를 기준으로 구분한다. 카탈로그 컨텍스트와 재고 컨텍스트는 서로 다른 용어를 사용하므로 이 용어를 기준으로 컨텍스트를 분리할 수 있다. 또한, BOUNDED CONTEXT는 실제로 사용자에게 기능을 제공하는 물리적 시스템으로 도메인 모델은 이 BOUNDED CONTEXT안에서 도메인을 구현한다.

이상적으로 하위 도메인과 BOUNDED CONTEXT가 일대일 관계를 가지면 좋겠지만 현실은 그렇지 않을 때가 많다. BOUNDED CONTEXT가 기업의 팀 조직 구조에따라 결정되기도 한다. 예를 들어, 주문 하위 도메인이라도 주문을 처리하는 팀과 복잡한 결제 금액 계산 로직을 구현하는 팀이 따로 있다고 해보자. 이 경우 주문 하위 도메인에 주문 BOUNDED CONTEXT와 결제 금액 계산 BOUNDED CONTEXT가 존재하게 된다. 아직 용어를 명확하게 하지 못해 두 하위 도메인을 한 BOUNDED CONTEXT에서 구현하기도 한다. 카탈로그와 재고 관리가 아직 명확하게 구분되지 않을 경우 두 하위 도메인을 한 BOUNDED CONTEXT에서 구현하기도 한다.

조직 구조에 따라 BOUNDED CONTEXT가 결정된다

조직 구조에 따라 BOUNDED CONTEXT가 결정된다

규모가 작은 기업은 전체 시스템을 한 개 팀에서 구현할 때도 있다. 즉 여러 하위 도메인을 한 개의 BOUNDED CONTEXT에서 구현한다.

여러 하위 도메인을 하나의 BOUNDED CONTEXT에서 개발할 때 주의할 점은 하위 도메인의 모델이 뒤섞이지 않도록 하는 것이다. 한 개의 이클립스 프로젝트에 각 하위 도메인의 모델이 위치하면 아무래도 전체 하위 도메인을 위한 단일 모델을 만들고 싶은 유혹에 빠지기 쉽다. 이런 유혹에 걸려들면 결과적으로 도메인 모델이 개별 하위 도메인을 제대로 반영하지 못해서 하위 도메인별 기능 확장이 어렵게 되고 이는 서비스의 경쟁력을 떨어뜨리는 원인이 된다. 따라서, 비록 한 개의 BOUNDED CONTEXT에서 여러 하위 도메인을 포함하더라도 하위 도메인마다 구분되는 패키지를 갖도록 구현해야 하위 도메인을 위한 모델이 서로 뒤섞이지 않아서 하위 도메인마다 BOUNDED CONTEXT를 갖는 효과를 낼 수 있다.

물리적인 BOUNDED CONTEXT가 한 개이더라도 내부적으로 패키지를 활용해서 논리적으로 BOUNDED CONTEXT를 만든다

물리적인 BOUNDED CONTEXT가 한 개이더라도 내부적으로 패키지를 활용해서 논리적으로 BOUNDED CONTEXT를 만든다

BOUNDED CONTEXT는 도메인 모델을 구분하는 경계가 되기 때문에 BOUNDED CONTEXT는 구현하는 하위 도메인에 알맞은 모델을 포함한다. 같은 사용자라 하더라도 주문 BOUNDED CONTEXT와 회원 BOUNDED CONTEXT가 갖는 모델이 달라진다. 또한, 같은 상품이더라도 카탈로그 BOUNDED CONTEXT의 Product와 재고 BOUNDED CONTEXT의 Product는 각 컨텍스트에 맞는 모델을 갖는다. 따라서 회원의 Member는 애그리거트 루트이지만 주문의 Orderer는 밸류가 되고 카탈로그의 Product는 상품이 속할 Caregory와 연관을 갖지만 재고의 Product는 카탈로그의 Category와 연관을 맺지 않는다.

BOUNDED CONTEXT의 구현

BOUNDED CONTEXT가 도메인 모델만 포함하는 것은 아니다. BOUNDED CONTEXT는 도메인 모델뿐만 아니라 도메인 기능을 사용자에게 제공하는 데 필요한 표현 영역, 응용 서비스, 인프라 영역 등을 모두 포함한다. 도메인 모델의 데이터 구조가 바뀌면 DB 테이블 스키마도 함께 변경해야 하므로 해당 테이블도 BOUNDED CONTEXT에 포함된다.

BOUNDED CONTEXT는 도메인 기능을 제공하는 데 필요한 요소를 모두 포함한다

BOUNDED CONTEXT는 도메인 기능을 제공하는 데 필요한 요소를 모두 포함한다

표현 영역은 인간 사용자를 위해 HTML 페이지를 생성할 수도 있고 다른 BOUNDED CONTEXT를 위해 REST API를 제공할 수도 있다.

모든 BOUNDED CONTEXT를 반드시 도메인 주도로 개발할 필요는 없다. 상품의 리뷰는 복잡한 도메인 로직을 갖지 않기 때문에 CRUD 방식으로 구현해도 된다. 즉, DAO와 데이터 중심의 밸류 객체를 이용해서 리뷰 기능을 구현해도 기능을 유지보수하는 데 큰 문제되지 않는다.