콘텐츠로 바로가기

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 등을 구체적으로 코드로 짜는 법 \rightarrow 09-03-05 DDD Tactical Patterns (별도 심화 모듈)로 위임.
  • 이벤트 스토밍(Event Storming) 워크숍 기법: 포스트잇을 붙이며 도메인 이벤트를 찾는 구체적 행위 \rightarrow 해당 문서는 '도출된 컨텍스트 매핑 아키텍처' 자체에 집중함.

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

Sequence Core Cluster Objective & Description Evidence (BoK)
1 Ubiquitous Language 기획자는 "상품"이라 부르고 DB는 "item", API는 "product"라 부르는 바벨탑의 재앙을 부수고 하나의 언어로 통일하는 권력을 쥡니다. P1
2 The Bounded Context "결제팀의 상품"과 "배송팀의 상품"은 이름만 같지 완전히 다른 외계인임을 선언하고, 둘 사이에 거대한 콘크리트 장벽(경계)을 쳐냅니다. P5
3 Context Mapping (Power Dynamics) 장벽을 친 A팀과 B팀이 데이터를 주고받을 때, 누가 갑이고 누가 을인지, 파트너인지 노예(Conformist)인지 정치적 권력 지형을 뜯어봅니다. Industry
4 The Anti-Corruption Layer (ACL) 더러운 레거시 시스템의 썩은 물이 우리 팀의 깨끗한 도메인으로 스며들지 못하게 완벽한 번역기이자 방파제(ACL)를 세우는 방어술을 장악합니다. Industry

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> 맵핑시켜 변수명 짓기.
  • How to Learn:
    • 1단계: 바벨탑의 저주: 기획자는 회의에서 "티켓(Ticket)"이라고 합니다. 개발자는 그걸 듣고 머릿속으로 번역해서 소스코드에는 Reservation 클래스로 짭니다. DBA는 테이블명을 tb_booking으로 짓습니다. 에러가 나면 셋이 모여 "예약 건수가 안 맞는데요?", "아, 티켓 테이블이요?"라며 번역하느라 시간을 허비합니다.
    • 2단계: 강제적 통일 (Ubiquitous): 도메인 주도 설계(DDD)의 1원칙입니다. 비즈니스 전문가가 쓰는 용어를 개발자가 '무조건' 변수명과 클래스명으로 씁니다. 영어 이름이 어색해도 씁니다.
    • 3단계: 살아있는 문서: 이렇게 짜면 코드가 곧 기획서가 됩니다. 기획자가 소스코드를 읽고 "어? 왜 cancel 다음에 refund가 안 불리죠?"라고 지적할 수 있게 되는, 비즈니스와 기술의 완벽한 동기화를 해부합니다.
  • 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) 번역기 없이 코드를 기획자에게 직접 읽어주는 시각화 렌더링.

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사) \rightarrow Node B (우리 쇼핑몰). 관계 판정: PG사가 스펙을 내리면 무조건 복종해야 하므로 Conformist 또는 ACL 강제. Node B (주문) \rightarrow 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"} \rightarrow ACL (Adapter) 진입: if X_FLAG=='Y' then isActive=true 변환 규칙 가동. \rightarrow Modern Domain (Downstream) 전달: class Account { boolean isActive = true; YearMonth expires = "2024-12" }. 더러운 외부 스키마가 도메인 코어(Core)로 단 1바이트도 침투하지 못하게 차단하는 헥사고날(Hexagonal) 방벽의 승리 시각화.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
Ubiquitous Language (보편 언어) 기획자, 비즈니스 리더, 개발자, 소스코드, 데이터베이스 테이블까지 예외 없이 완전히 똑같은 비즈니스 단어 사전을 강제로 쓰게 만들어 번역 비용을 박살 내는 DDD의 최우선 1원칙입니다. 기본 도메인 전문가와 개발자 간의 언어 통일 Domain Expert / Domain Model Jargon (기술 전문 용어) "한국어/영어"의 언어 통일이 아니라, "비즈니스 용어/코드 변수명"의 통일임. 코드가 비즈니스를 그대로 읽어줘야 함 P1:CS2023 core
Bounded Context (제한된 문맥) 똑같은 '상품(Product)'이라는 단어라도 전시팀 맥락(사진)과 배송팀 맥락(무게)이 완전히 다르므로, 이 의미의 충돌을 막기 위해 물리적/논리적으로 콘크리트 벽을 쳐버리는 마이크로서비스 분할의 기준점입니다. 권장 도메인 모델의 의미적 일관성 유지 Ubiquitous Language / Microservices Subdomain (문제 영역) Bounded Context는 조직이 시스템을 쪼개놓은 '해결책(Solution)'의 공간임. Subdomain(문제)과 1<1> 매칭되는 것이 이상적이지만 현실은 다름 P5:SFIA core
Context Mapping (컨텍스트 매핑) 쪼개진 바운디드 컨텍스트(A팀, B팀)들이 데이터를 주고받을 때, 누가 갑(Upstream)이고 누가 을(Downstream)인지, 팀 간의 정치적 권력과 API 종속성을 지도로 그려내는 전략 기법입니다. 실무 MSA 환경에서의 팀 간 연동 및 권력 구조 정의 Customer-Supplier / Conformist API Gateway 단순히 'API 호출 선'을 그리는 게 아니라, "B팀이 API 스펙을 바꾸면 A팀은 밤새서 쫓아가야 하는가?"라는 조직의 운명(Conway's Law)을 정의하는 것임 Industry core
Anti-Corruption Layer (부패 방지 계층, ACL) 우리가 통제할 수 없는 끔찍한 외부 레거시 시스템과 통신해야 할 때, 썩은 데이터 포맷이 우리 최신 도메인으로 스며들지 못하게 문지기(번역기)를 세워 격리하는 방어 패턴입니다. 심화 외부 종속성으로부터 내부 도메인 순수성 보호 Conformist / Facade / Adapter OHS (Open Host Service) 코드를 깔끔하게 짜기 위한 디자인 패턴(Facade)을 넘어, "저 외부 시스템은 언젠가 뜯어고쳐질 놈이니까 절연(Isolation)시키겠다"는 전략적 선전포고임 Industry core

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)의 뼈대가 되는지 거시적 관점에서 통찰할 수 있는가?

OOP & DDD

2 / 4