https://fsharpforfunandprofit.com/books/
바운디드 컨텍스트 간 계약
이벤트 및 관련 DTO는 바운디드 컨텍스트 간의 일종의 계약을 형성합니다.
성공적인 의사 소통을 위해서는 두 컨텍스트가 공통 형식에 동의해야 합니다.
- Shared Kernel :
- 두 도메인이 공통적인 비즈니스 개념을 사용하는 경우입니다.
- 예를 들어 주문 접수 컨텍스트와 배송 컨텍스트가 동일한 주소 양식을 사용하기로 했다면, 둘은 동일한 유효성 검사 로직을 사용해야 합니다.
- 이 관계에서 이벤트 또는 DTO의 정의를 변경하는 것은 영향을 받는 다른 컨텍스트의 소유자와 협의한 경우에만 수행되어야 합니다. 해당 개념 외에는 독립적으로 진화할 수 있습니다.
- A Customer/Supplier or Consumer Driven Contract relationship :
- 다운스트림 컨텍스트는 업스트림 컨텍스트가 제공하기를 원하는 계약을 정의합니다.
- 청구 컨텍스트는 계약을 정의할 수 있으며("이것이 고객에게 청구하기 위해 필요한 것입니다") 주문 접수 컨텍스트는 해당 정보만 제공하고 추가 정보는 제공하지 않습니다.
- 해당 계념 외에는 독립적으로 진화할 수 있습니다.
- A Conformist relationship
- 고객 주도 계약 관계의 역입니다.
- 다운스트림은 업스트림에서 주는대로 받아야 합니다. 흔한 API 컨슈머 관계입니다.
- 주문 접수 컨텍스트는 외부의 제품 카탈로그에 정의된 계약을 수락하고 코드를 그대로 사용하도록 조정할 수 있습니다.
Anti-Corruption Layers (부패 방지 계층)
종종 외부 시스템과 통신할 때 사용 가능한 인터페이스가 도메인 모델과 전혀 일치하지 않습니다.
이 경우 상호 작용 및 데이터는 경계 컨텍스트 내에서 사용하기에 더 적합한 것으로 변환되어야 합니다.
컨텍스트 간의 이러한 추가 분리 수준을 DDD 용어로 Anti-Corruption Layer라고 하며 종종 "ACL"로 축약됩니다.
Anti-Corruption Layer는 주로 유효성 검사를 수행하거나 데이터 손상을 방지하는 것이 아니라
두 가지 다른 언어(업스트림 컨텍스트에서 사용되는 언어) 간의 번역기 역할을 합니다.
ex) 주문 접수 컨텍스트의 고객 = 주문인 => 배송 컨텍스트의 고객 = 수령인
컨텍스트 맵 간 관계
OrderTaking 및 Billing 컨텍스트 간의 관계는 "Shared Kernel"이 됩니다. 즉, 통신 계약을 공동으로 소유하게 됩니다.
- OrderTaking와 Billing 사이의 관계는 "Customer Drivem Comtract" 관계가 될 것입니다. 즉, Billing 컨텍스트가 계약을 결정하고 OrderTaking시스템이 Billing 컨텍스트에 필요한 데이터를 정확히 제공합니다.
- Order-taking와 Product-Catalog 간의 관계는 "conformist" 관계가 됩니다. 즉, OrderTaking 컨텍스트가 ProductCagalog와 동일한 모델을 사용하도록 합니다.
- 마지막으로 외부 Address Checking 서비스에는 우리 도메인과 전혀 유사하지 않은 모델이 있으므로 상호 작용에 명시적 Anti-Corruption Layer를 삽입합니다. 이것은 서드파티 컴포넌트를 사용할 때 일반적인 패턴입니다. 이를 통해 공급업체 종속을 방지하고 나중에 다른 서비스로 교체할 수 있습니다.
도메인 상호 작용 방식을 결정하는 것은 종종 기술적인 문제만큼이나 조직적인 문제이며,
역 콘웨이 전략 -조직 구성을 보고 시스템 만들기-를 적용하는 경우도 있습니다
바운디드 컨텍스트 내의 워크플로
디스커버리 단계에서 비즈니스 워크플로를 하나 이상의 도메인 이벤트를 생성하는 하나의 커맨드에 의해 시작된 미니 프로세스로 정의했습니다.
다이어그램을 만들 때 워크플로를 입력 및 출력이 있는 작은 파이프로 나타냅니다.
공개 워크플로(바운딩된 컨텍스트 외부에서 트리거되는 워크플로)는 그림과 같이 경계를 약간 넘어 "삐져나온" 것으로 표시됩니다.
워크플로의 입출력
워크플로 함수의 입력은 커맨드 객체입니다.
아웃풋은 다른 컨텍스트와 통신하기 위한 이벤트 집합입니다.
예를 들어 OrderTaking 워크플로에서 입력은 PlaceOrder 명령과 연결된 데이터이고 출력은 OrderPlaced 이벤트와 같은 이벤트 집합입니다.
data BillableOrderPlaced =
OrderId
AND BillingAddress
AND AmountToBill
OrderAcknowledgementSent 이벤트도 내보내고 싶을 수도 있습니다.
바운디드 컨텍스트 내부의 도메인 이벤트 피하기
함수형 디자인에서 우리는 이 접근 방식이 숨겨진 종속성을 생성하기 때문에 사용하지 않는 것을 선호합니다.
대신 이벤트에 대한 "리스너"가 필요한 경우 다음과 같이 워크플로 끝에 추가하기만 하면 됩니다.
바운디드 컨텍스트 내부 핵심 구조
The Onion Architecture (오니온-헥사고날 아키텍처)
대신 도메인 코드를 중앙에 놓고 각 레이어가 더 멀리 있는 레이어가 아닌 내부 레이어에만 의존할 수 있다는 규칙을 사용하여 그 주위에 다른 측면을 조합하도록 합시다.
즉, 모든 종속성은 내부를 가리켜야 합니다. 이것을 "양파 아키텍처"라고 합니다.
(파라미터로 의존성을 먼저 주입받도록 하면 됨)
Keep I/O at the Edges - 입출력을 가장자리로
함수형 프로그래밍의 주요 목표는 내부를 볼 필요 없이 예측 가능하고 추론하기 쉬운 함수로 작업하는 것입니다.
이를 위해 가능한 한 불변 데이터로 작업하고 함수에 숨겨진 종속성 대신 명시적 종속성이 있는지 확인하려고 노력할 것입니다.
가장 중요한 것은 무작위성, 함수 외부 변수의 뮤테이션(수정), 모든 종류의 I/O를 포함하여 함수에서 부작용을 피하려고 노력하는 것입니다.
예를 들어, 데이터베이스나 파일 시스템을 읽거나 쓰는 기능은 "불순한" 것으로 간주되므로 핵심 도메인에서 이러한 종류의 기능을 피하려고 합니다.
그러면 어떻게 데이터를 읽거나 쓸 수 있습니까?
대답은 I/O를 양파의 가장자리로 푸시하는 것입니다.
예를 들어 워크플로 내부가 아니라 워크플로의 시작 또는 끝에서만 데이터베이스에 액세스합니다.
이것은 우리가 서로 다른 관심사를 분리하도록 강요하는 추가적인 이점이 있습니다.
코어 도메인 모델은 비즈니스 로직에만 관련되는 반면 지속성 및 기타 I/O는 인프라 관련 문제입니다.
실제로 I/O 및 데이터베이스 액세스를 에지로 이동하는 관행은 이전 장에서 소개한 지속성 무지(Persistene ignorance)의 개념과 매우 잘 맞습니다.
워크플로 내부에서 데이터베이스에 액세스할 수 없는 경우 데이터베이스를 사용하여 도메인을 모델링할 수 없습니다.
정리
- 도메인 개체는 데이터 전송 개체(DTO)와 달리 컨텍스트 경계 내에서만 사용하도록 설계된 개체입니다.
- 데이터 전송 개체(DTO)는 직렬화에 사용하고, 컨텍스트 간에 공유를 위해 설계된 개체입니다.
- Shared Kernel, Customer/Supplier 및 Conformist는 바운디드 컨텍스트 간의 다른 종류의 관계입니다.
- ACL(Anti-Corruption Layer)은 결합을 줄이고 도메인이 독립적으로 발전할 수 있도록 한 도메인에서 다른 도메인으로 개념을 변환하는 구성 요소입니다.
- 지속성 무지는 도메인 모델이 도메인 자체의 개념에만 기초해야 하며 데이터베이스 또는 기타 지속성 메커니즘에 대한 인식을 포함하지 않아야 함을 의미합니다.
'BackEnd' 카테고리의 다른 글
타입으로 코드 문서화하기 With F# - 타입을 조합하여 도메인 모델링 (0) | 2022.03.18 |
---|---|
타입으로 코드 문서화하기 With F# - 타입 기초 (0) | 2022.03.18 |
도메인 모델을 함수형 아키텍처로 - 컨텍스트 간 통신 1 (0) | 2022.03.17 |
도메인을 문서화하기 (0) | 2022.03.17 |
데이터베이스 주도 설계, 클래스 주도 설계 피하기 (0) | 2022.03.17 |