도메인 모델은 여러 하위 도메인으로 구분되기 때문에 한 개의 모델로 여러 하위 모델을 표현하려고 시도하면 오히려 모든 하위 도메인에 맞지 않는 모델을 만들게 된다.
예를들어 상품이라는 모델을 생각해보면, 카탈로그에서 상품, 재고 관리에서 상품, 주문에서 상품, 배송에서 상품은 이름만 같지 실제로 의미하는 것은 다르다. 카탈로그에서의 상품은 상품 이미지, 상품명, 상품가격과 같은 상품 정보가 위주라면, 재고 관리에서는 실존하는 개별 객체를 추적하기 위한 목적으로 사용한다.
또 논리적으로 같은 존재처럼 보이지만 하위 도메인에 따라 다른 용어를 사용하는 경우도 있다. 카탈로그 도메인에서의 상품이 검색 도메인에서는 문서로 불리기도 한다. 비슷하게 시스템을 사용하는 사람을 회원 도메인에서는 회원이라고 부르지만, 주문 도메인에서는 주문자라고 부른다.
이렇게 하위 도메인마다 같은 용어라도 의미가 다르고 같은 대상이라도 지칭하는 용어가 다를 수 있어서 한 개의 모델로 모든 하위 도메인을 표현하려는 시도는 올바른 방법이 아니며 표현할 수도 없다. 따라서 하위 도메인마다 사용하는 용어가 다르기 때문에 올바른 도메인 모델을 개발하려면 하위 도메인마다 모델을 만들어야 한다. 또 각 모델은 명시적으로 구분되는 경계를 가져서 섞이지 않도록 해야 한다.
바운디드 컨텍스트는 도메인 모델을 구분하는 경계가 되기 때문에 바운디드 컨텍스트는 구현하는 하위 도메인에 알맞는 모델을 포함한다. 같은 사용자라 하더라도 주문 바운디드 컨텍스트와 회원 바운디드 컨텍스트가 갖는 모델이 달라진다. 같은 상품이라도 카탈로그 바운디드 컨텍스트의 Procut와 재고 바운디드 컨텍스트의 Product는 각 컨텍스트에 맞는 모델을 갖는다. 따라서 회원의 Member는 애그리거트 루트이지만 주문의 Orderer는 밸류가 된다.
바운디드 컨텍스트는 도메인 모델만 표현하는 것은 아니다. 표현 영역, 응용 서비스, 인프라스터럭처 영역을 모두 포함한다. 도메인 모델의 데이터 구조가 바뀌면 DB 테이블 스키마도 함께 변경해야 하므로 테이블도 바운디드 컨텍스트에 포함된다.
모든 바운디드 컨텍스트는 반드시 도메인 주도로 개발할 필요는 없는데, 상품의 리뷰같은 경우는 복잡한 도메인 로직을 갖지 않기 때문에 CRUD 방식으로 구현해도 된다. 즉, DAO와 데이터 중심의 밸류 객체를 이용해서 리뷰 기능을 구현해도 유지 보수하는 데 큰 문제가 없다.
따라서 바운디드 컨텍스트는 서로 다른 기술을 사용할 수도 있다.
바운디드 컨텍스트 간 통합
온라인 쇼핑 사이트에서 매출 증대를 위해 카탈로그 하위 도메인에 개인화 추천 기능을 도입한다고 하자. 그러면 기존 카탈로그 시스템을 개발하던 팀과 별도로 추천 시스템을 담당하는 팀이 새로 생겨 이 팀에서 주도적으로 추천 시스템을 만들기로 했다. 그러면 카탈로그 하위 도메인에는 기존 카탈로그를 위한 바운디드 컨텍스트와 추천 기능을 위한 추천 바운디드 컨텍스트가 생긴다.
두 팀이 관련된 바운디드 컨텍스트를 개발하면 자연스럽게 두 바운디드 컨텍스트 간 통합이 발생한다. 카탈로그와 추천 바운디드 컨텍스트 간 통합이 필요한 기능은 '사용자가 제품 상세 페이지를 볼 때, 보고 있는 상품과 유사한 상품 목록을 하단에 보여준다'와 같다.
사용자가 카탈로그 바운디드 컨텍스트에 추천 제품 목록을 요청하면 카탈로그 바운디드 컨텍스트는 추천 바운디드 컨텍스트로부터 추천 정보를 읽어와서 추천 제품 목록을 제공한다. 이때 카탈로그 컨텍스트와 추천 컨텍스트의 도메인 모델은 서로 다르다. 카탈로그는 제품을 중심으로 도메인 모델을 구현하지만 추천은 추천 연산을 위한 모델을 구현한다. 따라서 추천 시스템은 상품의 상세 정보를 포함하지 않으며 상품 번호 대신 아이템 ID라는 용어를 사용해서 식별자를 표현하고 추천 순위와 같은 데이터를 담을 수 있다.
카탈로그 시스템은 추천 시스템으로부터 추천 데이터를 받아오지만, 추천의 도메인 모델을 사용하기보다는 카탈로그 도메인 모델을 사용해서 추천 상품을 표현해야 한다.
즉 아래와 같은 도메인 서비스를 이용해서 상품 추천 기능을 표현해야 한다.
도메인 서비스를 구현한 클래스는 인프라스트럭처 영역에 위치한다. 이 클래스는 외부 시스템과의 연동을 처리하고 외부 시스템의 모델과 현재 도메인 모델간의 변환을 책임진다. 아래 코드에서는 ProductRecommendationService라는 도메인 서비스를 RecommendationSystemClient라는 인프라스트럭처 서비스가 구현한 예제인데, 따라서 RecommendationSystemClient가 외부 시스템의 도메인 모델을 침범하지 않도록 막아주는 역할도 할 수 있으므로 다른 바운디드 컨텍스트의 도메인 모델에 영향을 받지 않고 내 도메인 모델을 유지할 수 있도록 해준다.
public class RecommendationSystemClient implement ProductRecommendationService {
privaate ProductRepository productRepository;
// 외부 추천 시스템을 위한 클라이언트
private ExternalRecClient externalRecClient;
@Override
public List<Product> getRecommendationOf(ProductId id) {
List<RecommendationItem> item = externalRecClient.getRecs(id.getValue());
return productRepository.findById(item.prodId);
}
}
마이크로서비스 아키텍처 특징은 바운디드 컨텍스트와도 잘 어울리는데, 각 바운디드 컨텍스트는 모델의 경계를 형성하는데 바운디드 컨텍스트를 마이크로서비스로 구현하면 자연스럽게 컨텍스트별로 모델이 분리된다. 코드로 생각하면 마이크로서비스마다 프로젝트를 생성하므로 바운디드 컨텍스트마다 프로젝트를 만들게 된다.
참고 문서
https://appleg1226.tistory.com/41
(2) DDD의 도메인과 바운디드 컨텍스트 - 개발보다는 설계부터!
도메인과 바운디드 컨텍스트는 무엇이길래 이전 글에서도 이야기 했지만, DDD는 용어부터가 우리가 알고있는 것과 다르고, 익숙해져야 할 것들이 많다. 특히나 바운디드 컨텍스트(Bounded Context)에
appleg1226.tistory.com
https://jaehoney.tistory.com/252
DDD - 바운디드 컨텍스트란 무엇인가 ?!
해당 포스팅은 "도메인 주도 개발 시작하기" 라는 내용을 정리한 글입니다. 해당 도서는 아래 Link에서 확인할 수 있습니다. - http://www.yes24.com/Product/Goods/108431347 도메인 모델과 경계 도메인 모델
jaehoney.tistory.com
'DDD' 카테고리의 다른 글
이벤트(Event), CQRS (Command Query Responsibility Segregation) (0) | 2023.01.10 |
---|---|
도메인 서비스, 애그리거트 트랜잭션 관리 (0) | 2022.12.20 |
응용 서비스와 표현 영역 (0) | 2022.12.13 |
리포지터리와 모델 구현 (0) | 2022.12.01 |
애그리거트 (0) | 2022.11.13 |