CS log

Bounded Context Language 본문

Development/Backend

Bounded Context Language

sj.cath 2023. 11. 21. 01:22

9.1 도메인 모델과 경계

  • 처음 도메인 모델을 만들 때 빠지기 쉬운 함정 = 도메인을 완벽하게 표현하는 단일 모델을 만드는 것
    • 한 도메인은 다시 여러 하위 도메인으로 구분되기 때문에 한 개의 모델로 여러 하위 도메인을 모두 표현하려고 시도하면 오히려 모든 하위 도메인에 맞지 않는 모델을 만들게 된다.
      • ex) 상품 모델 만들기
      • 카탈로그에서 상품, 재고 관리에서 상품, 주문에서 상품, 배송에서 상품은 실제로 의미하는 것이 다르다. 왜냐하면 카탈로그에서 상품은 상품 이미지, 상품 이미지, 상품명, 상품 가격, 옵션 목록, 상세 설명과 같은 상품을 사용한다.카탈로그에서는 물리적으로 1개인 물건(맥북프로)가 재고 관리에서는 맥북프로 재고가 10개이기 때문에 여러 개 존재할 수 있다.
      • 논리적으로 같은 존재처럼 보이지만 하위 도메인에 따라 다른 용어를 사용하는 경우도 있다.
        • 카탈로그 도메인에서의 상품이, 검색 도메인에서는 문서로 불리기도 한다. 시스템을 이용하는 사람이 회원 도메인에서는 “회원”으로, 주문 도메인에서는 “주문자”라고 부르고, 배송 도메인에서는 “보내는 사람”이라고 부르기도 한다. 게시판 실습 상황에 적용해보면 회원 관리 차원에서는 “회원”이라고 하지만 글 도메인에서는 “작성자”라고 부른다.
        한 개의 모델로 모든 하위 모데인을 표현하려는 시도는 올바른 방법이 아니며 표현할 수도 없다.⇒ 올바른 도메인 모델을 개발하려면 하위 도메인마다 모델을 만들어야 한다.
      • 여러 하위 도메인의 모델이 섞이기 시작하면 모델의 의미가 약해질 뿐만 아니라 여러 도메인의 모델이 서로 얽히기 때문에 각 하위 도메인별로 다르게 발전하는 요구사항을 모델에 반영하기 어려워진다.
    모델은 특정한 컨텍스트(문맥) 하에서 완전한 의미를 갖는다.⇒ 이렇게 구분되는 경계를 갖는 컨텍스트는 DDD에서는 “바운디드 컨텍스트”라고 부른다. ex) 같은 제품이라도 카탈로그 컨텍스트와 재고 컨텍스트에서 의미가 서로 다르다.

 

9.2 바운디드 컨텍스트

  • 바운디드 컨텍스트는 모델의 경계를 결정하며 한 개의 바운디드 컨텍스트는 논리적으로 한 개의 모델을 갖는다.
    • 바운디드 컨텍스트는 용어를 기준으로 구분한다
    • ex) 카탈로그 컨텍스트와 재고 컨텍스트는 서로 다른 용어를 사용하므로 이 용어를 기준으로 컨텍스트를 분리할 수 있다.
    • 실제로 사용자에게 기능을 제공하는 물리적 시스템으로 도메인 모델은 이 바운디드 컨텍스트 안에서 도메인을 구현한다.
  • 이상적으로 하위 도메인과 바운디드 컨텍스트가 일대일 관계를 가지면 좋겠지만 현실은 그렇지 않을 때가 많다.
  • 바운디드 컨텍스트는 기업의 팀 조직 구조에 따라 결정되기 도 한다.
    • ex) 주문 하위 도메인이라도 주문을 처리하는 팀과 복잡한 결제 금액 계산 로직을 구현하는 팀이 따로 있다고 한다면 주문 하위 도메인에 주문 바운디드 컨텍스트와 결제 금액 계산 바운디드로 구성할 수 있다.
    • 주문 하위 도메인 = 주문 바운디드 컨텍스트 + 결제 금액 계산 바운디드 컨텍스트
  • 용어를 명확하게 구분하지 못해 두 하위 도메인을 하나의 바운디드 컨텍스트에서 구현하기도 한다.
      • ex) 카탈로그와 재고 관리가 아직 명확하게 구분되지 않은 경우, 두 하위 도메인을 하나의 바운디드 컨텍스트(상품 바운디드 컨텍스트)에서 구현하기도 한다.
        • 카탈로그 하위 도메인 + 재고 하위 도메인= 상품 바운디드 컨텍스트
  • 규모가 작은 기업은 전체 시스템을 한 개 팀에서 구현할 때도 있다.
      • ex) 한 개의 웹 애플리케이션으로 회원, 카탈로그, 재고, 구매, 결제와 관련된 모든 기능을 제공하는 경우 여러 하위 도메인을 한 개의 한 개의 바운디드 컨텍스트에서 구현한다.
      • 주의할 점 = 하위 도메인의 모델이 섞이지 않도록 하는 것
        • 하위 도메인을 위한 단일 모델을 만들고 싶은 유혹에 빠지기 쉽다. → 이런 유혹에 걸려들면 도메인 모델이 개별 하위 도메인을 제대로 반영하지 못해서 하위 도메인별로 기능을 확장하기 어렵게 된다. → 하위 도메인마다 구분되는 패키지를 갖도록 구현해야 하며, 이렇게 함으로써 하위 도메인을 위한 모델이 서로 뒤섞이지 않고 하위 도메인마다 바운디드 컨텍스트를 갖는 효과를 낼 수 있다.
    • ⇒ 물리적인 바운디드 컨텍스트가 한 개이더라도 내부적으로 패키지를 활용해서 논리적으로 바운디드 컨텍스트를 만든다.
  • 바운디드 컨텍스트는 각자 구현하는 하위 도메인에 맞는 모델을 갖는다.
    • ex) 회원의 경우 → 회원 바운디드 컨텍스트에서는 Member가 애그리거트 루트가 되고 주문 바운디드 컨텍스트에서는 Orderer이라는 이름을 가진 벨류로 역할을 한다.

 

9.3 바운디드 컨텍스트 구현

  • 바운디드 컨텍스트는 도메인 기능을 제공하는 데 필요한 모든 요소를 포함한다. (도메인 모델만 포함하는 것은 아니다. )
    • 필요한 표현 영역, 응용 서비스, 인프라스트럭처 영역을 모두 포함 (도메인 모델의 데이터 구조가 바뀌면 DB 테이블 스키마도 함께 변경해야 하므로 테이블도 바운디드 컨텍스트에 포함된다)
  • 모든 바운디드 컨텍스트를 반드시 도메인 주도로 개발할 필요는 없다.
    • 상품 리뷰의 경우 복잡한 도메인 로직을 갖지 않기 때문에 CRUD 방식으로 구현해도 된다.
      • 즉, DAO와 데이터 중심의 벨류 객체를 이용해서 리뷰 기능을 구현해도 기능을 유지보수하는 데 큰 문제가 없다.
      • 표현 영역 → 서비스 → DAO → DBMS
    • 서비스 - DAO 구조를 사용하면 도메인 기능이 서비스에 흩어지게 되지만 도메인 기능 자체가 단순하면 서비스-DAO로 구성된 CRUD 방식을 사용해도 코드를 유지보수하는 데 문제가 되지 않는다.
  • 한 바운디드 컨텍스트에서 두 방식을 혼합해서 사용할 수 있다.
    • CQRS = 명령 기능과 내용 기능을 모델을 구분하는 패턴이다.
      • 상태 변경 기능은 도메인 모델 기반으로 구현
      • 조회 기능 = 서비스 - DAO(조회 전용 데이터 모델)
  • 각 바운디드 컨텍스트는 서로 다른 구현 기술을 사용할 수 있다.
    • 웹 MVC는 스프링 MVC를 사용하고 리포지터리 구현 기술로는 JPA/하이버네이트를 사용하는 바운디드 컨텍스트가 존재할 수도 있다.

9.4 바운디드 컨텍스트 간 통합

  • 예를 들어 카탈로그 바운디드 컨텍스트와 추천 기능을 위한 바운디드 컨텍스트가 생긴다고 하자
    • 2개가 관련된 바운디드 컨텍스트를 개발하면 자연스럽게 두 바운디드 컨텍스트 간 통합이 발생한다.
    • 사용자가 카탈로그 바운디드 컨텍스트에 추천 제품 목록을 요청하면 카탈로그 바운디드 컨텍스트는 추천 바운디드 컨텍스트로부터 추천 정보를 읽어와 추천 제품 목록을 제공한다.
  • 외부 시스템과의 연동을 처리하고 외부 시스템의 모델과 현재 모델 간의 변환을 책임지는 도메인 서비스
    • = 상품 추천 기능을 표현하는 도메인 서비스 인터페이스
      • 도메인 관점에서 인터페이스 정의
    • RecSystemClient (추천 상품 로딩)
      • 도메인 모델과 외부 시스템 간의 모델 변환 처리
      • Rest API로부터 데이터를 읽어와 카탈로그 도메인에 맞는 상품 모델로 변환
        • 모델 간의 변환이 복잡하면 변환 처리 클래스(Translator)를 별도로 만들어도 된다.
        [간접 통합 방식]
        • 카탈로그 바운디드 컨텍스트는 추천 시스템이 필요로 하는 사용자 활동 이력을 메시지 큐에 추가한다.
        메시지 큐는 비동기로 메시지를 처리하기 때문에 카탈로그 바운디드 컨텍스트는 메시지를 큐에 추가한 뒤에 추천 바운디드 컨텍스트가 메시지를 처리할 때까지 기다리지 않고 바로 자신의 처리를 계속 한다.
        • 사용할 메시지의 데이터 구조를 맞추어야 한다.
        • 어떤 도메인 관점에서 모델을 사용하느냐에 따라 두 바운디드 컨텍스트의 구현 코드가 달라지게 된다. 한 쪽에서 출판하고 다른 한 쪽에서는 구독하는 방식이다.
      • 메시지 큐를 사용하는 것이다.
package com.efub.dddstudy.Chap9_도메인모델과바운디드컨텍스트;

import com.efub.dddstudy.Chap3_애그리거트.Product;
import com.efub.dddstudy.Chap3_애그리거트.ProductRepository;

import java.util.List;
import java.util.stream.Collectors;

//인프라 영역
public class RecSystemClient implements ProductRecommedationService{
	private ProductRepository productRepository;

	@Override
	public List<Product> getRecommendationsOf(ProductId id)
	{
		List<RecommendationItem> items = getRecItems(id.getValue());
		return toProduct(items);
	}
	
	private List<RecommendationItem> getRecItems(String itemId){
		return externalRecClient.getRecs(itemId);//외부 추천 시스템을 위한 클라이언트 
	}
	
	private List<Product> toProducts(List<RecommendationItem> items){
		return items.stream()
				.map(item -> toProductId(item.getItemId()))
				.map(prodId -> productRepository.findById(prodId))
				.collect(toList());
	}
	
	private ProductId toProductId(String itemId){
		return new ProductId(itemId);
	}
}

*마이크로 서비스와 바운디드 컨텍스트

모델의 경계를 형성하는 바운디드 컨텍스트를 마이크로 서비스로 구현하면 자연스럽게 컨텍스트별로 모델이 분리된다.

9.5 바운디드 컨텍스트 간 관계

  • 바운디드 컨텍스트는 어떤 식으로든 연결되기 때문에 두 바운디드 컨텍스트는 다양한 방식으로 관계를 맺는다.
    • 가장 흔한 관계는 한쪽에서 API를 제공하고 다른 한쪽에서 그 API를 호출하는 관계이다. REST API가 대표적이다.
    • 이때, 바운디드 컨텍스트는 API를 제공하는 바운디드 컨텍스트에 의존하게 된다.
      • ex) 상류 컴포넌트 = 추천 바운디드 컨텍스트 → 공급자 역할
        • 하류 컴포넌트 = 카탈로그 바운디드 컨텍스트
    1. 호스트 서비스
    • 상류 팀의 고객인 하류팀이 다수 존재하면 상류 팀은 여러 하류 팀의 요구사항을 수용할 수 있는 API를 만들고 이를 서비스 형태로 공개해서 서비스의 일관성을 유지할 수 있다.

          2. 상류 컴포넌트의 서비스는 상류 바운디드 컨텍스트의 도메인 모델을 따른다.

    • → 하류 컴포넌트는 상류 서비스의 모델이 자신의 도메인 모델에 영향을 주지 않도록 보호해주는 완충 지대를 만들어야 한다.
      • ex) 인프라 영역의 RecSystemClient - 외부 시스템의 도메인 모델이 내 도메인을 침범하지 않도록 막아주는 역할을 한다. - 안티코럽션 계층

          3. 공유 커널 = 두 바운디드 컨텍스트가 같은 모델을 공유하는 경우 → 주문과 관련된 중복 설계를 막을 수 있다.

          4. 독립 방식

               - 서로 통합하지 않는 방식

               - 통합은 수동적으로 이루어진다.

               - 수동의 한계가 있을 때 중간에 통합 시스템을 별도로 두는 방식

9.6 컨텍스트 맵

  • 바운디트 컨텍스트 간 관계를 표시
    • 오픈 호스트 서비스 = OHS
    • 안티 코럽션 계층 = ACL

'Development > Backend' 카테고리의 다른 글

DDD (Domain Driven Design)  (0) 2023.11.21
Spring Security & JWT  (1) 2023.11.04
TDD  (0) 2023.10.05
Django part1~part4  (0) 2023.03.27