DDD Strategic Context Mapping
[Placeholder for technical implementation]
Article
M
Me
hyunyoun's Blog
software-engineering-devopssoftware-engineeringdev-opsarchitecturedesignddd-strategic-context-mappingoopddd11 min read
1. Overview
DDD 전략적 컨텍스트 매핑(DDD Strategic Context Mapping)은 단일 테이블과 코드 베이스로 비대해진 거대 짐승(Monolith)을 논리적으로 해체하여, 개발팀들이 서로의 목을 조르지 않고 독립적으로 달릴 수 있게 만드는 비즈니스 도메인 경계 분할의 최상위 아키텍처를 해부합니다.
학습자는 쇼핑몰의 'User' 클래스 하나에 마케팅, 결제, 배송 팀이 각자의 필드를 100개씩 우겨넣어 붕괴하는 바벨탑의 저주를 타파하는 **보편 유비쿼터스 언어(Ubiquitous Language)**의 중요성을 뜯어봅니다. 나아가 "배송팀의 User"와 "결제팀의 User"는 이름만 같지 전혀 다른 객체임을 선언하고 물리적/논리적 장벽을 치는 **바운디드 컨텍스트(Bounded Context)**의 위대함을 장악합니다. 마지막으로, 나누어진 컨텍스트(마이크로서비스)들이 서로 어떻게 데이터를 주고받고 정치적 권력을 나누는지 규정하는 컨텍스트 매핑(Context Mapping - ACL, OHS 등) 역량을 확보합니다.
2. Scope & Boundaries
In-Scope
- Ubiquitous Language: 도메인 전문가(비즈니스)와 개발자가 일상과 코드에서 동일하게 사용하는 타협 없는 단일 언어 사전.
- Bounded Context: 언어와 도메인 모델의 의미가 완벽하게 일관성을 유지하는 캡슐화된 경계 (마이크로서비스의 기준점).
- Context Mapping Patterns: Partnership, Shared Kernel, Customer/Supplier, Conformist (순응주의자).
- Integration Patterns: ACL (Anti-Corruption Layer, 부패 방지 계층), OHS (Open Host Service), PL (Published Language).
Out-of-Scope
- DDD Tactical Design (전술적 설계): Entity, Value Object, Aggregate Root, Repository 등을 구체적으로 코드로 짜는 법 09-03-05 DDD Tactical Patterns (별도 심화 모듈)로 위임.
- 이벤트 스토밍(Event Storming) 워크숍 기법: 포스트잇을 붙이며 도메인 이벤트를 찾는 구체적 행위 해당 문서는 '도출된 컨텍스트 매핑 아키텍처' 자체에 집중함.
Boundaries
- Strategic (전략) vs Tactical (전술): 전술적 설계(Entity, Repository)는 결국 '코드'를 예쁘게 짜는 기술입니다. 하지만 전략적 설계(Bounded Context)는 '팀의 구조'와 '마이크로서비스의 찢어짐'을 결정하는 국가 레벨의 거버넌스입니다. 잘못된 바운디드 컨텍스트 위에서 아무리 전술적 엔티티를 예쁘게 깎아봤자, 똥 위에 지은 예쁜 성일 뿐이라는 거시적 아키텍처의 우위성에 명확한 선을 긋습니다.
3. Counterexample
- 괴물 엔티티의 탄생 (God Class 'User'): 회사가 커지며 모노리틱 시스템의
User테이블 필드가 200개가 되었습니다. 마케팅팀은쿠폰_발급일필드를, 배송팀은우편번호필드를, 결제팀은카드해시필드를 추가했습니다. 배송팀 개발자가 무심코User객체의 로직을 수정했는데, 전혀 상관없는 결제팀의 월말 정산 배치가 터져버립니다. 비즈니스 경계(Context)를 나누지 않고 세상 모든 것을 하나의 'User'로 퉁치려다 발생한 데이터 락(Lock)과 의존성 지옥입니다. - 오염의 전이 (Corruption): A팀(결제)이 B팀(레거시 ERP)의 데이터를 API로 가져다 씁니다. B팀의 데이터 포맷은 90년대 스타일(
STR_01,FLG_N)로 극도로 난해합니다. A팀 개발자들은 바쁘다는 이유로 중간에 번역기(ACL)를 두지 않고, 자신들의 최신 결제 로직 깊숙한 곳까지STR_01이라는 변수명을 그대로 씁니다. 몇 년 뒤 B팀 시스템이 개편되자, A팀의 결제 코어 로직이 연쇄적으로 붕괴해 버리는 침투적 오염(Corruption)의 재앙입니다.
4. Prerequisites
- Microservices Architecture (Basic): 모놀리스의 분해 필요성. (07-04-01 Microservices Foundations)
- What vs How (Basic): 비즈니스 도메인(What)이 기술(How)을 압도해야 한다는 철학.
5. Learning Map
6. Learning Topics
Basic
Core Topic 01: 바벨탑의 붕괴, 보편 언어 (Ubiquitous Language)
- Why to Learn: "기획자-개발자-DBA"가 각자 다른 단어를 쓰면서 발생하는 끔찍한 소통 낭비(번역 비용)를 없애고, 코드 자체가 비즈니스 문서를 대변하도록 언어를 통일하기 위함입니다.
- What to Learn:
- Concepts: Domain (도메인), Ubiquitous Language (보편 언어), Translation Cost (번역 비용), Domain Expert.
- Skills: 비즈니스 문서에 "주문이 취소되면 쿠폰은 환불된다"라고 적혀있다면, 코드에도 무조건
order.cancel(),coupon.refund()로 정확히 1<1>1> 맵핑시켜 변수명 짓기.
- How to Learn:
- 1단계: 바벨탑의 저주: 기획자는 회의에서 "티켓(Ticket)"이라고 합니다. 개발자는 그걸 듣고 머릿속으로 번역해서 소스코드에는
Reservation클래스로 짭니다. DBA는 테이블명을tb_booking으로 짓습니다. 에러가 나면 셋이 모여 "예약 건수가 안 맞는데요?", "아, 티켓 테이블이요?"라며 번역하느라 시간을 허비합니다. - 2단계: 강제적 통일 (Ubiquitous): 도메인 주도 설계(DDD)의 1원칙입니다. 비즈니스 전문가가 쓰는 용어를 개발자가 '무조건' 변수명과 클래스명으로 씁니다. 영어 이름이 어색해도 씁니다.
- 3단계: 살아있는 문서: 이렇게 짜면 코드가 곧 기획서가 됩니다. 기획자가 소스코드를 읽고 "어? 왜
cancel다음에refund가 안 불리죠?"라고 지적할 수 있게 되는, 비즈니스와 기술의 완벽한 동기화를 해부합니다.
- 1단계: 바벨탑의 저주: 기획자는 회의에서 "티켓(Ticket)"이라고 합니다. 개발자는 그걸 듣고 머릿속으로 번역해서 소스코드에는
- Implement: 보편 언어 불일치(Translation) 린터 검출 모사.
Business Req: "User becomes VIP when total spent > $1000."Legacy Code:customer.updateRank(2) if customer.getTotal() > 1000.DDD Code:user.promoteToVIP() if user.getTotalSpent() > 1000. 비즈니스 룰과 코드 컨텍스트가 100% 밀착되어(Coupled) 번역기 없이 코드를 기획자에게 직접 읽어주는 시각화 렌더링.
Recommended
Core Topic 02: 장벽을 세워라, 바운디드 컨텍스트 (The Bounded Context)
- Why to Learn: 세상 모든 개념을 완벽하게 통합한 단 하나의 거대한 DB 테이블을 만들겠다는 망상을 부수고, '맥락(Context)'에 따라 똑같은 단어도 다르게 쪼개어 시스템 결합도를 낮추기 위함입니다.
- What to Learn:
- Concepts: Bounded Context (제한된 문맥), Linguistic Boundary, Monolith Decomposition, Microservices Boundary.
- Skills: 거대한
Product객체를, 카탈로그(전시) 컨텍스트의Product(사진, 설명, 리뷰)와 재고(배송) 컨텍스트의Product(무게, 바코드, 박스 사이즈) 2개의 독립된 마이크로서비스 DB로 찢어내기.
- How to Learn:
- 1단계: 하나의 진실은 없다: 쇼핑몰에서 '상품(Product)'이란 무엇입니까? 전시팀(Front)에게 상품은 '화려한 사진과 할인율'입니다. 창고팀(Logistics)에게 상품은 '가로세로 30cm, 무게 2kg짜리 짐짝'일 뿐입니다.
- 2단계: 괴물 합체 (Monolith): 이 둘을 억지로 하나의
Product테이블에 우겨넣으면, 전시팀이 사진을 업데이트할 때 창고팀이 락(Lock)에 걸려 박스를 포장하지 못하는 어처구니없는 참사가 벌어집니다. - 3단계: 장벽 치기 (Bounded Context): "여기는 카탈로그 컨텍스트야. 저기는 창고 컨텍스트야." 물리적으로 장벽을 치고, DB도 쪼갭니다(MSA). 창고 컨텍스트의 개발자는 카탈로그 쪽 사진 데이터가 어떻게 생겼는지 알 필요도 없고(Encapsulation), 오직 '무게'와 '바코드'에만 집중하면 되는 완벽한 인지적 해방을 뜯어봅니다.
- Implement: Bounded Context 모델 쪼개기 시뮬레이션.
God Class:User { id, password, address, creditCard, lastLogin }(결제팀과 배송팀이 매일 충돌).Action (Split):Context [Identity]:User { id, password, lastLogin }Context [Shipping]:Customer { id, address }Context [Billing]:Payer { id, creditCard }하나의 현실을 3개의 전혀 다른 도메인 객체로 쪼개어 트랜잭션 충돌(Deadlock)을 0으로 만드는 아키텍처 렌더링.
Practical
Core Topic 03: 정치학과 권력, 컨텍스트 매핑 (Context Mapping)
- Why to Learn: 쪼개진 컨텍스트(마이크로서비스)들이 서로 API로 데이터를 주고받을 때, 누가 인터페이스 규격을 정하고 누가 굽혀야 하는지 '팀 간의 권력(Power) 구조'를 명확히 설계하기 위함입니다.
- What to Learn:
- Concepts: Context Mapping, Upstream(상류) vs Downstream(하류), Customer-Supplier (고객-공급자), Conformist (순응주의자), Partnership, Shared Kernel.
- Skills: 구글 맵스 API(Upstream)를 쓰는 우리 배달 앱(Downstream)의 권력 관계를 분석하여, "구글이 API 스펙을 바꾸면 우리는 무조건 따라야 하는 Conformist"임을 자각하고 방어 로직 설계하기.
- How to Learn:
- 1단계: 상류(Upstream)와 하류(Downstream): 강 상류에서 물을 더럽히면 하류는 똥물을 마셔야 합니다. 데이터(API)를 주는 쪽이 Upstream, 받는 쪽이 Downstream입니다.
- 2단계: Customer-Supplier (갑을 관계): 하류(결제팀)가 상류(주문팀)에게 "야, 우리 결제 쪽에 이 데이터 필요하니까 네 API 스펙 좀 이렇게 바꿔줘"라고 당당히 요구(Customer)할 수 있는 관계입니다.
- 3단계: Conformist (순응주의자): 상류가 '외부 카카오톡 API'입니다. 카카오가 API를 바꾸면 우리(Downstream)는 밤을 새워 코드를 뜯어고쳐서 맹목적으로 순응(Conformist)해야 합니다. 여기서 요구사항을 건의했다간 무시당합니다.
- 4단계: Shared Kernel (공유 커널): 도저히 분리가 안 돼서 두 팀이 딱 하나의 핵심 DB 테이블만 같이 쓰는 최후의 타협책입니다. 마이크로서비스 설계 시 각 팀 간의 정치적 종속성과 API 협상력을 선 긋는 매핑 지도를 해부합니다.
- Implement: Context Mapping 권력 관계 레이더 도출.
Node A (결제망 PG사)Node B (우리 쇼핑몰).관계 판정: PG사가 스펙을 내리면 무조건 복종해야 하므로Conformist또는ACL강제.Node B (주문)Node C (우리 배송).관계 판정: 사내 같은 부문 소속. 배송팀(C)의 요구로 주문팀(B)이 API를 맞춰주는Customer/Supplier관계 성립. 아키텍처가 곧 조직도(Conway's Law)라는 통찰 렌더링.
Advanced
Core Topic 04: 썩은 물의 방어막, 부패 방지 계층 (The Anti-Corruption Layer)
- Why to Learn: 도저히 건드릴 수 없는 20년 된 레거시 시스템과 연동해야 할 때, 그 레거시의 더러운 데이터 구조가 우리 팀의 최신(Modern) 도메인 모델로 전염되는 것을 목숨 걸고 막아내기 위함입니다.
- What to Learn:
- Concepts: ACL (Anti-Corruption Layer), OHS (Open Host Service), Facade Pattern, Adapter, Domain Translation.
- Skills: 레거시 ERP가 던지는
USR_STS_CD: "01"이라는 쓰레기 데이터를, 우리 도메인으로 들어오는 문지기(ACL) 클래스에서UserStatus.ACTIVE라는 깨끗한 Enum(보편 언어)으로 번역하여 시스템 내부를 보호하기.
- How to Learn:
- 1단계: 부패의 전이: 새로 런칭한 최신 '배달 앱'이 있습니다. 그런데 정산 데이터를 20년 된 '구형 ERP'로 보내야 합니다. 구형 ERP는 컬럼 이름이 전부 알 수 없는 일본어 한자 약어로 되어 있습니다. 바쁘다고 우리 배달 앱 소스코드 안에서 그 한자 변수명을 섞어 쓰기 시작하면, 최신 앱이 한 달 만에 레거시 똥통으로 부패(Corruption)해 버립니다.
- 2단계: 방파제 (ACL): 두 컨텍스트 사이에 거대한 콘크리트 벽(ACL)을 세웁니다. 이 벽 안에는 번역기(Adapter/Facade)가 득실거립니다. 외부 시스템과 통신하는 건 오직 이 ACL뿐입니다.
- 3단계: 순수의 유지: 구형 ERP가 한자를 던지면, ACL이 그걸 받아서 예쁜 영어(Ubiquitous Language) 객체로 번역한 뒤 우리 도메인으로 넘겨줍니다. 훗날 구형 ERP가 최신 시스템으로 교체되어도, 우리는 내부 코드를 건드릴 필요 없이 외부 ACL 번역기만 갈아 끼우면 되는 극강의 격리 방어술을 뜯어봅니다.
- Implement: ACL(부패 방지 계층) 데이터 트랜스레이션 모사.
Legacy ERP (Upstream)API Response:{"X_FLAG": "Y", "DAT_VAL": "202412"}ACL (Adapter)진입:if X_FLAG=='Y' then isActive=true변환 규칙 가동.Modern Domain (Downstream)전달:class Account { boolean isActive = true; YearMonth expires = "2024-12" }. 더러운 외부 스키마가 도메인 코어(Core)로 단 1바이트도 침투하지 못하게 차단하는 헥사고날(Hexagonal) 방벽의 승리 시각화.
7. Terminology
8. References
Primary
- [P1] CS2023 - Software Engineering (SE) - Software Architecture (Domain-Driven Design, Bounded Contexts)
- [P5] SFIA - Systems Design (SYSD) - System decomposition and Context Mapping
Secondary
- [Domain-Driven Design] Eric Evans - Tackling Complexity in the Heart of Software (The Blue Book)
- [Implementing Domain-Driven Design] Vaughn Vernon - Strategic Design, Context Mapping (The Red Book)
Industry
- [MartinFowler.com] - BoundedContext, UbiquitousLanguage, AntiCorruptionLayer
- [AWS Prescriptive Guidance] - Decompose monoliths into microservices using DDD
9. Final Checklist
Primary
- 도메인 전문가가 "회원가입 완료 시 웰컴 쿠폰이 발행된다"고 말했는데, 개발자가 소스코드에
DBManager.insertCouponRow()라고 적어놓았을 때 발생하는 보편 언어(Ubiquitous Language) 파괴의 비즈니스적 손실을 지적할 수 있는가? - 수백 개의 필드를 가진 거대한
Order클래스를, '주문 접수 컨텍스트'와 '정산 컨텍스트', '배송 컨텍스트' 3개의 바운디드 컨텍스트(Bounded Context)로 무자비하게 쪼개어 각각의 마이크로서비스로 분립시키는 근거를 설명할 수 있는가?
Secondary
- 사내 공용 인증 시스템(Upstream)과 신규 서비스(Downstream) 간의 컨텍스트 매핑을 정의할 때, 신규 서비스 팀이 인증 API 스펙 변경에 대해 아무런 발언권이 없는 상황을 'Conformist(순응주의자)' 관계로 정의하고 그 리스크를 평가할 수 있는가?
- 똑같은 도메인 객체를 두 팀이 절반씩 수정해야 하는 상황에서 물리적 분리가 불가능해 'Shared Kernel(공유 커널)'을 선택했을 때, 이 테이블을 수정할 때마다 두 팀이 거쳐야 하는 극한의 CI(통합) 및 협의 프로세스의 비용을 논증할 수 있는가?
Industry
- 20년 된 메인프레임 은행망(
TX_CD_99)과 연동해야 하는 최신 모바일 뱅킹(TransactionType.REFUND) 시스템 사이에서, 외부의 썩은 레거시 모델이 내부로 오염되는 것을 차단하기 위해 트랜스레이터(번역기) 역할을 하는 ACL(Anti-Corruption Layer) 인터페이스를 설계할 수 있는가? - Conway의 법칙(시스템 아키텍처는 조직의 소통 구조를 닮는다)에 비추어 볼 때, 훌륭하게 설계된 Bounded Context 맵이 궁극적으로 어떻게 각 개발팀(Squad/Tribe)의 조직 개편과 인원 배치(Team Topology)의 뼈대가 되는지 거시적 관점에서 통찰할 수 있는가?