9장 도메인 모델과 바운디드 컨텍스트
9.1 도메인 모델과 경계
논리적으로 같은 존재처럼 보이지만 하위 도메인에 따라 다른 용어를 사용하는 경우도 있고, 한 개인 상품이 다른 곳에서는 여러 개 존재할 수 있다. 하위 도메인마다 같은 용어라도 의미가 다르고, 같은 대상이라도 지칭하는 용어가 다를 수 있기 때문에 한 개의 모델로 모든 하위 도메인을 표현하려는 시도는 올바른 방법이 아니며 표현할 수도 없다.
하위 도메인마다 사용하는 용어가 달라서 올바른 도메인 모델을 개발하려면 하위 도메인 모델을 만들어야 한다. 각 모델은 명시적으로 구분되는 경계를 가져서 섞이지 않도록 해야 한다. 모델은 특정한 컨텍스트(문맥) 하에서 완전한 의미를 갖는다. 같은 제품이라도 카탈로그 컨텍스트와 재고 컨텍스트에서 의미가 서로 다르다. 이렇게 구분되는 경계를 갖는 컨텍스트를 DDD에서는 바운디드 컨텍스트라고 부른다.
9.2 바운디드 컨텍스트
바운디드 컨텍스트는 모델의 경계를 결정하며 한 개의 바운디드 컨텍스트는 논외적으로 한 개의 모델을 갖는다. 용어를 기준으로 구분하며, 실제로 사용자에게 기능을 제공하는 물리적 시스템으로 도메인 모델은 이 바운디드 컨텍스트 안에서 도메인을 구현한다. 이상적으로 하위 도메인과 바운디드 컨텍스트가 일대일 관계를 가지는 것은 힘들다.
규모가 작은 기업은 여러 하위 도메인을 한 개의 바운디드 컨텍스트에서 구현한다. 이때 주의할 점은 여러 하위 도메인을 하나의 바운디드 컨텍스트에서 개발할 때 하위 도메인의 모델이 섞이지 않도록 하는 것이다. 한 개의 바운디드 컨텍스트가 여러 하위 도메인을 포함하더라도 도메인마다 구분되는 패키지를 갖도록 구현해야 하며, 이는 하위 도메인마다 바운디드 컨텍스트를 갖는 효과를 낼 수 있다.
9.3 바운디드 컨텍스트 구현
바운디드 컨텍스트가 도메인 모델만 포함하는 것은 아니다. 바운디드 컨텍스트는 도메인 기능을 사용자에게 제공하는 데 필요한 표현 영역, 응용 서비스, 인프라스트럭처 영역을 모두 포함한다. 도메인 모델의 데이터 구조가 바뀌면 DB 테이블 스키마도 변경해야 하므로 테이블도 바운디드 컨텍스트에 포함된다.
모두 바운디드 컨테스트를 반드시 도메인 주도로 개발할 필요는 없다. 상품의 리뷰는 복잡한 도메인 로직을 갖지 않기에 CRUD 방식으로 구현해도 된다. 각 바운디드는 도메인에 알맞은 아키텍처를 사용한다. 한 바운디드 컨텍스트에서 여러 방식을 혼합해서 사용할 수 있고, 서로 다른 구현 기술을 사용할 수도 있다.
마이크로서비스의 특징은 바운디드 컨텍스트와 잘 어울린다. 각 바운디드 컨텍스트는 모델의 경계를 형성하는데 바운디드 컨텍스트를 마이크로서비스로 구현하면 자연스럽게 컨텍스트별로 모델이 분리된다. 코드로 생각하면 마이크로서비스마다 프로젝트를 생성하므로 바운디드 컨텍스트마다 프로젝트를 만들게 된다.
이것은 코드 수준에서 모델을 분리하여 두 바운디드 컨텍스트의 모델이 섞이지 않도록 해주고, 별도 프로세스로 개발한 바운디드 컨텍스트는 독립적으로 배포하고 모니터링하며 확장되는데 이 역시 마이크로서비스가 갖는 특징이다.
9.4 바운디드 컨텍스트 간 관계
바운디드 컨텍스트 관계 중 가장 흔한 관계는 한쪽에서 API를 제공하고 다른 한쪽에서 그 API를 호출하는 관계이다. REST API가 대표적이다. 예로 하류 컴포넌트인 카탈로그 컨텍스트는 상류 컴포넌트인 추천 컨텍스트가 제공하는 데이터와 기능에 의존한다. 추천 시스템이 제공하는 REST API의 인터페이스가 바뀌면 카탈로그 시스템의 코드도 바뀌게 된다.
추천 시스템은 하류 컴포넌트가 사용할 수 있는 REST API를 제공하거나 프로토콜 버퍼와 같은 것을 이용해 서비스를 제공할 수 있다.
상류팀의 고객인 하류 팀이 다수 존재하면 요구사항을 수용할 수 있는 API를 만들고, 이를 서비스 형태로 공개해서 서비스의 일관성을 유지할 수 있다. 이를 공개 호스트 서비스라고 한다.
공개 호스트 서비스의 예로 검색이 있다. 블로그, 카페 같은 서비스를 제공하는 포털은 각 서비스별로 검색 기능을 구현하기보다는 검색을 위한 전용 시스템을 구축하고 검색 시스템과 각 서비스를 통합한다. 이때 검색 시스템은 상류 컴포넌트가 되고, 블로그와 카페 등 이는 하류 컴포넌트가 된다. 상류 팀은 각 하류 컴포넌트의 요구사항을 수용하는 단일 API를 만들어 이를 공개하고 각 하류 팀은 공개된 API를 사용해 검색 기능을 구현한다.
상류 컴포넌트의 서비스는 상류 바운디드 컨텍스트의 도메인 모델을 따른다. 따라서 하류 컴포넌트는 상류 서비스의 모델이 자신의 도메인 모델에 영향을 주지 않도록 보호해주는 완충 지대를 만들어야 한다.
예로 RecSystemClient는 인프라 영역에서 외부 시스템과의 연동을 처리하는데 외부 시스템의 도메인 모델이 내 도메인 모델을 침범하지 않도록 막아주는 역할을 한다. 즉 내 모델이 깨지는 것을 막아주는 안티코럽션 계층이 된다. 이 계층에서 두 바운디드 컨텍스트 간의 모델 변환을 처리해 주기 때문에 다른 바운디드 컨텍스트의 모델에 영향을 받지 않고 내 도메인 모델을 유지할 수 있다.
두 바운디드 컨텍스트가 같은 모델을 공유하는 경우도 있다. 예로 운영자를 위한 주문 관리 도구를 개발하는 팀, 고객을 위한 주문 서비스를 개발하는 팀이 다르다고 가정하자. 두 팀은 주문을 표현하는 모델을 공유함으로써 주문과 관련된 중복 설계를 막을 수 있다. 이렇게 두 팀이 공유하는 모델을 공유 커널이라고 부른다. 공유 커널의 장점은 중복을 줄여준다는 것이다.
마지막으로 살펴볼 관계는 독립 방식이다. 서로 통합하지 않는 방식이며, 독립적으로 모델을 발전시킨다. 두 바운디드 컨텍스트 간의 통합은 수동으로 이뤄진다.
9.5 컨텍스트 맵
개별 바운디드 컨텍스트에 매몰되면 전체를 못보는 경우가 있다. 전체 비즈니스를 조망할 수 있는 지도가 필요한데, 이것이 바로 컨텍스트 맵이다. 컨텍스트 맵은 시스템의 전체 구조를 보여준다. 하위 도메인과 일치하지 않는 바운디드 컨텍스트를 찾아 도메인에 맞게 바운디드 컨텍스트를 조절하고 사업의 핵심 도메인을 위해 조직 역량을 어떤 바운디드 컨텍스트에 집중할지 파악하는 데 도움을 준다.