도메인 모델과 바운디드 컨텍스트

706__·2023년 12월 21일

DDD

목록 보기
9/11

도메인 모델과 경계

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

논리적으로 같은 존재처럼 보이지만 하위 도메인에 따라 다른 용어를 사용하는 경우가 있다,
카탈로그 도메인에서의 상품이 검색 도메인에서는 문서라고 불리는 것처럼 말이다.

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

하위 도메인마다 사용하는 용어가 다르기 때문에 올바른 도메인 모델을 개발하려면 하위 도메인마다 모델을 만들어야 한다. 각 모델은 명시적으로 구분되는 경계를 가져서 섞이지 않도록 해야 한다.

여러 하위 도메인의 모델이 섞이기 시작하면 모델의 의미가 약해질 뿐만 아니라 각 하위 도메인별로 다르게 발전하는 요구사항을 모델에 반영하기 어려워진다.

모델은 특정한 컨텍스트 하에서 완전한 의미를 갖는다.
같은 제품이라도 카탈로그 컨텍스트와 재고 컨텍스트에서 의미가 서로 다르다.
이렇게 구분되는 경계를 갖는 컨텍스트를 도메인 주도 설계에서 Bounded Context 라고 부른다.


바운디드 컨텍스트

바운디드 컨텍스트는 모델의 경계를 결정한다.
한 개의 바운디드 컨텍스트는 논리적으로 한 개의 모델을 갖는다.

바운디드 컨텍스트는 용어를 기준으로 구분한다.
또한 실제로 사용자에게 기능을 제공하는 물리적 시스템으로 도메인 모델은 이 바운디드 컨텍스트 안에서 도메인을 구현한다.

여러 하위 도메인을 하나의 바운드 컨텍스트에서 개발할 때 주의할 점은 하위 도메인의 모델이 섞이지 않도록 하는 것이다.
비록 한 개의 바운디드 컨텍스트가 여러 하위 도메인을 포함하더라도 하위 도메인마다 구분되는 패키지를 갖도록 구현해야 한다.
이렇게 함으로써 하위 도메인을 위한 모델이 서로 뒤섞이지 않고 하위 도메인마다 바운디드 컨텍스트를 갖는 효과를 낼 수 있다.

바운디드 컨텍스트는 도메인 모델을 구분하는 경계가 되기 떄문에 구현하는 하위 도메인에 알맞은 모델을 포함한다. 같은 사용자라고 하더라도 주문 바운디드 컨텍스트와 회원 바운디드 컨텍스트가 갖는 모델이 달라진다.


바운디드 컨텍스트 구현

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

표현 영역은 사용자를 위해 HTML 페이지를 생성할 수도, 다른 바운디드 컨텍스트를 위해 REST API를 제공할 수도 있다.
모든 바운디드 컨텍스트를 반드시 도메인 주도로 개발할 필요는 없다.
상품의 리뷰는 복잡한 도메인 로직을 갖지 않기 때문에 CRUD 방식으로 구현해도 된다.
DAO와 데이터 중심의 밸류 객체를 이용해서 리뷰 기능을 구현해도 기능을 유지 보수하는 데 큰 문제가 없다.

서비스-DAO 구조를 사용하면 도메인 기능이 서비스에 흩어지게 된다.
그러나 도메인 기능 자체가 단순하면 서비스-DAO로 구성된 CRUD 방식을 사용해도 코드를 유지 보수하는 데 문제가 되지 않는다고 생각한다.

한 바운디드 컨텍스트에서 두 방식을 혼합해서 사용할 수도 있다.
대표적인 예가 CQRS 방식이다.

Command Query Responsibility Segregation
상태를 변경하는 명령 기능과 내용을 조회하는 쿼리 기능을 위한 모델을 구분하는 패턴

이 패턴을 단일 바운디드 컨텍스트에 적용하면 상태 변경과 관련된 기능은 도메인 모델 기반으로, 조회 기능은 서비스-DAO를 이용해서 구현할 수 있다.


바운디드 컨텍스트 간 통합

온라인 쇼핑 사이트에서 매출 증대를 위해 카탈로그 하위 도메인에 개인화 추천 기능을 도입하기로 했다고 하자.
기존 카탈로그 시스템을 개발하던 팀과 별도로 추천 시스템을 담당하는 팀이 새로 생겨서 이 팀에서 주도적으로 추천 시스템을 만들기로 했다.
이렇게 되면 카탈로그 하위 도메인에는 기존 카탈로그를 위한 바운디드 컨텍스트와 추천 기능을 위한 바운디드 컨텍스트가 생긴다.

두 팀이 관련된 바운디드 컨텍스트를 개발하면 자연스럽게 두 바운디드 컨텍스트 간 통합이 발생한다.
카탈로그와 추천 바운디드 컨텍스트 간 통합이 필요한 기능은 다음과 같다.

  • 사용자가 제품 상세 페이지를 볼 떄, 보고 있는 상품과 유사한 상품 목록을 하단에 보여준다.

사용자가 카탈로그 바운디드 컨텍스트에 추천 제품 목록을 요청하면 카탈로그 바운디드 컨텍스트는 추천 바운디드 컨텍스트로부터 추천 정보를 읽어와 제공한다.
이 떄 카탈로그 컨텍스트와 추천 컨텍스트의 도메인 모델은 서로 다르다.
카탈로그는 제품 중심을, 추천은 추천 연산을 위한 모델을 구현한다.

카탈로그 시스템은 추천 시스템으로부터 추천 데이터를 받아온다.
하지만 추천의 도메인 모델을 사용하기보다는 카탈로그 도메인 모델을 사용해서 추천 상품을 표현해야 한다.

REST API를 호출하는 것은 두 바운디드 컨텍스트를 직접 통합하는 방법이다.
직접 통합하는 대신 간접적으로 통합하는 방법도 있다.
대표적인 간접 통합 방식이 메시지 큐를 사용하는 것이다.
추천 시스템은 사용자가 조회한 상품 이력이나 구매 이력과 같은 사용자 활동 이력을 필요로 하는데, 이 내역을 전달할 때 메시지 큐를 사용할 수 있다.

어떤 도메인 관점에서 모델을 사용하느냐에 따라 두 바운디드 컨텍스트의 구현 코드가 달라지게 된다.


바운디드 컨텍스트 간 관계

바운디드 컨텍스트는 어떤 식으로든 연결되기 때문에 두 바운디드 컨텍스트는 다양한 방식으로 관계를 맺는다.
가장 흔한 관계는 한 쪽에서 API를 제공하고 다른 한쪽에서 그 API를 호출하는 관계이다.
REST API가 대표적이다.
이 관계에서 API를 사용하는 바운디드 컨텍스트는 API를 제공하는 바운디드 컨텍스트에 의존하게 된다.

그림에서 다운스트림 컴포넌트 '카탈로그 컨텍스트'는 업스트림 컴포넌트 '추천 컨텍스트'가 제공하는 데이터와 기능에 의존한다.
카탈로그는 추천 상품을 보여주기 위해 추천 바운디드 컨텍스트가 제공하는 REST API를 호출한다.
추천 시스템이 제공하는 REST API의 인터페이스가 바뀌면 카탈로그 시스템의 코드도 바뀌게 된다.

상류 컴포넌트는 일종의 서비스 공급자 역할을 하며, 하류 컴포넌트는 그 서비스를 사용하는 고객 역할을 한다.
고객과 공급자 관계에 있는 두 팀은 상호 협력이 필수적이다.

상류 컴포넌트는 보통 하류 컴포넌트가 사용할 수 있는 통신 프로토콜을 정의하고 이를 공개한다.
상류 팀의 고객인 하류 팀이 다수 존재하면 상류 팀은 여러 하류 팀의 요구사항을 수용할 수 있는 API를 만들고 이를 서비스 형태로 공개해서 서비스의 일관성을 유지할 수 있다.
이런 서비스를 가리켜 Open Host Service라고 한다.

두 바운디드 컨텍스트가 같은 모델을 공유하는 경우도 있다.
예를 들어, 운영자를 위한 주문 관리 도구를 개발하는 팀과 고객을 위한 주문 서비스를 개발하는 팀이 다르다고 가정하자.
두 팀은 주문을 표현하는 모델을 공유함으로써 주문과 관련된 중복 설계를 막을 수 있다.
이렇게 두 팀이 공유하는 모델을 Shared Kernel라고 부른다.

공유 커널의 장점은 중복을 줄여준다는 것이다.
하지만 두 팀이 한 모델을 공유하기 때문에 한 팀에서 임의로 모델을 변경하면 안 되며 두 팀이 밀접한 관곌르 유지해야 한다.
두 팀이 밀접한 관계를 형성할 수 없다면 공유 커널을 사용할 때의 장점보다 이로 인해 개발이 지연되고 정체되는 문제가 더 커지게 된다.

마지막으로 살펴볼 관계는 Seperate Way이다.
간단히 말해서, 서로 통합하지 않은 방식이다.
두 바운디드 컨텍스트 간에 통합하지 않으므로 서로 독립적으로 모델을 발전시킨다.

독립 방식에서 두 바운디드 컨텍스트 간의 통합은 수동으로 일어진다.
수동으로 통합하는 방식이 나쁜 것은 아니지만 규모가 커질수록 수동 통합에는 한계가 있으므로 규모가 커지기 시작하면 두 바운디드 컨텍스트를 통합해야 한다.
이때 외부에서 구매한 솔루션과 ERP를 완전히 대체할 수 없다면 두 바운디드 컨텍스트를 통합해 주는 별도의 시스템을 만들어야 할 수도 있다.


컨텍스트 맵

개별 바운디드 컨텍스트에 매몰되면 전체를 보지 못할 때가 있다.
나무만 보고 숲을 보지 못하는 상황을 방지하려면 전체 비즈니스를 조망할 수 있는 지도가 필요한데, 그것이 바로 컨텍스트 맵이다.
컨텍스트 맵은 바운디드 컨텍스트 간의 관계를 표시한다.

한눈에 각 바운디드 컨텍스트의 경계가 명확하게 드러나고 서로 어떤 관계를 맺고 있는지 알 수 있다.
바운디드 컨텍스트 영역에 주요 애그리거트를 함께 표시하면 모델에 대한 관계가 더 명확히 드러난다.

컨텍스트 맵은 시스템의 전체 구조를 보여준다.
이는 하위 도메인과 일치하지 않는 바운디드 컨텍스트를 찾아 도메인에 맞게 바운디드 컨텍스트를 조절하고, 사업의 핵심 도메인을 위해 조직 역량을 어떤 바운디드 컨텍스트에 집중할지 파악하는 데 도움을 준다.

0개의 댓글