DDD 이론 5: Context Mapping 심화
9가지 Context Map 패턴의 심층 분석, Team Topologies 연계, 실제 기업 사례와 실습을 통해 대규모 시스템의 통합 전략을 마스터합니다.
- • Context Map의 본질과 전략적 가치를 이해한다
- • 9가지 Context Mapping 패턴을 깊이 있게 분석하고 적용할 수 있다
- • Open Host Service와 Published Language의 실무 구현 방법을 익힌다
- • Team Topologies와 Context Mapping의 연계를 이해한다
- • Context Map 시각화 도구와 문서화 방법을 활용할 수 있다
- • Context Map의 진화와 마이그레이션 전략을 수립할 수 있다
- • Netflix, Amazon, Shopify 등 실제 기업 사례를 분석할 수 있다
- • 대규모 시스템의 Context Map을 직접 설계할 수 있다
1. Context Map의 본질과 목적
"Context Map은 프로젝트에 관련된 Bounded Context들과 그들 사이의 관계를 보여주는 문서다. 이것은 현재 상태를 있는 그대로 보여줘야 한다. 이상적인 상태가 아니라."
— Eric Evans, Domain-Driven Design, Chapter 14
1.1 Context Map이란?
Context Map은 시스템 내 모든 Bounded Context와 그들 간의 관계를 시각화한 전략적 설계 도구입니다. 단순한 아키텍처 다이어그램이 아니라, 팀 간의 관계, 권력 구조, 통합 전략을 명시적으로 드러내는 문서입니다.
🗺️ 기술적 측면
- • 시스템의 Bounded Context 목록
- • Context 간 데이터 흐름 방향
- • 통합 방식 (API, 이벤트, 공유 DB 등)
- • 의존성 방향과 강도
👥 조직적 측면
- • 팀 간의 협력 관계
- • 권력과 협상력의 분포
- • 의사결정 권한
- • 커뮤니케이션 패턴
1.2 왜 Context Map이 필요한가?
현실 파악
시스템의 실제 상태를 명확히 이해. 숨겨진 의존성과 암묵적 결합을 발견.
커뮤니케이션 도구
팀 간, 이해관계자 간 공통 언어 제공. 복잡한 시스템을 한눈에 설명.
전략적 의사결정
어디에 투자할지, 어떤 통합 전략을 선택할지 결정하는 기반.
리스크 식별
단일 장애점, 병목 지점, 과도한 결합 등 잠재적 문제 발견.
진화 계획
현재 상태에서 목표 상태로의 마이그레이션 경로 계획.
1.3 Context Map vs 다른 다이어그램
| 다이어그램 | 초점 | Context Map과의 차이 |
|---|---|---|
| 시스템 아키텍처 | 기술 컴포넌트, 인프라 | 팀 관계, 통합 패턴 미포함 |
| ERD | 데이터 구조, 관계 | 비즈니스 경계, 소유권 미포함 |
| 서비스 맵 | 서비스 간 호출 관계 | 협력 패턴, 권력 관계 미포함 |
| 조직도 | 팀 구조, 보고 체계 | 시스템 경계, 기술 통합 미포함 |
| Context Map | 비즈니스 경계 + 팀 관계 + 통합 전략 | 전략적 관점의 통합 뷰 |
"Context Map은 기술적 다이어그램이 아니다. 그것은 조직의 정치적 지형도다. 누가 누구에게 의존하는지, 누가 협상력을 가지는지를 보여준다."
— Alberto Brandolini, Event Storming 창시자
💡 실무 인사이트
많은 팀이 Context Map을 "있으면 좋은 문서" 정도로 생각합니다. 하지만 실제로는 전략적 의사결정의 핵심 도구입니다. 새로운 기능을 어느 Context에 배치할지, 어떤 팀과 협력해야 할지, 외부 시스템을 어떻게 통합할지 등의 결정에 Context Map이 필수입니다.
2. Context Mapping 패턴 심화
4장에서 9가지 패턴을 개괄적으로 살펴봤습니다. 이번 섹션에서는 각 패턴의실제 구현 방법, 트레이드오프, 진화 전략을 심층적으로 다룹니다.
2.1 협력 패턴 심화
두 팀이 공동의 목표를 위해 긴밀하게 협력하는 관계. 인터페이스 변경 시 함께 조율하고, 함께 성공하거나 함께 실패합니다.
성공 조건
- • 두 팀이 같은 관리자 아래 있거나 긴밀한 관계
- • 공동 스프린트 계획, 동기화된 릴리스
- • 정기적인 합동 회의 (주 1회 이상)
- • 공유된 성공 지표 (KPI)
실패 신호
- • 한 팀이 다른 팀을 기다리며 블로킹
- • 인터페이스 변경 시 갈등 발생
- • 책임 전가, 비난 문화
- • 릴리스 일정 불일치
구현 패턴
// Partnership: 공유 인터페이스 정의
// 두 팀이 함께 소유하고 변경
// shared-contracts/order-payment.ts
export interface OrderPaymentContract {
// 버전 관리로 호환성 유지
version: '2.0';
// 주문 → 결제 요청
initiatePayment(request: PaymentRequest): Promise<PaymentInitiated>;
// 결제 → 주문 콜백
onPaymentCompleted(callback: PaymentCompletedHandler): void;
onPaymentFailed(callback: PaymentFailedHandler): void;
}
// 변경 프로세스:
// 1. 두 팀이 함께 인터페이스 변경 논의
// 2. 공유 저장소에 PR 생성
// 3. 양쪽 팀 리뷰 및 승인
// 4. 동시 배포 또는 하위 호환 유지⚠️ 주의: Partnership의 함정
Partnership은 유지 비용이 높습니다. 팀 간 조율에 많은 시간이 소요되고, 한 팀의 지연이 다른 팀에 직접 영향을 줍니다.정말 필요한 경우에만 선택하세요.
두 Context가 도메인 모델의 일부를 공유합니다. 공유 부분의 변경은 양쪽 팀의 합의가 필요합니다.
공유 커널 구조
// shared-kernel/
├── domain/
│ ├── Money.ts // 금액 Value Object
│ ├── Address.ts // 주소 Value Object
│ ├── DateRange.ts // 기간 Value Object
│ └── PersonName.ts // 이름 Value Object
├── events/
│ ├── DomainEvent.ts // 기본 이벤트 인터페이스
│ └── EventMetadata.ts // 이벤트 메타데이터
└── types/
├── Result.ts // 결과 타입 (성공/실패)
└── EntityId.ts // ID 기본 타입
// 사용 예시
import { Money, Address } from '@company/shared-kernel';
class Order {
constructor(
private readonly totalAmount: Money, // 공유 커널
private readonly shippingAddress: Address // 공유 커널
) {}
}공유해도 좋은 것
- • 범용 Value Object (Money, Address)
- • 기본 이벤트 인터페이스
- • 공통 유틸리티 타입
- • 변경 빈도가 낮은 것
공유하면 안 되는 것
- • Entity (식별성이 Context마다 다름)
- • 비즈니스 규칙
- • Context 특화 로직
- • 자주 변경되는 것
"Shared Kernel은 가능한 작게 유지하라. 공유하는 것이 많아질수록 두 팀의 자율성은 줄어든다."
— Eric Evans
2.2 상류/하류 패턴 심화
Upstream(공급자)이 Downstream(고객)의 요구사항을 수용하는 관계.고객의 요구가 공급자의 백로그에 반영됩니다.
협력 프로세스
Customer-Supplier 협력 프로세스: 1. 요구사항 수집 Downstream 팀 → Upstream 팀에 API 요구사항 전달 2. 우선순위 협상 양 팀이 함께 우선순위 결정 Downstream의 비즈니스 가치 고려 3. 계약 정의 Consumer-Driven Contract Testing Downstream이 기대하는 계약을 먼저 정의 4. 구현 및 검증 Upstream이 구현 Downstream의 계약 테스트로 검증 5. 배포 Upstream 먼저 배포 (하위 호환 유지) Downstream 이후 배포
Consumer-Driven Contract 예시
// Downstream(Order Context)이 정의하는 계약
// pact/order-product-contract.ts
const productContract = {
consumer: 'OrderContext',
provider: 'ProductContext',
interactions: [
{
description: 'get product by id',
request: {
method: 'GET',
path: '/api/products/123'
},
response: {
status: 200,
body: {
id: '123',
name: Matchers.string(),
price: {
amount: Matchers.decimal(),
currency: Matchers.string()
},
available: Matchers.boolean()
}
}
}
]
};
// Upstream(Product Context)은 이 계약을 만족해야 함
// CI/CD에서 계약 테스트 실행| 기준 | Conformist | ACL |
|---|---|---|
| 외부 모델 품질 | 좋음, 우리 도메인과 유사 | 나쁨, 우리 도메인과 다름 |
| 변경 빈도 | 낮음, 안정적 | 높음, 자주 변경 |
| 구현 비용 | 낮음 | 높음 (번역 계층 필요) |
| 유지보수 비용 | 외부 변경에 취약 | 외부 변경 격리 |
| 도메인 순수성 | 오염 가능 | 보호됨 |
💡 실무 가이드라인
- • 표준 프로토콜 (OAuth, OpenID) → Conformist
- • 잘 설계된 외부 API (Stripe, Twilio) → Conformist 또는 얇은 ACL
- • 레거시 시스템 → ACL 필수
- • Core Domain과 통합 → ACL로 보호
3. Open Host Service와 Published Language
"Open Host Service는 여러 클라이언트가 사용할 수 있는 프로토콜을 정의한다. Published Language는 그 프로토콜에서 사용하는 공용 언어다. 이 둘은 함께 사용될 때 가장 강력하다."
— Eric Evans, Domain-Driven Design
3.1 Open Host Service (OHS)
Upstream Context가 여러 Downstream을 위한 표준화된 서비스를 제공합니다. 각 Downstream에 맞춤 API를 만드는 대신, 범용적인 API를 공개합니다.
OHS 아키텍처
┌─────────────────┐
┌───►│ Order Context │
│ └─────────────────┘
┌─────────────────┐ │ ┌─────────────────┐
│ Product Context │──────┼───►│ Search Context │
│ [Open Host] │ │ └─────────────────┘
│ │ │ ┌─────────────────┐
│ REST API v2 │──────┼───►│Analytics Context│
│ GraphQL │ │ └─────────────────┘
│ Event Stream │ │ ┌─────────────────┐
└─────────────────┘ └───►│ Mobile App │
└─────────────────┘
특징:
• 하나의 API로 여러 소비자 지원
• 버전 관리로 하위 호환성 유지
• 문서화된 공개 인터페이스OHS 구현 옵션
- • REST API - 가장 범용적
- • GraphQL - 유연한 쿼리
- • gRPC - 고성능, 타입 안전
- • Event Stream - 비동기 통합
- • Webhook - 푸시 알림
OHS 설계 원칙
- • 특정 소비자에 종속되지 않음
- • 명확한 버전 관리 전략
- • 충분한 문서화
- • 하위 호환성 우선
- • Rate Limiting, 인증 포함
3.2 Published Language
Context 간 통신을 위한 잘 문서화된 공용 언어입니다. OHS의 데이터 형식을 정의하고, 모든 참여자가 이해할 수 있는 스키마를 제공합니다.
동기 통신용
- • OpenAPI (Swagger) - REST API 스펙
- • GraphQL Schema - GraphQL 타입 정의
- • Protocol Buffers - gRPC 스키마
- • JSON Schema - JSON 구조 정의
비동기 통신용
- • AsyncAPI - 이벤트 기반 API 스펙
- • Avro - 스키마 진화 지원
- • CloudEvents - 이벤트 표준 형식
- • JSON Schema - 이벤트 페이로드
OpenAPI 예시
# product-api.yaml
openapi: 3.0.3
info:
title: Product Context API
version: 2.0.0
description: |
상품 정보를 제공하는 Open Host Service.
모든 소비자는 이 API를 통해 상품 데이터에 접근합니다.
paths:
/products/{productId}:
get:
summary: 상품 상세 조회
parameters:
- name: productId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: 성공
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
components:
schemas:
Product:
type: object
required: [id, name, price, status]
properties:
id:
type: string
format: uuid
name:
type: string
maxLength: 200
description:
type: string
price:
$ref: '#/components/schemas/Money'
status:
type: string
enum: [ACTIVE, INACTIVE, DISCONTINUED]
Money:
type: object
required: [amount, currency]
properties:
amount:
type: number
format: decimal
currency:
type: string
pattern: '^[A-Z]{3}$'# product-events.yaml
asyncapi: 2.6.0
info:
title: Product Context Events
version: 1.0.0
channels:
product/created:
publish:
message:
$ref: '#/components/messages/ProductCreated'
product/price-changed:
publish:
message:
$ref: '#/components/messages/ProductPriceChanged'
components:
messages:
ProductCreated:
name: ProductCreated
payload:
type: object
required: [eventId, occurredAt, productId, name, price]
properties:
eventId:
type: string
format: uuid
occurredAt:
type: string
format: date-time
productId:
type: string
format: uuid
name:
type: string
price:
$ref: '#/components/schemas/Money'
ProductPriceChanged:
name: ProductPriceChanged
payload:
type: object
required: [eventId, occurredAt, productId, oldPrice, newPrice]
properties:
eventId:
type: string
format: uuid
occurredAt:
type: string
format: date-time
productId:
type: string
format: uuid
oldPrice:
$ref: '#/components/schemas/Money'
newPrice:
$ref: '#/components/schemas/Money'
reason:
type: string3.3 스키마 진화 전략
Published Language는 시간이 지나면서 진화합니다.하위 호환성을 유지하면서 스키마를 변경하는 전략이 필요합니다.
✓ 하위 호환 변경 (안전)
- • 새 필드 추가 (optional)
- • 새 enum 값 추가
- • 필드를 optional로 변경
- • 새 엔드포인트 추가
✗ 하위 비호환 변경 (위험)
- • 필드 삭제
- • 필드 타입 변경
- • 필드를 required로 변경
- • 필드 이름 변경
- • enum 값 삭제
버전 관리 전략
URL 버전: /api/v1/products, /api/v2/products
헤더 버전: Accept: application/vnd.company.v2+json
이벤트 버전: ProductCreated.v1, ProductCreated.v2
💡 실무 팁: Schema Registry
이벤트 기반 시스템에서는 Schema Registry를 사용하여 스키마를 중앙에서 관리하세요.
- • Confluent Schema Registry - Kafka와 함께 사용
- • AWS Glue Schema Registry - AWS 환경
- • Apicurio Registry - 오픈소스 옵션
4. 팀 토폴로지와 Context Mapping
"조직의 커뮤니케이션 구조를 설계하는 모든 조직은 그 구조의 복사본인 시스템을 설계하게 된다."
— Melvin Conway, Conway의 법칙 (1967)
4.1 Conway의 법칙과 역 Conway 기동
Conway의 법칙
시스템 구조는 조직 구조를 반영합니다. 팀 간 커뮤니케이션 패턴이 시스템 간 인터페이스가 됩니다.
3개 팀 → 3개 컴포넌트
팀 간 소통 어려움 → 시스템 간 통합 어려움
역 Conway 기동
원하는 시스템 구조에 맞게 조직을 설계합니다. Context Map을 먼저 그리고, 그에 맞게 팀을 구성합니다.
목표 아키텍처 정의 → 팀 구조 조정
Bounded Context = 팀 소유권
4.2 Team Topologies의 4가지 팀 유형
1. Stream-aligned Team (스트림 정렬 팀)
비즈니스 가치 흐름에 정렬된 팀. 하나의 Bounded Context를 소유.
2. Platform Team (플랫폼 팀)
내부 서비스/플랫폼을 제공하는 팀. 여러 팀이 사용하는 공통 기능.
3. Enabling Team (지원 팀)
다른 팀의 역량 향상을 돕는 팀. 기술 전문성 전파.
4. Complicated Subsystem Team (복잡한 서브시스템 팀)
특수 전문성이 필요한 복잡한 컴포넌트를 담당하는 팀.
4.3 팀 상호작용 모드
| 상호작용 모드 | 설명 | Context Mapping 패턴 |
|---|---|---|
| Collaboration | 두 팀이 긴밀하게 협력 | Partnership, Shared Kernel |
| X-as-a-Service | 한 팀이 서비스 제공, 다른 팀이 소비 | OHS + Published Language, Customer-Supplier |
| Facilitating | 한 팀이 다른 팀의 역량 향상 지원 | 직접적 패턴 없음 (ACL 구현 지원 등) |
┌─────────────────────────────────────────────────────────────────────────┐ │ E-Commerce Platform Team Topology │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ Stream-aligned Teams (비즈니스 가치 흐름) │ │ ┌──────────────┐ Partnership ┌──────────────┐ │ │ │ Order Team │◄────────────────►│ Payment Team │ │ │ │ (주문 BC) │ │ (결제 BC) │ │ │ └──────┬───────┘ └──────────────┘ │ │ │ │ │ │ Customer-Supplier │ │ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Catalog Team │ │Shipping Team │ │ │ │ (상품 BC) │ │ (배송 BC) │ │ │ └──────┬───────┘ └──────────────┘ │ │ │ │ │ │ OHS + PL │ │ ▼ │ │ Platform Team (내부 플랫폼) │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Platform Team │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │Identity│ │ Event │ │ API │ │ │ │ │ │Platform│ │ Bus │ │Gateway │ │ │ │ │ └────────┘ └────────┘ └────────┘ │ │ │ │ [Open Host Service 제공] │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ Enabling Team (역량 지원) │ │ ┌──────────────────────────────────────────────────┐ │ │ │ DDD/Architecture Team │ │ │ │ • Context 경계 설계 지원 │ │ │ │ • ACL 구현 가이드 │ │ │ │ • Event Storming 퍼실리테이션 │ │ │ └──────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘
4.4 인지 부하와 팀 크기
"팀의 인지 부하를 초과하는 Bounded Context를 할당하지 마라. 팀이 감당할 수 있는 복잡도에는 한계가 있다."
— Team Topologies, Matthew Skelton & Manuel Pais
5-9명
이상적인 팀 크기
Two-Pizza Team
1-2개
팀당 Bounded Context
명확한 소유권
2주
의미 있는 기능 배포 주기
독립적 진화
⚠️ 경고: 팀-Context 불일치
다음 상황은 문제의 신호입니다:
- • 하나의 Context를 여러 팀이 공유 → 소유권 불명확, 충돌
- • 한 팀이 너무 많은 Context 소유 → 인지 부하 초과
- • Context 경계와 팀 경계 불일치 → 커뮤니케이션 오버헤드
5. Context Map 시각화와 도구
5.1 Context Map 표기법
Context Map 표기법 범례: ┌─────────────┐ │ Context │ 박스: Bounded Context │ Name │ └─────────────┘ 관계 표기: A ◄──────────► B Partnership (양방향 화살표) A ────────────► B Upstream → Downstream (단방향) A ──── SK ────► B Shared Kernel A ──── ACL ───► B Anti-Corruption Layer A ──── OHS ───► B Open Host Service A ──── PL ────► B Published Language A ──── CF ────► B Conformist A ──── CS ────► B Customer-Supplier U = Upstream (상류) D = Downstream (하류) 예시: ┌─────────────┐ ┌─────────────┐ │ Product │ OHS │ Order │ │ Context │────────►│ Context │ │ [U] │ PL │ [D] │ └─────────────┘ └─────────────┘
5.2 Context Map 도구
📝 다이어그램 도구
- Miro/Mural - 협업 화이트보드, Event Storming에 적합
- Draw.io - 무료, 다양한 템플릿
- Lucidchart - 전문적인 다이어그램
- PlantUML - 코드로 다이어그램 생성
🛠️ 전문 도구
- Context Mapper - DSL 기반 Context Map 모델링
- Structurizr - C4 모델 + Context Map
- EventStorming.com - 온라인 Event Storming
- IcePanel - 아키텍처 시각화 플랫폼
// ecommerce.cml - Context Mapper DSL
ContextMap ECommerceContextMap {
type = SYSTEM_LANDSCAPE
state = AS_IS
contains OrderContext
contains ProductContext
contains PaymentContext
contains ShippingContext
contains InventoryContext
// 관계 정의
OrderContext [D,C]<-[U,S] ProductContext {
implementationTechnology = "REST API"
exposedAggregates = Product
}
OrderContext [D]<-[U] PaymentContext {
implementationTechnology = "Domain Events"
}
OrderContext Partnership PaymentContext {
implementationTechnology = "Shared Library"
}
ShippingContext [D,ACL]<-[U,OHS] ExternalLogisticsAPI {
implementationTechnology = "REST + ACL"
}
}
BoundedContext OrderContext implements OrderDomain {
type = FEATURE
domainVisionStatement = "주문 생성, 변경, 취소를 담당"
responsibilities = "Order", "OrderItem", "OrderStatus"
Aggregate Order {
Entity Order {
aggregateRoot
- OrderId id
- CustomerId customerId
- List<OrderItem> items
- OrderStatus status
- Money totalAmount
}
}
}
// 다이어그램 생성 명령
// ./contextmapper generate ecommerce.cml -g plantuml5.3 Context Map 문서화 템플릿
1. 개요
- • 시스템 이름과 목적
- • Context Map 버전과 최종 수정일
- • 작성자와 검토자
2. Context 목록
각 Context에 대해:
- • 이름과 설명
- • 소유 팀
- • 핵심 도메인 개념
- • 기술 스택
- • 서브도메인 유형 (Core/Supporting/Generic)
3. 관계 정의
각 관계에 대해:
- • Upstream/Downstream Context
- • 패턴 (Partnership, ACL, OHS 등)
- • 통합 방식 (REST, Event, 공유 DB 등)
- • 데이터 흐름
- • SLA/계약
4. 시각적 다이어그램
- • 전체 Context Map 다이어그램
- • 데이터 흐름 다이어그램
- • 팀 소유권 매핑
5. 진화 계획
- • 현재 상태 (AS-IS)
- • 목표 상태 (TO-BE)
- • 마이그레이션 단계
- • 리스크와 의존성
💡 실무 팁: Context Map을 살아있게 유지하기
- • 코드와 함께 버전 관리 - Context Map을 Git에 저장
- • 정기 리뷰 - 분기별로 Context Map 리뷰 세션
- • 변경 시 업데이트 - 새 Context 추가, 관계 변경 시 즉시 반영
- • 온보딩 자료로 활용 - 새 팀원에게 시스템 설명
- • ADR과 연결 - 아키텍처 결정 기록과 Context Map 연결
6. Context Map 진화와 마이그레이션
6.1 Context Map의 진화
Context Map은 정적인 문서가 아닙니다. 비즈니스가 성장하고, 팀이 변화하고, 기술이 발전함에 따라 지속적으로 진화해야 합니다.
진화 트리거
- • 새로운 비즈니스 도메인 추가
- • 팀 구조 변경 (합병, 분리)
- • 기술 스택 변경
- • 외부 시스템 통합/제거
- • 성능/확장성 요구사항 변화
- • 레거시 시스템 현대화
6.2 패턴 전환 시나리오
시나리오 1: Conformist → ACL
Before: After:
┌──────────┐ ┌──────────┐
│ External │ │ External │
│ API │ │ API │
└────┬─────┘ └────┬─────┘
│ Conformist │
▼ ▼
┌──────────┐ ┌────┴─────┐
│ Our │ → │ ACL │
│ Context │ └────┬─────┘
└──────────┘ │
▼
┌──────────┐
│ Our │
│ Context │
└──────────┘언제: 외부 API가 자주 변경되거나, 우리 도메인 모델과 불일치가 커질 때
시나리오 2: Partnership → Customer-Supplier
Before: After:
┌──────────┐ Partnership ┌──────────┐
│ Context │◄────────────►│ Context │
│ A │ │ B │
└──────────┘ └──────────┘
↓
┌──────────┐ Customer-Supplier ┌──────────┐
│ Context │◄────────────────────│ Context │
│ A [U] │ │ B [D] │
└──────────┘ └──────────┘언제: 팀이 분리되거나, 한쪽이 더 안정적인 서비스 제공자 역할을 할 때
시나리오 3: Big Ball of Mud → 여러 Context
Before: After:
┌─────────────────────┐ ┌──────────┐ ┌──────────┐
│ │ │ Context │◄──►│ Context │
│ Big Ball of Mud │ → │ A │ │ B │
│ │ └──────────┘ └──────────┘
└─────────────────────┘ │ │
└──────┬───────┘
▼
┌──────────┐
│ Context │
│ C │
└──────────┘언제: 레거시 현대화, 마이크로서비스 전환 시
6.3 Context 분할 전략
분할 신호
- • 같은 용어가 다른 의미로 사용됨
- • 팀 내 서로 다른 그룹이 다른 부분을 담당
- • 변경 주기가 크게 다른 영역 존재
- • 확장 요구사항이 다른 영역 존재
분할 프로세스
1. 경계 식별 - Event Storming으로 서브도메인 재발견 - 언어적 경계 확인 2. 내부 모듈화 - 기존 Context 내에서 모듈로 분리 - 모듈 간 인터페이스 정의 3. 데이터 분리 - 공유 테이블 식별 - 각 모듈 전용 테이블로 분리 4. API 분리 - 모듈별 API 엔드포인트 분리 - 내부 통신을 API 호출로 전환 5. 물리적 분리 (선택) - 별도 서비스로 배포 - Context Map 업데이트
6.4 Context 병합 전략
병합 신호
- • 두 Context가 항상 함께 변경됨
- • 과도한 Context 간 통신 오버헤드
- • 분산 트랜잭션 문제 빈발
- • 팀 병합으로 인한 조직 변화
- • 너무 작은 Context로 인한 운영 부담
⚠️ 병합 시 주의사항
- • 마이크로서비스 병합은 매우 어려움
- • 데이터 마이그레이션 복잡도 높음
- • 모듈러 모놀리스에서는 상대적으로 쉬움
- • 병합 전 충분한 분석 필요
AS-IS (현재)
┌─────────────────────┐ │ Monolith │ │ ┌─────┐ ┌─────┐ │ │ │Order│─│Pay │ │ │ └─────┘ └─────┘ │ │ ┌─────┐ ┌─────┐ │ │ │Prod │─│Ship │ │ │ └─────┘ └─────┘ │ │ Shared DB │ └─────────────────────┘ 문제: • 모든 것이 결합 • 독립 배포 불가 • 확장 어려움
TO-BE (목표)
┌───────┐ ┌───────┐
│ Order │◄─►│Payment│
│Context│ │Context│
└───┬───┘ └───────┘
│ CS
▼
┌───────┐ ┌───────┐
│Product│ │Shipping│
│Context│ │Context │
└───────┘ └───┬───┘
│ ACL
▼
┌────────┐
│External│
│Logistics│
└────────┘
개선:
• 독립적 Context
• 명확한 관계
• 독립 배포 가능💡 마이그레이션 원칙
- • 점진적 진행 - Big Bang 마이그레이션 피하기
- • 롤백 가능 - 각 단계에서 롤백 계획 수립
- • 비즈니스 연속성 - 마이그레이션 중에도 서비스 유지
- • 측정 가능 - 성공 지표 정의 및 모니터링
7. 실제 기업 사례 심층 분석
7.1 Netflix의 Context Mapping
Netflix Context Map (간략화)
┌─────────────────────────────────────────────────────────────────┐
│ API Gateway (Zuul) │
└─────────────────────────────────────────────────────────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Streaming │ │Recommendation│ │Subscription │ │ Content │
│ Context │ │ Context │ │ Context │ │ Context │
│ │ │ (Core) │ │ │ │ │
│ • Playback │ │ • ML Models │ │ • Billing │ │ • Catalog │
│ • Encoding │ │ • User Pref │ │ • Plans │ │ • Metadata │
│ • CDN │ │ • A/B Test │ │ • Payment │ │ • Licensing │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │ │
│ OHS + PL │ OHS + PL │ ACL │
│ │ │ │
└────────────────┴────────────────┴────────────────┘
│
▼
┌─────────────────────┐
│ Data Platform │
│ (Event Sourcing) │
└─────────────────────┘적용 패턴
- • OHS + PL: 각 서비스가 gRPC/REST API 공개
- • ACL: 외부 결제 시스템 통합
- • Published Language: Protobuf 스키마
- • Separate Ways: 지역별 독립 시스템
핵심 원칙
- • 팀 자율성 최대화
- • 각 팀이 자신의 API 소유
- • Chaos Engineering으로 장애 격리 검증
- • 이벤트 기반 데이터 동기화
7.2 Amazon의 Context Mapping
"Amazon은 2002년에 이미 서비스 지향 아키텍처로 전환했다. 모든 팀은 서비스 인터페이스를 통해서만 통신해야 한다."
— Jeff Bezos의 API Mandate (2002)
Amazon E-Commerce Context Map (간략화)
┌─────────────────────────────────────────────────────────────────┐
│ Customer Experience │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Search │ │ Browse │ │ Cart │ │ Checkout │ │
│ │ Context │ │ Context │ │ Context │ │ Context │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
└───────┼─────────────┼─────────────┼─────────────┼───────────────┘
│ │ │ │
│ CS │ CS │ Partnership │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ Core Commerce │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Catalog │ │ Order │ │ Payment │ │ Inventory│ │
│ │ Context │ │ Context │ │ Context │ │ Context │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
└───────┼─────────────┼─────────────┼─────────────┼───────────────┘
│ │ │ │
│ OHS │ Events │ ACL │ CS
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ Fulfillment │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Warehouse │ │ Shipping │ │ Returns │ │ Logistics│ │
│ │ Context │ │ Context │ │ Context │ │ Context │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────┘Amazon의 핵심 원칙
- • Two-Pizza Team: 각 팀이 하나의 Context 소유
- • You Build It, You Run It: 개발팀이 운영까지 책임
- • API First: 모든 통신은 API를 통해서만
- • Backward Compatibility: API 하위 호환성 필수
7.3 Shopify의 모듈러 모놀리스
"우리는 마이크로서비스의 복잡성 없이 Bounded Context의 이점을 얻기 위해 모듈러 모놀리스를 선택했다."
— Shopify Engineering Blog (2024)
Shopify Modular Monolith ┌─────────────────────────────────────────────────────────────────┐ │ Single Rails Application │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Public API Layer │ │ │ └──────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌──────────┐ ┌──────────┐ │ ┌──────────┐ ┌──────────┐ │ │ │ Orders │ │ Products │ │ │ Payments │ │ Shipping │ │ │ │ Module │ │ Module │ │ │ Module │ │ Module │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ [Context]│ │ [Context]│ │ │ [Context]│ │ [Context]│ │ │ └────┬─────┘ └────┬─────┘ │ └────┬─────┘ └────┬─────┘ │ │ │ │ │ │ │ │ │ └─────────────┴────────┴───────┴─────────────┘ │ │ │ │ │ Internal Module APIs │ │ (Packwerk로 경계 강제) │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Shared Database │ │ │ │ (스키마는 모듈별로 분리) │ │ │ └──────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ Packwerk 규칙: • 모듈 간 직접 참조 금지 • 공개 API를 통해서만 통신 • 의존성 방향 강제
장점
- • 단순한 배포 (하나의 앱)
- • 트랜잭션 처리 용이
- • 리팩토링 쉬움
- • 운영 복잡도 낮음
도구
- • Packwerk: 모듈 경계 강제
- • Sorbet: 타입 체크
- • Delorean: 데이터 분리
7.4 국내 사례: 배달의민족
배달의민족 Context Map (공개 정보 기반)
┌─────────────────────────────────────────────────────────────────┐
│ 고객 접점 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 검색 │ │ 주문 │ │ 리뷰 │ │
│ │ Context │ │ Context │ │ Context │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
└───────┼─────────────┼─────────────┼─────────────────────────────┘
│ │ │
│ Events │ Partnership │ Events
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ 핵심 도메인 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 가게 │ │ 메뉴 │ │ 결제 │ │ 정산 │ │
│ │ Context │ │ Context │ │ Context │ │ Context │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
└───────┼─────────────┼─────────────┼─────────────┼───────────────┘
│ │ │ │
│ OHS │ Events │ ACL │ Events
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ 배달 도메인 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 라이더 │ │ 배차 │ │ 추적 │ │
│ │ Context │ │ Context │ │ Context │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────┘핵심 전략
- • 이벤트 기반: Kafka를 통한 Context 간 통신
- • CQRS: 읽기/쓰기 분리로 성능 최적화
- • 점진적 전환: 2년에 걸친 마이크로서비스 전환
- • 팀 자율성: 각 Context를 독립 팀이 소유
8. 실습: 대규모 시스템 Context Map 설계
8.1 비즈니스 요구사항
핵심 기능
- • 강의 콘텐츠 관리 및 스트리밍
- • 수강 신청 및 결제
- • 학습 진도 추적
- • 퀴즈 및 과제 평가
- • 수료증 발급
- • 강사-학생 Q&A
비기능 요구사항
- • 동시 접속 10만 명 지원
- • 글로벌 서비스 (다국어)
- • 99.9% 가용성
- • 외부 결제 시스템 연동
- • 기업 고객용 SSO 지원
8.2 식별된 Bounded Context
📚 콘텐츠 Context
- • 강의, 섹션, 레슨
- • 비디오 메타데이터
- • 강의 자료
📊 학습 Context
- • 학습 진도
- • 완료 기록
- • 학습 분석
📝 평가 Context
- • 퀴즈, 과제
- • 채점, 피드백
- • 수료 기준
🛒 수강 Context
- • 수강 신청
- • 수강 권한
- • 환불 처리
🎓 수료증 Context
- • 수료증 생성
- • 검증 서비스
- • 블록체인 기록
💬 커뮤니티 Context
- • Q&A 게시판
- • 토론
- • 리뷰
👤 Identity Context
- • 인증/인가
- • SSO 연동
- • 프로필
💳 결제 Context
- • 결제 처리
- • 구독 관리
- • 정산
🔔 알림 Context
- • 이메일/푸시
- • 알림 설정
- • 템플릿
8.3 Context Map
온라인 교육 플랫폼 Context Map
┌─────────────────────────────────────────────────────────────────────────┐
│ External Systems │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Stripe │ │ Auth0 │ │ CDN │ │ Twilio │ │
│ │ (PG) │ │ (IdP) │ │(Cloudflare)│ │ (SMS) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ACL │CF │OHS │ACL │
└───────┼─────────────┼─────────────┼─────────────┼───────────────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Platform Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 결제 │ │ Identity │ │ 스트리밍 │ │ 알림 │ │
│ │ Context │ │ Context │ │ Context │ │ Context │ │
│ │ [OHS] │ │ [OHS] │ │ [OHS] │ │ [OHS] │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
└───────┼─────────────┼─────────────┼─────────────┼───────────────────────┘
│ │ │ │
│ CS │ OHS │ CS │ Events
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Core Domain │
│ │
│ ┌──────────┐ Partnership ┌──────────┐ Partnership │
│ │ 콘텐츠 │◄─────────────────►│ 학습 │◄─────────────────┐ │
│ │ Context │ │ Context │ │ │
│ │ [U] │ │ │ │ │
│ └────┬─────┘ └────┬─────┘ │ │
│ │ │ │ │
│ │ CS │ CS │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 수강 │ │ 평가 │ │ 수료증 │ │
│ │ Context │ │ Context │ │ Context │ │
│ │ [D] │ │ [D] │ │ [D] │ │
│ └──────────┘ └────┬─────┘ └──────────┘ │
│ │ │
│ │ Events │
│ ▼ │
│ ┌──────────┐ │
│ │ 커뮤니티 │ │
│ │ Context │ │
│ └──────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
관계 요약:
• 콘텐츠 ↔ 학습: Partnership (긴밀한 협력)
• 학습 ↔ 평가: Partnership (학습 완료 시 평가)
• 학습 → 수료증: Customer-Supplier (수료 조건 충족 시)
• 콘텐츠 → 수강: Customer-Supplier (수강 권한 확인)
• 평가 → 커뮤니티: Events (과제 제출 시 토론 생성)
• 모든 Context → 알림: Events (알림 발송)8.4 팀 구조 매핑
| 팀 | 소유 Context | 팀 유형 | 규모 |
|---|---|---|---|
| 콘텐츠팀 | 콘텐츠 Context | Stream-aligned | 6명 |
| 학습경험팀 | 학습 + 평가 Context | Stream-aligned | 8명 |
| 커머스팀 | 수강 + 결제 Context | Stream-aligned | 5명 |
| 플랫폼팀 | Identity + 알림 + 스트리밍 | Platform | 7명 |
| 커뮤니티팀 | 커뮤니티 + 수료증 | Stream-aligned | 4명 |
💡 설계 결정 근거
- • 콘텐츠-학습 Partnership: 강의 구조 변경 시 학습 진도 로직도 함께 변경 필요
- • 플랫폼팀 OHS: 여러 팀이 공통으로 사용하는 기능을 표준 API로 제공
- • 외부 시스템 ACL: Stripe, Auth0 등 외부 API 변경으로부터 도메인 보호
- • 이벤트 기반 알림: 모든 Context의 중요 이벤트를 구독하여 알림 발송
9. 자주 묻는 질문 (FAQ)
시스템 아키텍처 다이어그램은 기술적 구성요소(서버, DB, 네트워크)를 보여주고, Context Map은 비즈니스 도메인 간의 관계와 팀 간 협력 방식을 표현합니다. Context Map은 '왜 이렇게 통합하는가'에 대한 조직적, 정치적 맥락을 포함합니다.
아니요. 실제로 통합이 발생하는 관계만 표시합니다. 독립적으로 운영되는 Context는 Separate Ways로 명시하거나 생략할 수 있습니다.
레거시 시스템과 통합할 때, 외부 서비스의 모델이 우리 도메인과 맞지 않을 때, Upstream의 변경으로부터 보호가 필요할 때, Conformist 패턴이 도메인 무결성을 해칠 때 사용합니다.
Partnership은 두 팀이 긴밀히 협력하지만 각자의 모델을 유지할 때, Shared Kernel은 공통 모델을 실제로 공유하고 함께 변경할 때 사용합니다. Shared Kernel은 강한 결합을 만들므로 정말 필요한 경우에만 사용하세요.
새로운 Bounded Context가 추가될 때, 팀 구조가 변경될 때, 통합 패턴이 변경될 때, 그리고 분기별 정기 리뷰 시점에 업데이트를 권장합니다.
네. 모놀리스 내에서도 모듈 간 경계와 의존성을 명확히 하는 데 Context Map이 유용합니다. 오히려 마이크로서비스로 전환하기 전에 Context Map을 먼저 그리는 것이 좋습니다.
일반 API는 특정 클라이언트를 위한 맞춤형 인터페이스이고, OHS는 다수의 클라이언트를 위한 표준화된 프로토콜입니다. OHS는 Published Language와 함께 사용되어 명확한 계약을 제공합니다.
Big Ball of Mud는 그 자체로 하나의 Context로 표시합니다. 다른 Context와의 관계에서는 주로 ACL을 사용하여 오염을 방지하고, 점진적으로 Strangler Fig 패턴을 적용하며 Context Map을 업데이트합니다.
10. 핵심 요약
- • 시스템의 현재 상태를 있는 그대로 표현
- • 기술적 + 조직적 관계를 모두 포함
- • 팀 간 커뮤니케이션의 기반
- • 진화하는 살아있는 문서
- • 협력형: Partnership, Shared Kernel
- • 상하관계: Customer-Supplier, Conformist
- • 보호형: ACL, OHS/PL
- • 독립형: Separate Ways, Big Ball of Mud
- • Stream-aligned → Core Domain 담당
- • Platform → OHS/PL 제공
- • Enabling → Partnership 촉진
- • Complicated-subsystem → ACL 뒤 전문 영역
- • 현재 상태 먼저, 목표 상태는 나중에
- • 패턴 선택은 기술 + 조직 + 정치 고려
- • 정기적 리뷰와 업데이트 필수
- • 도구보다 팀 간 대화가 중요
"Context Map은 단순한 다이어그램이 아니라,
조직이 소프트웨어를 어떻게 만들고 있는지에 대한 솔직한 대화입니다."
— Eric Evans
11. 참고 자료 및 다음 학습
- Domain-Driven Design
Eric Evans - Context Mapping 원전
- Implementing Domain-Driven Design
Vaughn Vernon - 실무 적용 가이드
- Team Topologies
Matthew Skelton - 팀 구조와 Context 연계
- Learning Domain-Driven Design
Vlad Khononov - 현대적 접근법
- Context Mapper
contextmapper.org - DSL 기반 모델링
- Miro / FigJam
협업 기반 Context Map 시각화
- EventStorming
eventstorming.com - 도메인 발견 워크샵
- DDD Crew GitHub
github.com/ddd-crew - 템플릿 모음
1단계: 실습
- • 현재 시스템 Context Map 그리기
- • 팀과 함께 리뷰하기
- • 문제 영역 식별하기
2단계: 심화
- • Event Storming 워크샵
- • ACL 구현 패턴 학습
- • 이벤트 기반 통합 설계
3단계: 적용
- • 목표 Context Map 설계
- • 마이그레이션 계획 수립
- • 점진적 개선 실행
💡 이 시리즈의 다음 내용
- • DDD Theory 06: Aggregate와 일관성 경계
- • DDD Theory 07: Domain Events와 이벤트 소싱
- • DDD Theory 08: CQRS 패턴 심화