고딩왕 코범석

9장 - 도메인 모델과 바운디드 컨텍스트 본문

Book Lounge/도메인 주도 개발 시작하기

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

고딩왕 코범석 2022. 7. 26. 21:41
반응형

Index

  1. 도메인 모델과 경계
  2. 바운디드 컨텍스트
  3. 바운디드 컨텍스트 구현
  4. 바운디드 컨텍스트 간 통합
  5. 바운디드 컨텍스트 간 관계

도메인 모델과 경계

한 개의 모델로 여러 하위 도메인을 모두 표현하려 시도하면 모든 하위 도메인에 맞지 않는 모델을 만들게 된다.

  • 예를 들어, 카탈로그에서의 상품과 재고 관리에서의 상품, 주문 상품, 배송에서의 상품들은 모두 같은 상품이지만 실제 의미하는 것이 다르다.
    • 카탈로그에서의 상품은 상품 제목, 내용과 같은 정보를 의미하고 재고 관리에서의 상품은 상품 갯수가 주된 정보이다.
  • 여러 하위 도메인의 모델이 얽히기 시작하면 하위 도메인 별로 다르게 발전하는 요구사항을 모델에 반영하기 어려워진다.

이러한 이유로 한 개의 모델로 모든 하위 모델을 표현하려는 시도는 좋지 않다. 모델은 특정한 컨텍스트(문맥)에 따라 완전한 의미를 갖는데 이렇게 구분되는 경계를 갖는 컨텍스트를 DDD에서는 바운디드 컨텍스트라 부른다.

위로

바운디드 컨텍스트

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

때에 따라 하나의 하위 도메인에서 여러 바운디드 컨텍스트가 존재할 수 있고, 하나의 바운디드 컨텍스트가 여러 도메인에 걸쳐있는 경우도 존재한다.

주의할 점은 하위 도메인의 모델이 섞이지 않아야 한다.

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

바운디드 컨텍스트는 도메인 모델을 구분하는 경계가 되기 때문에 바운디드 컨텍스트는 구현하는 하위 도메인에 알맞는 모델을 포함한다.

  • 예를 들어, 같은 사용자라 하더라도 주문 바운디드 컨텍스트와 회원 바운디드 컨텍스트가 갖는 모델이 달라진다.
    • 즉, 회원의 Member는 애그리거트 루트이지만 주문의 Orderer는 밸류가 된다.
  • 같은 상품이라도 카탈로그 바운디드 컨텍스트의 Product와 재고 바운디드 컨텍스트가 갖는 모델이 달라진다.
    • 카탈로그의 Product는 상품이 속할 Category와 연관을 맺지만 재고의 Product는 카탈로그의 Category와 연관을 맺지 않는 것이다.

위로

바운디드 컨텍스트 구현

바운디드 컨텍스트는 도메인 기능을 사용자에게 제공하는데 필요한 표현 영역, 응용 서비스, 인프라스트럭쳐 영역을 모두 포함한다.

도메인 모델의 데이터 구조가 변경되면 DB 테이블 스키마도 변경되므로 테이블도 바운디드 컨텍스트에 포함된다.

모든 바운디드 컨텍스트를 도메인 주도로 개발할 이유는 없으며, 복잡한 도메인 로직을 갖고 있지 않다면 데이터 중심의 밸류 객체를 통해 구현해도 상관없다. 그리고 서로 다른 구현 기술을 사용할 수 있다.

한 바운디드 컨텍스트에서 도메인 주도와 데이터 중심 두 방식으로 개발을 진행할 수 있는데 대표적인 예가 CQRS 패턴이다.

https://user-images.githubusercontent.com/37062337/180995356-3ccc4711-b0cc-42e1-894c-c5f4f29a5f19.png

위로

바운디드 컨텍스트 간 통합

온라인 쇼핑몰에서 매출 증대를 위해 카탈로그 하위 도메인에 개인화 추천 기능을 도입한다고 가정하자. 이 때 카탈로그 하위 도메인에는 기존 카탈로그를 위한 바운디드 컨텍스트와 추천 기능을 위한 바운디드 컨텍스트가 생긴다.

사용자가 카탈로그 바운디드 컨텍스트에 추천 제품 목록을 요청할 때, 카탈로그 컨텍스트와 추천 컨텍스트의 도메인 모델은 서로 다르다.

이 경우 추천 도메인의 상품 모델보다 카탈로그 도메인 모델을 사용해서 표현해야하는데, 카탈로그 모델을 기반으로 하는 도메인 서비스를 이용해 상품 추천 기능을 표현해야한다.

public interface ProductRecommendationService {
    List<Product> getRecommendationsOf(ProductId productId);
}

도메인 서비스를 구현한 클래스는 인프라스트럭쳐 영역에 위치한다.

https://user-images.githubusercontent.com/37062337/181002575-d9076888-9cd9-4f81-b3a6-1b64aeeaeccb.png

위 그림의 RecommendationSystemClient는 REST API로부터 추천 상품을 가져온 후 Product 객체로 변환하는 책임을 갖고 있다.

만약 두 클래스간 변환 과정이 복잡하다면 별도의 클래스를 만들어 해당 클래스에서 변환 작업을 진행해도 된다.

REST API로 직접 통합하는 방법도 있지만 메세지 큐를 통해 간접적으로 통합하는 방법도 있다. 추천 시스템에서 사용자가 조회한 상품, 구매 이력과 같은 사용자 활동 이력을 메세지 큐에 보내고, 추천 시스템은 메세지 큐에서 consume 하는 방법이 대표적인 간접적 통합 방식이다.

메세지 큐의 장점은 큐로 보내는 메세지를 비동기로 보내서 처리가 완료될 때까지 기다리지 않고 자신의 처리를 이어서 한다.

위로

바운디드 컨텍스트 간 관계

바운디드 컨텍스트 간 관계는 다양하며 가장 흔한 관계는 REST API이며 프로토콜 버퍼도 제공할 수 있다.

카탈로그와 추천 예시로 돌아가면 카탈로그 바운디드 컨텍스트에서 추천 바운디드 컨텍스트로 호출하기 때문에 추천이 upstream, 카탈로그가 downstream 관계를 갖게 되고, 추천 바운디드 컨텍스트에서 제공하는 API가 변경되면 카탈로그 바운디드 컨텍스트의 코드도 수정된다.

만약 upstream에 의존하는 바운디드 컨텍스트가 다수 존재하면 서비스 형태로 공개하여 서비스의 일관성을 유지할 수 있는데, 이런 서비스를 가리켜 호스트 서비스 라고 한다.

  • 호스트 서비스의 대표적인 예가 검색이다.
  • 블로그, 카페, 게시판과 같은 서비스를 제공하는 포털은 각 서비스별로 검색 기능을 구현하기 보다는 검색을 위한 전용 시스템을 구축하고 각 서비스와 검색 시스템을 통합시킨다.
  • 이 때, 검색 시스템은 upstream, 블로그, 카페, 게시판은 downstream 관계이며 검색 팀은 각 downstream의 요구사항을 수용하는 단일 API를 만들어 이를 공개한다.
  • downstream은 upstream에서 제공하는 모델이 자신의 도메인 모델에 영향을 미치지 않도록 보호해주는 완충 지대를 만들어야한다.
    • 위 상품 추천 시스템을 REST API로 호출하는 예시에서 RecommendationSystemClient가 완충 역할을 담당한다.

위로

반응형