DDD(1) - 바운디드 컨텍스트 연동
- 바운디드 컨텍스트 간 소통과 통합을 구성하는 다양한 패턴
- 이러한 패턴은 바운디드 컨텍스트에서 작업하는 팀 간의 협력적 특성에 의해 주도됨
- 컨텍스트 맵
이 포스트에서는 연쇄적인 변경으로부터 스스로를 보호하는데 사용할 수 있는 바운디드 컨텍스트를 연동하기 위한 다양한 패턴에 대해 알아본다.
시스템 구성 요소를 연동하는 방법에 영향을 주는 기술적/조직적 제약 사항에 대해 알아보고, 다양한 상황과 제한을 다루는 연동 패턴에 대해 알아본다.
그리고 각 패턴이 소프트웨어 개발팀 간의 협업에 어떻게 영향을 미치는지에 대해 알아본다.
컨텍스트 맵은 도해적 방법으로 시스템의 바운디드 컨텍스트 사이에서 커뮤니케이션하는 방법을 구상하고, 프로젝트의 통합과 협업 환경의 조감도를 제공하는 역할을 한다.
바운디드 컨텍스트 패턴은 유비쿼터스 언어의 일관성을 유지하고, 모델링을 가능하게 해준다.
각 바운디드 컨텍스트의 모델은 서로 독립적으로 발전하고 구현될 수 있지만, 바운디드 컨텍스트 자체는 독립적이지 않다.
시스템의 구성 요소가 서로 상호 작용하듯이 바운디드 컨텍스트들도 서로 독립적으로 발전하되, 상호 작용해야 한다.
결국, 바운디드 컨텍스트 사이에는 항상 접점이 있는데 이를 컨트랙트(contract) 라고 한다.
각 컨트랙트는 하나 이상의 당사자에게 영향을 끼치므로 서로 조율해서 컨트랙트를 정의해야 한다.
바운디드 컨텍스트가 다르면 사용하는 유비쿼터스 언어도 다르다.
그렇다면 연동이 필요할 경우 컨트랙트는 어떤 언어를 사용해야 할 지에 대한 고민이 필요한데, 이렇게 연동에 대한 고민은 솔루션 설계에서 다루어져야 한다.
5. 바운디드 컨텍스트 간 관계 와 함께 보면 도움이 됩니다.
목차
- 1. 협력형(cooperation) 패턴 그룹
- 2. 사용자-제공자(Customer-Supplier) 패턴 그룹
- 3. 분리형 노선(Seperated Ways): 협업 대신 각자의 길을 선택
- 4. 발행된 언어(Published Language): 시스템 경계를 넘는 명확한 계약
- 5. 컨텍스트 맵
- 참고 사이트 & 함께 보면 좋은 사이트
1. 협력형(cooperation) 패턴 그룹
소통이 잘 되는 팀에서 구현된 바운디드 컨텍스트와 관련이 있다.
예) 단일 팀에 의해 구현된 바운디드 컨텍스트
1.1. 파트너십(Partnership) 패턴
파트너십은 두 개의 바운디드 컨텍스트를 담당하는 팀이 공동의 목표를 향해 긴밀하게 협력해야 하는 상황에서 사용되는 컨텍스트 매핑 패턴이다.
이 패턴은 특히 연동, 테스트, 출시 등에서 서로 실시간으로 조정과 협업이 필요할 때 효과적이다.
그러나 파트너십은 높은 동기화 비용과 팀 자율성 저하라는 단점도 있어서, 장기적인 유지보다는 전략적 단기 활용이 권장된다.
파트너십 패턴은 두 팀이 상호 의존적인 관계로, 공통이 목표를 위해 ad-hoc 방식으로 조율하며 함께 일하는 매핑 전략이다.
- 양방향 연동 조율
- 연동 바익이 계획된 계약 기반(API 스펙 등)이 아니라, 그때그때 협의를 통해 ad-hoc 으로 조정됨
- 높은 협업 의지와 실행력 필요
- API 변경, 릴리스, 테스트 타이밍 등을 수시로 동기화해야 함
- 상호 책임 공유
ad-hoc
사전에 정의된 명세없이 상황에 따라 유동적으로 조정되는 방식
예) 한 팀이 API 를 수정하고 이를 슬랙이나 미팅을 토해 즉각적으로 공유 → 상대 팀이 신속히 반영
명시적 계약(API 명세, 인터페이스 버전 관리)이 부족하므로, 긴밀한 커뮤니테이션이 생명
<파트너십의 장점>
- 강력한 협업 기반의 문제 해결
- 복잡한 도메인을 빠르게 통합하고 시도할 수 있는 실행력 제공
- 초기 설계 및 실험에 적합
- 모델이 안정되지 않은 상태에서 함께 탐색하고 개선 가능
<파트너십의 단점과 제약>
- 자율성 저하
- 한 팀이 독립적으로 일하기 어렵고, 다른 팀의 일정과 정책에 영향을 받음
- 운영 부담 증가
- 동기화와 조율에 대한 커뮤니케이션 코스트가 매우 높음
- 지리적 분산 환경에 부적합
- 다른 시간대나 물리적 거리에 있는 팀은 실시간 협업이 어려움
<전략적 활용 가이드>
- 사용 시점
- 두 컨텍스트가 아직 도메인적으로 밀접하게 연동되어야 할 초기 단계
- 회피 시점
- 시스템이 어느 정도 안정되고, 변경 빈도가 낮아졌을 때
- 전환 전략
- ACL, Open-Host Service, Published Language 등으로 전환 고려
파트너십 패턴은 짧은 거리에서 빠르게 달릴 때 유리한 단거리 러너같은 전략이다.
마라톤 같은 장기 운영을 위해서는 더 안정적이고 명확한 계약 기반 매핑으로 전환하는 것이 조직과 시스템에 더 유리하다.
1.2. 공유 커널(Shared Kernel) 패턴
공유 커널은 둘 이상의 팀이 특정 도메인 모델의 일부를 공통의 계약 아래 공유하는 컨텍스트 매핑 전략이다.
바운디드 컨텍스트 간의 의존성을 줄이고 독립성을 높이는 것이 DDD 의 핵심이지만, 현실적으로는 공통적으로 사용되는 도메인 모델이 존재하며, 이를 분리된 채 유지하는 것보다 공유하는 편이 더 효율적일 수 있다.
공유 커널은 둘 이상의 바운디드 컨텍스트가 합의한 작은 모델을 공유하는 매핑 전략으로,
- 하나의 모델을 여러 팀이 함께 사용함
- 공유된 모델은 각 컨텍스트의 유비쿼터스 언어에 자연스럽게 녹아들어야 함
- 일반적으로 권한, 통화, 사용자 ID 같은 핵심 개념 또는 불변성 있는 구조에 적용
<공유 커널의 구조적 특징>
- 공유 범위는 최소화되어야 함
- 모델 전체가 아닌, 진짜로 겹치는 핵심 영역만 공유
- 공유 커널의 범위가 넓을수록 변경 전파 비용과 의존성 증가
- 변경은 즉시 모든 컨텍스트에 영향
- 단일 저장소를 사용할 경우 → 직접 코드 참조
- 저장소가 분리되어 있다면 → 공유 커널을 외부 라이브러리 형태로 관리하고 각 팀이 버전별로 참조
- 공유 커널은 별도의 바운디드 컨텍스트가 아님
- 공유 커널은 논리적 개념이지, 독립된 도메인 또는 서비스로 관리되지 않음
- ‘통화’, ‘권한’ 등은 각 컨텍스트의 일부로 흡수되는 구조
<공유 커널 적용 시 고려할 전략적 기준>
- 중복 비용 vs 조율 비용
- 중복 비용이 크고, 모델 변경이 거의 없는 경우 → 공유 커널 도입 적합
- 모델이 자주 변경된다면 → 커플링 증가로 인해 조율 비용 과도해짐
- 즉, 중복 유지 비용 > 조율 비용인 경우에 적용
- 변동성(Volatility) 이 핵심 판단 요소
- 변경 가능성이 낮은 모델(예: 사용자 ID, 국가 코드 등) 은 공유하기 좋음
- 자주 바뀌는 비즈니스 규칙은 공유 대상에서 제외
<공유 커널 적용 사례>
- 파트너십이 어려운 경우
- 지리적 분산, 조직 문제 등으로 긴밀한 협업이 힘들 때 대안
- 레거시 현대화 시도 중
- 기존 시스템을 점진적으로 바운디드 컨텍스트로 분해할 때 중간 전략으로 사용
- API 계약보다 모델 공유가 더 자연스러운 경우
- 데이터 구조를 공유해야 할 필요가 명확한 경우 (예: ‘통화’ 모델)
<반패턴: 공유 커널로 인한 강한 커플링>
- 외부 이벤트를 그대로 공유 커널에 포함시키면, 이벤트를 생성하는 도메인과 소비하는 도메인 사이에 강한 의존성이 생김
- 이는 모델 간 경계를 침식시키고, 결과적으로 유비쿼터스 언어를 오염시킴
- 외부의 이벤트는 커맨드/쿼리 형태로 명시적 메시지로 변환해서 수신하는 것이 바람직함
공유 커널은 전략적으로 아주 신중하게 적용해야 한다.
도메인 경계를 침범하지 않으면서도 공동의 표준을 형성할 수 있을 때, 이 패턴은 도메인 간 안전성과 통합성을 동시에 가져다준다.
2. 사용자-제공자(Customer-Supplier) 패턴 그룹
사용자-제공자 패턴은 바운디트 컨텍스트 간 통합 전략 중, 한 쪽이 서비스를 제공하고, 다른 쪽이 이를 소비하는 구조를 가지는 관계이다.
제공자는 업스트림 팀, 소비자는 다운스트림 팀으로 불리며, 이들 간에는 권한과 의존성의 불균형이 존재한다.
사용자-제공자 패턴은 하나의 팀(다운스트림)이 다른 팀(업스트림)이 제공하는 도메인, 서비스, API 를 사용하는 구조의 매핑 전략이다.
- 업스트림
- 공급자 역할을 하며, 도메인 설계와 API 형식을 주도함
- 다운스트림
- 사용자 역할을 하며, 업스트림이 제공하는 서비스에 맞춰 개발을 진행함
- 의존성은 단방향
- 다운스트림은 업스트림을 의존하지만, 그 반대는 아님
<문제가 발생하는 상황>
- 업스트림이 예고없이 프로토콜, 스키마를 변경
- 다운스트림은 예기치 않은 오류나 대응 비용 발생
- 신뢰 관계 약화, 통합 안정성 하락
- 지원 책임 불명확
- 다운스트림은 지원을 요청해도 받지 못하고, 업스트림은 개선을 강요당함
<바람직한 협업을 위한 전략>
- 공식적인 사용자-제공자 관계 설정
- 두 팀이 역할과 책임을 명확히 정의해야 함
- 연동 컨트랙트에 대한 사전 합의와 변경 관리 체계 마련
- 다운스트림은 공급자가 자신들만을 상대하는 것이 아니라는 점을 이해하고 현실적인 기대 수준 유지
- API/데이터 형식의 표준화
- 업스트림이 자신의 인터페이스에 대한 표준을 수립하고 공유하면, 모든 다운스트림 팀이 안정적으로 통합 가능
- 신뢰 기반의 소통
- 정직한 피드백과 문서화된 연동 컨트랙트를 통해 예측 가능한 통합 환경 조성
즉, 다운스트림의 자율성과 예측 가능성을 보장하기 위해 명확한 연동 컨트랙트와 신뢰 기반 소통 체계가 반드시 필요하다.
연동 컨트랙트
API 스펙, 데이터 형식, 메시지 구조 등 양측 간 통신을 위한 명세
<파트너십과의 차이점>
항목 | 파트너십 | 사용자-제공자 |
---|---|---|
관계 구조 | 동등 | 비대칭 |
연동 주도권 | 공동 결정 | 업스트림이 주도 |
커뮤니케이션 빈도 | 매우 높음 | 중간~낮음 (명세 중심) |
독립성 | 낮음 | 업스트림은 높음, 다운스트림은 낮음 |
추천 사용 시점 | 초기 실험/동기화 필요 | 안정화 이후 분리 가능한 경우 |
파트너십에서 사용자-제공자 패턴으로 전환하는 것은 하나의 자연스러운 성장 경로이다.
2.1. 순응주의자(Conformist) 패턴
순응주의자 패턴은 업스트림 팀이 제공하는 모델에 대해 다운스트림 팀이 자체적인 해석이나 조정없이 그대로 따르는 전략이다.
이는 힘의 불균형이 분명할 때 선택되며, 사용자-제공자 패턴의 하위 유형 중 하나이다.
- 다운스트림 팀은 업스트림 팀이 제공하는 API, 데이터 형식, 유비쿼터스 언어를 그대로 사용
- 자신의 도메인에 맞게 변환하거나 번역하는 계층을 만들지 않음
- 실질적으로는 다운스트림이 기능과 개발 방향에서 자율성을 잃음
<순응주의자 패턴이 나타나는 상황>
- 힘의 불균형
- 업스트림이 조직적, 기술적으로 우위에 있고 다운스트림의 요구를 고려하지 않음
- 이해와 역량의 부족
- 다운스트림 팀이 업스트림 모델을 충분히 이해하거나 해석할 수 없음
- 비용 대비 효과 낮음
- 해석 계층을 따로 만들기엔 리소스가 부족하거나 리스크가 큼
- 외부 서비스 연동
- 외부 SaaS, API 제공자와의 연동에서 흔히 발생
- 예) 외부 결제 API, 외부 인증 시스템과의 연동
<구조와 통합 방식>
- 다운스트림은 업스트림의 유비쿼터스 언어와 도메인 모델을 그대로 수용
- 구조나 속성 이름, 데이터 표현 방식이 1:1로 대응
- 별도의 변환 계층없이 통합되므로, 연동 자체는 상대적으로 단순함
<장점>
- 빠른 통합 가능
- 별도의 해석/변환 작업 없이 바로 연동 가능
- 리스크 최소화
- 구현 난이도와 복잡도 낮음
- 현실적인 절충
- 자율성이 낮더라도 빠르게 서비스와 연결 가능
<단점>
- 모델 간격이 좁혀지지 않음
- 다운스트림이 도메인 언어와 설계를 왜곡당함
- 강한 종속성
- 업스트림이 바뀔 때마다 다운스트림이 직접 영향을 받음
- 향후 리팩토링 부담
- 장기적 기술 부채로 이어질 수 있음
<적용 전략 및 리스크 완화 방안>
- 변경 계획 공유
- 업스트림의 모델 변경 일정에 미리 접근하여 사전 대응
- 의사소통 강화
- 완전한 순응 상태라도 지속적인 협의 창구를 마련
- 핵심 도메인과는 분리
- 순응주의자 모델은 핵심 도메인 밖에서만 제한적으로 적용
- 중요한 도메인이라면 ACL 또는 자체 모델 번역 계층을 고려해야 함
순응주의자 패턴은 때로는 가장 현실적인 선택지가 되기도 하지만, 다운스트림의 자율성과 유비쿼터스 언어를 희생하는 결정인 만큼, 명확한 판단과 사전 조율, 전략적 전환 계획이 필요하다.
2.2. 충돌 방지 계층(ACL: AntiCorruption Layer) 패턴
부패 방지 계층이라고도 한다.
충돌 방지 계층은 외부 도메인(업스트림)의 모델이 내부 도메인(다운스트림)을 오염시키지 않도록 보호하는 전략적 완충 계층이다.
업스트림의 데이터와 메시지를 받아들일 때, 이를 그대로 사용하지 않고 자체의 유비쿼터스 언어와 구조에 맞게 변환하여 수용한다.
충돌 방지 계층은 외부 모델(업스트림)을 내부 도메인(다운스트림)에 직접 노출시키지 않고, 중간 계층에서 변환하여 통합하는 패턴이다.
- 다운스트림은 자신의 언어와 모델을 유지하면서 업스트림과의 연동을 수행
- 데이터 번역기 역할을 수행하는 계층을 별도로 구성함
충돌 방지 계층은 오픈 호스트 서비스와는 다른 방식으로 복잡성을 관리한다.
ACL 은 특히 다른 바운디드 컨텍스트와의 연동 시 복잡성을 줄이는데 특화되어 있다.
ACL 은 바운디드 컨텍스트 간 직접 연동을 피하고, 중간 계층에서 모델/언어/인터페이스 차이를 조정해주는 역할을 한다.
즉, 바운디드 컨텍스트 A 가 컨텍스트 B 를 사용할 때 A 가 B 를 직접 참조하는 대신 A 와 B 사이에 ACL을 두어 연동을 추상화한다.
ACL 은 로컬 복잡성과 글로벌 복잡성 모두를 낮춰주는 장점이 있다.
복잡성 유형 | ACL 의 효과 |
---|---|
로컬 복잡성 | 도메인 내부에서 외부 시스템의 영향을 격리시킴 |
글로벌 복잡성 | 시스템 전반의 연동 구조를 단순화하고 결합도를 낮춤 |
ACL 은 바운디드 컨텍스트 내부의 비즈니스 로직과 외부 연동의 복잡성을 명확히 분리해준다.
연동 과정에서 생기는 복잡성은 ACL 이 모두 책임지기 때문에 실제 도메인 모델은 외부 변화로부터 보호된다.
ACL 은 컨텍스트 간의 충돌을 막는 방화벽이다.
비즈니스 로직을 외부 변화로부터 보호하고, 연동을 우연하게 관리할 수 있도록 돕는다.
ACL 서비스는 바운디드 컨텍스트를 사용하는 로컬 복잡성과 시스템의 글로벌 복잡성을 모두 줄여준다.
ACL 서비스가 바운디드 컨텍스트를 사용할 때의 비즈니스 복잡성과 연동할 때의 복잡성을 분리해준다. 연동의 복잡성은 ACL 서비스가 담당한다.
<충돌 방지 계층을 사용하는 경우>
조건 | 설명 |
---|---|
다운스트림이 핵심 하위 도메인일 경우 | 외부 영향으로부터 내부 모델 보호가 최우선 |
업스트림 모델이 불완전하거나 비효율적일 경우 | 다운스트림 요구에 맞지 않는 구조를 필터링 |
업스트림의 변경 빈도가 잦을 경우 | 구조적 격리를 통해 영향 최소화 가능 |
다운스트림이 자체 언어를 정립할 수 있는 역량이 있을 경우 | 변환 계층을 구축할 여력이 있어야 함 |
<순응주의자 패턴과의 차이>
항목 | 순응주의자 | 충돌 방지 계층 |
---|---|---|
모델 사용 방식 | 업스트림 모델을 그대로 사용 | 업스트림 모델을 다운스트림 모델로 변환 |
자율성 | 거의 없음 | 높은 자율성 |
유지보수 | 단기 간편, 장기 부채 | 초기 비용 높지만 장기적으로 안정 |
유비쿼터스 언어 | 업스트림 중신 | 다운스트림 중심 |
변경 대응 | 수동적으로 대응 | 능동적으로 번역하고 보호 |
즉, 충돌 방지 계층은 순응주의자의 정반대 접근이다.
<구성 요소>
- Translator / Mapper
- 업스트림 모델을 다운스트림 모델로 변환하는 계층
- Adapter
- 외부 인터페이스를 내부 시스템과 연결
- Facade / Gateway
- 다운스트림 내부에서 충돌 방지 계층을 사용하는 진입점
<장점>
- 내부 도메인을 외부 영향으로부터 보호
- 다운스트림의 모델 독립성과 자율성 보장
- 시스템 진화 시 유연성 확보
<단점>
- 구현 비용과 복잡도 증가
- 번역 계층 유지 보수 필요
- 팀의 역량과 시간 리소스가 충분해야 함
<충돌 방지 계층 적용 예시>
- 외부 결제 시스템에서 수신한 메시지를 내부 도메인 언어(예: 결제완료됨)으로 해석하는 계층
- 레거시 시스템의 Order 구조를 최신 도메인 모델의 PurchaseRequest 로 변환
충돌 방지 계층을 구현하는 방법에 대해서는 1. 모델 변환 을 참고하세요.
충돌 방지 계층은 단지 보호 계층이 아니다.
이 계층을 통해 다운스트림은 자신의 도메인을 지키면서도 미래에 보다 나은 모델로 발전시킬 수 있는 시간과 유연성을 확보할 수 있다.
즉, 충돌 방지 계층은 “당장 순응하지 않고, 천천히 이상적인 구조로 진화할 수 있는 자유”를 주는 도구이다.
2.3. 오픈 호스트 서비스(OHS: Open-Host Service) 패턴: 외부 연동을 위한 개방형 전략
오픈 호스트 서비스 패턴은 하나의 바운디드 컨텍스트가 자신들의 내부 모델을 외부팀과 안전하고 유연하게 연동하기 위해 퍼블릭 API 를 제공하는 전략이다.
이 패턴은 특히 다운스트림 팀의 요구가 명확하거나 다양해지는 상황에서 업스트림 팀이 주도적으로 연동 인터페이스를 설계할 필요가 있을 때 유용하다.
오픈 호스트 서비스는 자신의 바운디드 컨텍스트 모델을 외부 팀들이 접근할 수 있도록 API 로 안전하게 노출하는 방식이다.
오픈 호스트 서비스는 단순히 API 를 노출하는 것이 아니라, 시스템 경계를 명확히 하고 도메인을 보호하면서도 사용자 요구에 응답하는 전략적 패턴이다.
특히 다양한 팀이 같은 정보를 공유하거나 접근할 필요가 있는 경우, 오픈 호스트 서비스는 가장 안전하고 지속가능한 해법이 될 수 있다.
오픈 호스트 서비스는 바운디드 컨텍스트 내부 모델을 직접 노출하지 않고, 공표된 언어를 통해 명확하고 제한된 연동 인터페이스를 제공함으로써 시스템의 복잡성을 효과적으로 제어한다.
- 내부 도메인 모델과 외부 노출 모델을 분리
- API 는 공표된 언어를 사용
- 연동의 핵심은 유비쿼터스 언어가 아닌 연동 지향 언어로 설계된 명시적 인터페이스
<오픈 호스트 서비스가 필요한 상황>
- 사용자 요구가 명확하거나 다양할 때
- 다양한 다우스트림 팀들이 존재하며, 공통의 방식으로 정보를 얻고자 함
- 사용자 측이 더 많은 권한과 영향력을 가지는 경우
- 소비자 중심 계약, 사용자 주도 기능 정의
- 모델 보호가 필요한 경우
- 내부 구현 모델은 외부에 노출하지 않고, 안정적인 퍼블릭 인터페이스만 제공
- 외부에 제공되는 퍼블릭 모델과 그 내부 구현을 다른 속도로 발전시킬 수 있음
- 내부 구현 모델은 외부에 노출하지 않고, 안정적인 퍼블릭 인터페이스만 제공
연동 모델은 퍼블릭 인터페이스와 발행된 언어로 구현되어야 한다.
즉, API 는 내부 유비쿼터스 언어가 아닌, 외부 팀과의 연동에 최적화된 공표된 언어로 설계한다.
내부 도메인 변경이 퍼블릭 API 에 영향을 주지 않도록 계층을 구분한다.
(내부 모델) → (번역 계층) → (퍼블릭 API: 공표된 언어)
너무 일찍 알게 되는 경우
- 업스트림이 될 준비가 되지 않은 상태에서 다른 팀이 모델 사용 의사를 보임
- API 를 준비하지 않은 상태에서 DB 접근을 허용하는 것은 절대 금물
- 데이터 훼손, 비공식 의존성 증가, 시스템 성능 저하 발생 가능
- 대응 전략
- 기본 API 만 제공하고 점진적으로 개선
- 다른 다운스트림 팀들과 인터뷰 후 요구사항 탐색
너무 늦게 알게 되는 경우
- 조직 내 커뮤니케이션 문제로 인해 갑작스러운 연동 요청 발생
시간 부족으로 급조된 API 제공으로 품질 저하 위험
- 예방 전략
- 매주 짧은 작업 공유 회의 운영
- 각 팀은 지금 작업 중인 과제가 어떤 가치를 갖는지, 현재 겪고 있는 어려움은 무엇인지, 과제를 완수하기 위해 필요한 사항은 무엇인지 공유
- 리드 엔지니어 중심의 통합 원칙 수립 및 통제
- 기술적 마일스톤 중심 협업 구조 운영
- 매주 짧은 작업 공유 회의 운영
이럴 때는 단기적으로 부족한 기능만이라도 다운스트림 팀에서 모델 접근을 제공해주는 방법이 있다.
아주 단순한 REST API 라면 두 팀 모두 큰 노력없이 구축이 가능할 것이다.
API 설계 시 고려사항
계획하고 구현하는데 많은 시간이 주어지지 않는다고 하더라도 API 를 제공하는 것을 주저해서는 안된다. 완성도가 떨어지더라도 일단 통합의 깃발을 들고 밀고 나가야 한다.
서비스 API 를 제공할 때 주목할 문제는 어떤 규격으로 정보를 교환할 것이냐는 것이다. 이는 발행된 언어 를 통해 해결할 수 있다.
- 쿼리 API
- 읽기 전용 API 로 다양한 팀이 조회 가능하게 제공
- 이벤트 스트림
- 다운스트림이 필요한 변경사항만 실시간 수신 가능
- 스냅샷 제공
- 업스트림의 데이터를 다운스트림이 쿼리해서 처리하는 동안 업스트림의 데이터가 변하지 않는다는 보장을 할 수 없으므로,
- API 호출 시점의 불일치 문제 방지를 위한 스냅샷 전략
- 미니멀 API 제공
- 처음에는 꼭 필요한 기능한 노출, 점직적으로 확장
- 소비자 주도 계약
- 소비자가 직접 요구사항을 명세 → API 발전 방향 주도
<오픈 호스트 서비스 vs DB 접근>
항목 | API 방식 | DB 접근 공유 |
---|---|---|
보안 | 높음 (권한 통제, 로그 추적) | 낮음 (임의 조작 위험) |
유연성 | 모델 격리 가능, 진화 가능 | 테이블 변경 시 큰 영향 |
확장성 | 다양한 팀 요구에 대응 가능 | 설계 변경이 어려움 |
의존성 관리 | 명확함 | 불투명함 |
DB 직접 접근은 단기 편의, 장기적 혼란의 씨앗이다.
3. 분리형 노선(Seperated Ways): 협업 대신 각자의 길을 선택
분리형 노선 패턴은 두 바운디드 컨텍스트가 통합을 시도하지 않고, 각자의 모델과 구조로 완전히 독립적인 구현을 선택하는 전략이다.
이는 협업의 어려움, 통합에 대한 투자 대비 효과 부족, 모델 간의 극단적 불일치 등의 이유로 발생한다.
- 일회성 연동 혹은 아예 연동없는 독립적인 개발
- 다운스트림은 업스트림을 따르지 않으며, 각자 독립적인 모델/서비스 구축
- 협업을 회피하거나, 협업보다 기능 중복이 더 효율적이라고 판단될 때 선택
<적용 조건>
- 통합 비용 > 기대 이득
- 통합에 필요한 조율/협업 비용이 너무 큼
- 협업 불가능
- 커뮤니케이션 단절, 정치적 장벽 등으로 인한 협업 불가
- 모델 호환성 없음
- 도메인 모델이 너무 달라 충돌 방지 모델조차 비용 과다
- 일반 하위 도메인
- 핵심 도메인이 아닌 경우 기능 중복 허용 가능
핵심 하위 도메인에서는 분리형 노선을 선택하면 안된다.
- 핵심 하위 도메인 간 중복 구현은 회사의 전략을 비효율화시킴
- 장기적으로 기술 부채, 유지보수 비용 증가로 이어질 수 있음
- 핵심 기능은 반드시 파트너십, 충돌 방지 계층 등으로 정제된 통합 방식 권장
<분리형 노선의 리스크>
- DRY(Don’t Repeat Yourself) 위반
- 기능 증복, 데이터 중복, 유지보수 중복
- DRY 원칙은 코드의 중복이 아니라 지식의 중복을 피하라는 의미임
- 사일로화
- 다른 팀이 어떤 기능을 갖고 있는지 모르게 되어 협업 기회 상실
- 전사적 전략 부재
- 중복이 시스템 전반의 통일성을 깨고, 확장성 저해
3.1. 커뮤니케이션 이슈
조직 구조상 협업이 어려운 경우이다.
- 대규모 조직, 분산된 팀, 문화적 장벽 등으로 인해 팀 간 협의가 매우 어려운 경우
- 통합보다 기능 중복이 더 빠르고 저렴할 수 있음
예) 본사와 해외 지사가 각자 로컬 고객 관리 시스템을 만드는 경우
3.2. 일반 하위 도메인
로깅, 모니터링, 서드파티 연동 등의 일반 하위 도메인인 경우이다.
- 로깅 프레임워크를 하나의 컨텍스트에서 서비스화하면 의존성과 복잡도만 증가
- 각 컨텍스트가 로컬로 독립 연동하는 것이 더 단순하고 안전
예) 카프카 클러스터에 각 컨텍스트가 직접 로깅 프로듀서로 접근
3.3. 모델의 차이
모델 차이가 너무 커서 연동이 불가한 경우이다.
- 순응주의자 패턴도 안되고, 충돌 방지 계층 비용도 너무 높은 경우
- 도메인 간 의미, 구조, 목적이 완전히 다름
예) 하나는 이벤트 소싱 기반, 하나는 정적 파일 기반 모델을 사용하는 경우
4. 발행된 언어(Published Language): 시스템 경계를 넘는 명확한 계약
발행된 언어는 서로 다른 바운디드 컨텍스트 간의 정보 교환을 위한 표준화된 스키마 기반 언어이다.
이는 DDD 에서 연동 지향 모델링을 위한 핵심 도구로, 이벤트, 커맨드, 쿼리 등 외부와 주고받는 모든 메시지에 대한 공통 규약을 정의한다.
특히 오픈 호스트 서비스나 충돌 방지 계층과 함께 사용할 때, 시스템 간의 커플링을 줄이고, 통합 복잡도를 줄이며, 각자의 도메인 독립성을 유지하는데 중요한 역할을 한다.
발행된 언어는 컨텍스트 간 통신을 위한 명시적이고 안정된 메시지 포맷 및 스키마의 집합이다.
단순한 메시지 포맷을 넘어, 여러 컨텍스트가 안정적으로 협력할 수 있는 기반 언어이다.
복잡한 시스템 간 통합을 설계할 때, 가장 먼저 정의해야 할 요소는 바로 발행된 언어이다.
- 메시지 구조, 필드 정의, 예외 케이스 등이 스키마 형태로 명확히 문서화
- JSON, Avro, Protobuf 등의 형식적 언어로 구현
- 외부 연동에 사용하는 커맨드, 쿼리, 이벤트 등에 적용 가능
<발행된 언어가 필요한 이유>
문제 | 해결책 |
---|---|
형식이 불명확한 메시지 → 해석 오류 다발 | 명시적 메시지 스키마 제공 |
내부 구조 변경 시 외부 시스템 충돌 | 외부 인터페이스의 안정적 유지 기능 |
연동 복잡도 증가 | 명확한 계약 기반 통신으로 설계 간결화 |
<기대 효과>
- 시스템의 글로벌 복잡성 감소
- 여러 팀, 여러 시스템이 하나의 언어로 소통 → 표준화된 통신 체계 구축
- 내부 유연성 확보
- 내부 로직이나 데이터 구조를 변경해도 외부 연동 포맷을 그대로 유지 가능
- 안정된 통합 경험 제공
- 사용자에게 영향을 주기 않고 내부 로직 진화 가능
<발행된 언어 구성요소>
- 메시지 스키마
- 이벤트/쿼리/커맨드의 포맷 정의
- 버전 관리
- 스키마의 변화에 대응하기 위한 명세 버전 관리
- 문서화
- API문서 혹은 스키마 명세서로 외부에 명확히 전달
오픈 호스트 서비스와의 연계
오픈 호스트 서비스는 내부 도메인과 연동 모델을 연결하는 브리지이며, 발행된 언어를 이 브리지가 사용하는 공용 언어(프로토콜)이다.
(내부 도메인 모델) → (오픈 호스트 서비스 API) → (발행된 언어) → (외부 팀)
API 설계 시 내부 유비쿼터스 언어 대신 발행된 언어 기반 포맷을 사용한다.
비즈니스 로직 변경 시에도 내부는 진화, 외부는 안정이라는 이상적 상태를 유지할 수 있다.
5. 컨텍스트 맵
컨텍스트 맵은 단순히 다이어그램이 아니라 협업과 통합 전략을 가시화하여 조직적 정렬을 돕는 도구이다.
- 팀 간 소통 구조 제공
- 각 컨텍스트를 담당하는 팀 간의 실제 관계와 기대치를 정리
- 사고 및 학습의 틀 제공
- 설계, 실험, 실패, 개선의 흐름을 구조적으로 표현
- 통합 요구 사항 도출
- 데이터 흐름, 인터페이스, API 연결 등의 통합 상황을 명확히 파악
- 조직적 문제
- 컨텍스트 맵은 조직적 문제에 대한 통찰력을 제공함
- 특정 제공자 팀의 사용자가 모두 충돌 방지 계층을 구현하거나 분리형 노선 패턴의 모든 구현이 한 팀에 집중된다면 그 팀은 눈여겨 볼 필요가 있음
컨텍스트 맵은 추상적인 모델링 도구가 아니라, 실제 소스코드와 팀의 협업 방식에 구체적으로 반영되는 전략이다.
즉, 컨텍스트 맵은 “누가 무엇을 공유하고, 누구에게 의존하며, 어떤 방식으로 통합이 이루어지는가”를 명확히 보여준다.
참고 사이트 & 함께 보면 좋은 사이트
본 포스트는 블라드 코노노프 저자의 도메인 주도 설계 첫걸음과 반 버논, 토마스 야스쿨라 저자의 전략적 모놀리스와 마이크로서비스를 기반으로 스터디하며 정리한 내용들입니다.