DDD 이론 2: 유비쿼터스 언어
DDD의 핵심 도구인 유비쿼터스 언어의 개념, 구축 방법, 실제 적용 사례를 깊이 있게 학습합니다.
Part 1: 유비쿼터스 언어의 이해
- 1. 유비쿼터스 언어란 무엇인가
- 2. 왜 유비쿼터스 언어가 필요한가
- 3. 언어 불일치의 실제 비용
Part 2: 유비쿼터스 언어 실천
- 4. 유비쿼터스 언어 구축하기
- 5. 코드에서의 유비쿼터스 언어
- 6. 유비쿼터스 언어 유지와 진화
- 7. 실제 사례와 안티패턴
Part 3: 심화 학습
- 8. 실습 워크숍: 유비쿼터스 언어 구축
- 9. Bounded Context와 유비쿼터스 언어
- 10. 실제 기업 사례 연구
- • 유비쿼터스 언어의 개념과 DDD에서의 중심적 역할을 이해한다
- • 언어 불일치가 프로젝트에 미치는 실제 비용을 파악한다
- • 도메인 전문가와 함께 유비쿼터스 언어를 구축하는 방법을 익힌다
- • 코드에서 유비쿼터스 언어를 표현하는 구체적인 기법을 학습한다
- • 언어를 지속적으로 유지하고 진화시키는 방법을 이해한다
- • Bounded Context와 유비쿼터스 언어의 관계를 파악한다
- • 실제 프로젝트에서의 성공/실패 사례를 통해 교훈을 얻는다
- • 실습을 통해 유비쿼터스 언어 구축 과정을 체험한다
Part 1: 유비쿼터스 언어의 이해
유비쿼터스 언어가 무엇이고 왜 중요한지 깊이 이해합니다
1. 유비쿼터스 언어란 무엇인가
"도메인 모델은 공통 언어의 중추가 될 수 있다. 이 언어의 사용을 팀 내 모든 의사소통과 코드에서 끈질기게 요구하라. 다이어그램, 문서, 특히 대화에서 같은 언어를 사용하라."
— Eric Evans, Domain-Driven Design, Chapter 2
유비쿼터스(Ubiquitous)의 의미
"Ubiquitous"는 라틴어에서 유래한 단어로 "어디에나 존재하는"이라는 뜻입니다. 유비쿼터스 언어는 프로젝트의 모든 곳에서, 모든 사람이,모든 상황에서 사용해야 합니다.
대화
회의, 토론, 일상 대화, 스탠드업
문서
요구사항, 설계 문서, 위키, 이메일
다이어그램
UML, 화이트보드, 아키텍처 도
코드
클래스명, 메서드명, 변수명, 테스트
유비쿼터스 언어의 핵심 특성
도메인 전문가의 언어 기반
개발자가 만든 기술 용어가 아니라, 도메인 전문가가 실제로 사용하는 비즈니스 용어를 기반으로 합니다. 개발자가 도메인 전문가의 언어를 배워야 합니다.
엄격하고 명확함
모호함이 없어야 합니다. 각 용어는 정확히 하나의 의미를 가지며, 팀 전체가 그 의미에 동의해야 합니다.
모델과 코드에 직접 반영
유비쿼터스 언어는 단순한 용어집이 아닙니다. 코드의 클래스명, 메서드명, 변수명에 그대로 나타나야 합니다.
Bounded Context 내에서 일관됨
같은 용어가 다른 Context에서는 다른 의미를 가질 수 있습니다. 하지만 하나의 Context 내에서는 반드시 일관되어야 합니다.
지속적으로 진화
도메인에 대한 이해가 깊어지면 언어도 함께 진화합니다. 언어의 변화는 모델의 변화를 의미합니다.
"언어의 변화를 모델의 변화로 인식하라. 도메인 전문가가 어색해하는 용어나 구조가 있다면, 그것은 모델에 문제가 있다는 신호다."
— Eric Evans, Domain-Driven Design, Chapter 2
2. 왜 유비쿼터스 언어가 필요한가
"소프트웨어 프로젝트에서 가장 흔한 실패 원인은 의사소통의 실패다. 개발자와 도메인 전문가가 서로 다른 언어로 말하면, 요구사항은 반드시 왜곡된다."
— Vaughn Vernon, Implementing Domain-Driven Design
전통적인 소프트웨어 개발의 의사소통 문제
❌ 번역의 연쇄 (Translation Chain)
도메인 전문가의 머릿속 지식
↓ (1차 번역: 말로 표현)
비즈니스 요구사항 문서
↓ (2차 번역: 분석가가 해석)
기능 명세서
↓ (3차 번역: 개발자가 해석)
기술 설계 문서
↓ (4차 번역: 코드로 구현)
실제 코드
⚠️ 각 번역 단계에서 의미가 손실되거나 왜곡됨!✓ 유비쿼터스 언어 사용 시
도메인 전문가 ←→ 개발자
↕
유비쿼터스 언어
↕
코드
✓ 같은 언어로 직접 소통, 번역 없음!언어 불일치가 발생하는 이유
🔧 개발자의 습관
- • 기술 용어 선호 (Entity, DTO, Service)
- • 구현 관점에서 사고
- • 축약어와 약어 남용
- • 도메인 학습에 시간 투자 꺼림
📊 도메인 전문가의 한계
- • 암묵적 지식이 많음
- • 당연하다고 생각해서 설명 안 함
- • 같은 용어를 다른 의미로 사용
- • 기술적 제약을 모름
🏢 조직의 문제
- • 개발팀과 비즈니스팀 분리
- • 문서 중심 의사소통
- • 직접 대화 기회 부족
- • 중간 전달자 (PM, BA) 의존
⏰ 시간 압박
- • 도메인 이해보다 빠른 구현 우선
- • 용어 정리할 시간 없음
- • 일단 동작하면 됨 마인드
- • 나중에 정리하자 (안 함)
3. 언어 불일치의 실제 비용
❌ 언어가 불일치할 때
도메인 전문가: "고객이 주문을 취소하면 환불 처리해야 해요."
개발자: "User 테이블에서 Order 레코드의 status를 CANCELLED로 업데이트하고, Payment 테이블에 refund 레코드를 INSERT 하면 되겠네요."
도메인 전문가: "...네? 무슨 말인지 모르겠어요. 그리고 부분 취소는요?"
개발자: "아, 부분 취소요? 그건 요구사항에 없었는데..."
→ 의사소통 실패, 요구사항 누락
✓ 유비쿼터스 언어를 사용할 때
도메인 전문가: "고객이 주문을 취소하면 환불 처리해야 해요."
개발자: "주문 취소 시 환불 정책은 어떻게 되나요? 전액 환불인가요, 부분 환불도 가능한가요?"
도메인 전문가: "배송 전이면 전액 환불, 배송 중이면 배송비 제외 환불이에요. 그리고 일부 상품만 취소하는 부분 취소도 있어요."
개발자: "그럼 주문 상태에 따라 환불 금액 계산 정책이 달라지는 거네요. 환불 정책을 별도 객체로 모델링하면 좋겠어요."
도메인 전문가: "네, 환불 정책이라는 표현이 정확해요. 우리도 그렇게 부르거든요."
→ 깊은 이해, 정확한 모델링
같은 단어, 다른 의미의 위험성
| 용어 | 마케팅팀 | 물류팀 | 개발팀 | CS팀 |
|---|---|---|---|---|
| 고객 | 잠재 구매자 포함 | 배송 수령인 | User 테이블 레코드 | 문의한 사람 |
| 주문 | 구매 의사 표현 | 배송해야 할 건 | Order 엔티티 | 클레임 대상 |
| 상품 | 판매 아이템 | 재고 관리 단위 | Product 테이블 | 반품 대상 |
| 취소 | 고객 이탈 | 배송 중단 | 상태 변경 | 환불 요청 |
⚠️ 위험: 같은 단어를 사용하지만 각 팀이 다른 의미로 이해하면 심각한 오해가 발생합니다. 회의에서 "고객"을 논의할 때 각자 다른 것을 상상하고 있을 수 있습니다.
언어 불일치의 실제 비용
💰 직접 비용
- • 요구사항 재작업 (전체 개발 비용의 30-50%)
- • 버그 수정 비용 증가
- • 회의 시간 낭비
- • 문서 재작성
⏰ 시간 비용
- • 새 팀원 온보딩 지연
- • 코드 이해 시간 증가
- • 의사결정 지연
- • 릴리스 지연
🔧 기술 부채
- • 도메인과 동떨어진 코드
- • 이해하기 어려운 모델
- • 변경하기 어려운 구조
- • 테스트하기 어려운 코드
😤 팀 비용
- • 팀 간 갈등
- • 신뢰 저하
- • 사기 저하
- • 이직률 증가
Part 2: 유비쿼터스 언어 실천
유비쿼터스 언어를 구축하고 유지하는 구체적인 방법을 학습합니다
4. 유비쿼터스 언어 구축하기
"유비쿼터스 언어를 구축하는 것은 일회성 작업이 아니다. 프로젝트 전체에 걸쳐 지속적으로 언어를 다듬고 발전시켜야 한다."
— Vaughn Vernon, Implementing Domain-Driven Design
언어 구축 5단계 프로세스
도메인 전문가의 언어 수집
도메인 전문가가 실제로 사용하는 용어를 그대로 수집합니다. 개발자가 임의로 번역하거나 기술 용어로 바꾸지 않습니다.
용어 정의 및 합의
각 용어의 정확한 의미를 정의하고, 팀 전체가 합의합니다. 모호한 용어는 명확하게 정의하거나 더 적절한 용어로 대체합니다.
용어집(Glossary) 작성
합의된 용어와 정의를 문서화합니다. 이 용어집은 팀의 공식 언어 사전이 됩니다.
코드에 반영
용어집의 용어를 클래스명, 메서드명, 변수명에 그대로 사용합니다. 코드가 곧 모델이 되어야 합니다.
지속적 정제
도메인 이해가 깊어지면 언어도 진화합니다. 새로운 통찰이 생기면 용어집과 코드를 함께 업데이트합니다.
용어집(Glossary) 작성 가이드
주문 (Order)
고객이 하나 이상의 상품을 구매하기 위해 생성한 거래 단위. 주문은 '주문 생성', '결제 완료', '배송 중', '배송 완료', '취소됨' 상태를 가진다.
코드: Order 클래스, OrderStatus enum
주문 항목 (Order Line Item)
주문 내의 개별 상품 항목. 상품, 수량, 단가, 소계를 포함한다. 주문은 최소 1개 이상의 주문 항목을 가져야 한다.
코드: OrderLineItem 클래스
주문하다 (Place Order)
고객이 장바구니의 상품들로 새로운 주문을 생성하는 행위. 재고 확인, 가격 계산, 결제 정보 검증이 선행되어야 한다.
코드: Order.place() 메서드, OrderPlaced 이벤트
취소하다 (Cancel Order)
고객 또는 시스템이 주문을 무효화하는 행위. 배송 전에만 가능하며, 취소 시 환불 프로세스가 시작된다.
코드: Order.cancel() 메서드, OrderCancelled 이벤트
환불 정책 (Refund Policy)
주문 취소 시 환불 금액을 결정하는 규칙. 배송 전 취소는 전액 환불, 배송 중 취소는 배송비 제외 환불.
코드: RefundPolicy 인터페이스, FullRefundPolicy, PartialRefundPolicy
5. 코드에서의 유비쿼터스 언어
"모델이 코드에 직접 반영되지 않으면, 그 모델은 무의미하다. 코드의 변경이 모델의 변경이고, 모델의 변경이 코드의 변경이어야 한다."
— Eric Evans, Domain-Driven Design, Chapter 2
코드로 표현하는 유비쿼터스 언어
❌ 기술 중심 네이밍
// 기술 용어로 가득한 코드
class OrderDTO {
private String id;
private List<ItemDTO> items;
private int statusCode;
private BigDecimal amount;
}
class OrderDAO {
void updateStatus(String id, int code);
void insertRefundRecord(String odId);
}
class OrderProcessor {
void process(OrderDTO dto) {
if (dto.getStatusCode() == 3) {
// 3이 뭐지? SHIPPED?
dao.updateStatus(dto.getId(), 5);
dao.insertRefundRecord(dto.getId());
}
}
}문제: 도메인 전문가가 이 코드를 보고 비즈니스 로직을 이해할 수 없음
✓ 유비쿼터스 언어 반영
// 도메인 언어가 살아있는 코드
class Order {
private OrderId id;
private List<OrderLineItem> lineItems;
private OrderStatus status;
private Money totalAmount;
void cancel(CancellationReason reason) {
if (this.status.isShipped()) {
throw new OrderAlreadyShipped();
}
this.status = OrderStatus.CANCELLED;
RefundPolicy policy =
RefundPolicy.forStatus(this.status);
Money refundAmount =
policy.calculateRefund(this);
this.registerEvent(
new OrderCancelled(this.id, refundAmount)
);
}
}장점: 코드가 비즈니스 규칙을 그대로 표현, 도메인 전문가도 검증 가능
Intention-Revealing Interface
메서드와 클래스의 이름은 "어떻게(How)"가 아니라 "무엇을(What)" 하는지를 드러내야 합니다. 이것이 에릭 에반스가 말하는 Intention-Revealing Interface입니다.
❌ 구현을 드러내는 이름
updateOrderStatusToFive() insertIntoRefundTable() setFlag(true) processData() handleEvent() doSomething()
✓ 의도를 드러내는 이름
cancelOrder() requestRefund() markAsShipped() placeOrder() confirmPayment() applyDiscount()
도메인 전문가가 읽을 수 있는 코드
좋은 도메인 코드는 도메인 전문가가 읽고 비즈니스 로직을 검증할 수 있어야 합니다. 주석이 아니라 코드 자체가 비즈니스 규칙을 설명해야 합니다.
// 도메인 전문가도 이해할 수 있는 비즈니스 로직
class Order {
void cancel(CancellationReason reason) {
// "배송된 주문은 취소할 수 없다"
if (this.status.isShipped()) {
throw new CannotCancelShippedOrder();
}
// "취소 사유를 기록한다"
this.cancellationReason = reason;
// "주문 상태를 '취소됨'으로 변경한다"
this.status = OrderStatus.CANCELLED;
// "환불 정책에 따라 환불 금액을 계산한다"
Money refundAmount = this.refundPolicy
.calculateRefundFor(this);
// "주문 취소 이벤트를 발행한다"
this.registerEvent(new OrderCancelled(
this.id,
reason,
refundAmount,
this.cancelledAt
));
}
// 도메인 전문가의 언어로 된 쿼리 메서드
boolean canBeCancelled() {
return !this.status.isShipped()
&& !this.status.isDelivered();
}
boolean isEligibleForFullRefund() {
return this.status.isBeforeShipping();
}
}테스트 코드에서의 유비쿼터스 언어
테스트 코드는 도메인 행위의 명세서 역할을 합니다. 테스트 이름과 구조도 유비쿼터스 언어를 따라야 합니다.
// BDD 스타일: Given-When-Then이 도메인 언어로 표현됨
describe('주문 취소', () => {
it('배송 전 주문은 취소할 수 있다', () => {
// Given: 결제 완료된 주문이 있다
const order = OrderFixture.paidOrder();
// When: 고객이 주문을 취소한다
order.cancel(CancellationReason.CUSTOMER_REQUEST);
// Then: 주문 상태가 '취소됨'이 된다
expect(order.status).toBe(OrderStatus.CANCELLED);
// And: 전액 환불이 요청된다
expect(order.domainEvents).toContainEqual(
expect.objectContaining({
type: 'OrderCancelled',
refundAmount: order.totalAmount
})
);
});
it('배송된 주문은 취소할 수 없다', () => {
// Given: 배송 중인 주문이 있다
const order = OrderFixture.shippedOrder();
// When & Then: 취소 시도하면 예외가 발생한다
expect(() => {
order.cancel(CancellationReason.CUSTOMER_REQUEST);
}).toThrow(CannotCancelShippedOrder);
});
});6. 유비쿼터스 언어 유지와 진화
📅 정기적인 모델링 세션
- • 주 1회 도메인 전문가와 모델 리뷰
- • 새로운 요구사항을 언어로 먼저 표현
- • 어색한 용어나 표현 발견 시 즉시 논의
- • Event Storming 정기 세션
📖 용어집 관리
- • 위키나 Notion으로 용어집 유지
- • 새 용어 추가 시 팀 전체 공유
- • 용어집을 코드와 함께 버전 관리
- • 정기적인 용어집 리뷰 (월 1회)
🔍 코드 리뷰 체크리스트
- • 클래스/메서드명이 용어집과 일치하는가?
- • 도메인 전문가가 이해할 수 있는 코드인가?
- • 기술 용어가 도메인 계층에 침투하지 않았는가?
- • 새로운 도메인 개념이 용어집에 추가되었는가?
🚨 언어 변경 신호
- • 도메인 전문가가 새로운 용어를 사용
- • 기존 용어로 설명하기 어려운 개념 등장
- • 코드가 비즈니스 로직을 표현하지 못함
- • 팀원들이 같은 것을 다르게 부름
"언어의 변화에 귀를 기울여라. 도메인 전문가가 당신의 용어를 교정할 때, 그것은 모델을 개선할 기회다. 그들이 당신의 언어를 채택할 때, 그것은 모델이 유용하다는 신호다."
— Eric Evans, Domain-Driven Design, Chapter 2
7. 실제 사례와 안티패턴
흔한 실수와 해결책
실수 1: 개발자만의 언어 사용
"Entity", "Repository", "Service", "DTO" 같은 기술 용어를 도메인 전문가와의 대화에서 사용
해결: 도메인 전문가가 사용하는 비즈니스 용어로 대화하고, 기술 용어는 개발자 간에만 사용
실수 2: 용어집을 만들고 방치
초기에 용어집을 만들었지만 업데이트하지 않아 현실과 괴리
해결: 용어집을 코드와 함께 버전 관리하고, 스프린트마다 리뷰. 용어집 업데이트를 Definition of Done에 포함
실수 3: 번역 계층 도입
도메인 언어와 코드 언어 사이에 번역 계층을 두어 복잡성 증가
해결: 코드가 곧 모델이 되도록 직접 반영. 번역이 필요하면 모델을 수정
실수 4: 영어 강제
한국 도메인 전문가와 일하면서 모든 용어를 영어로 번역하여 의미 손실
해결: 도메인 전문가의 언어(한국어)를 존중. 코드에서는 영어로 표현하되, 용어집에 한국어-영어 매핑 유지
실수 5: 모호한 용어 방치
"처리하다", "관리하다" 같은 모호한 동사를 그대로 사용
해결: 구체적인 행위로 분해. "주문을 처리하다" → "주문을 확인하다", "결제를 요청하다", "배송을 시작하다"
8. 실습 워크숍: 유비쿼터스 언어 구축
당신은 온라인 서점 시스템을 개발하는 팀의 개발자입니다. 도메인 전문가(서점 운영 담당자)와 첫 미팅을 진행합니다.
Step 1: 도메인 전문가 인터뷰
개발자: "고객이 책을 구매하는 과정을 설명해주시겠어요?"
도메인 전문가: "고객이 도서를 장바구니에 담고, 주문을 하면 결제가 진행돼요. 결제가 완료되면 배송이 시작되고요."
개발자: "도서와 상품은 같은 건가요?"
도메인 전문가: "아뇨, 우리는 '상품'이라고 안 해요. 항상 '도서'라고 부르죠. 그리고 eBook과 종이책을 구분해요."
개발자: "재고 관리는 어떻게 하시나요?"
도메인 전문가: "종이책은 재고가 있어요. 입고되면 재고가 늘고, 출고되면 줄어요. eBook은 재고 개념이 없고요."
💡 발견한 용어 (노란색 하이라이트)
도서, 장바구니, 주문, 결제, 배송, eBook, 종이책, 재고, 입고, 출고
Step 2: 용어 정의 및 관계 파악
| 용어 | 정의 | 영문 | 관계 |
|---|---|---|---|
| 도서 | 판매하는 책. eBook과 종이책으로 구분 | Book | 주문항목에 포함됨 |
| 종이책 | 물리적 형태의 도서. 재고 관리 필요 | PaperBook | 도서의 하위 유형 |
| eBook | 디지털 형태의 도서. 재고 없음 | EBook | 도서의 하위 유형 |
| 장바구니 | 구매 전 도서를 임시 보관하는 공간 | Cart | 고객당 1개 |
| 주문 | 고객의 구매 요청 단위 | Order | 여러 주문항목 포함 |
| 재고 | 종이책의 현재 보유 수량 | Stock / Inventory | 종이책에만 적용 |
Step 3: 코드로 표현
// 용어집이 그대로 코드가 됨
abstract class Book {
readonly bookId: BookId;
readonly title: string;
readonly author: Author;
readonly price: Money;
readonly publisher: Publisher;
abstract getBookType(): BookType;
}
class PaperBook extends Book {
readonly isbn: ISBN;
getBookType(): BookType {
return BookType.PAPER;
}
}
class EBook extends Book {
readonly fileFormat: FileFormat;
readonly downloadUrl: string;
getBookType(): BookType {
return BookType.EBOOK;
}
}
// 재고는 종이책에만 적용
class Stock {
readonly bookId: BookId; // PaperBook만 해당
private quantity: number;
receive(amount: number): void { // 입고
this.quantity += amount;
this.registerEvent(new StockReceived(this.bookId, amount));
}
release(amount: number): void { // 출고
if (this.quantity < amount) {
throw new InsufficientStock(this.bookId);
}
this.quantity -= amount;
this.registerEvent(new StockReleased(this.bookId, amount));
}
}9. Bounded Context와 유비쿼터스 언어
"유비쿼터스 언어는 Bounded Context 내에서만 유효하다. 같은 용어가 다른 Context에서는 완전히 다른 의미를 가질 수 있다."
— Vaughn Vernon, Implementing Domain-Driven Design
Context별 언어의 차이
같은 "고객"이라는 용어가 Context마다 다른 의미를 가짐
📦 주문 Context
고객 (Customer)
- • 주문을 생성하는 주체
- • 배송지 정보 보유
- • 주문 이력 조회 가능
class Customer {
customerId: CustomerId
shippingAddress: Address
orderHistory: Order[]
}💳 결제 Context
고객 (Payer)
- • 결제 수단 보유자
- • 신용 정보
- • 결제 한도
class Payer {
payerId: PayerId
paymentMethods: PaymentMethod[]
creditLimit: Money
}📊 마케팅 Context
고객 (Lead)
- • 마케팅 대상
- • 선호도 정보
- • 세그먼트 분류
class Lead {
leadId: LeadId
preferences: Preference[]
segment: Segment
}⚠️ 핵심: 각 Context는 자신만의 유비쿼터스 언어를 가집니다. "고객"을 전사적으로 통일하려 하면 모든 Context가 복잡해집니다.
Context 간 번역
서로 다른 Context가 통신할 때는 명시적인 번역이 필요합니다. 이것이 Anti-Corruption Layer의 역할입니다.
// 주문 Context에서 결제 Context로 요청할 때
class PaymentAntiCorruptionLayer {
constructor(private paymentService: PaymentService) {}
// 주문 Context의 언어 → 결제 Context의 언어로 번역
requestPayment(customer: Customer, order: Order): PaymentResult {
// Customer → Payer로 번역
const payer = this.translateToPayer(customer);
// Order → PaymentRequest로 번역
const paymentRequest = this.translateToPaymentRequest(order);
// 결제 Context의 언어로 호출
return this.paymentService.processPayment(payer, paymentRequest);
}
private translateToPayer(customer: Customer): Payer {
return new Payer(
PayerId.from(customer.customerId),
customer.defaultPaymentMethod
);
}
private translateToPaymentRequest(order: Order): PaymentRequest {
return new PaymentRequest(
order.orderId.toString(),
order.totalAmount,
order.currency
);
}
}10. 실제 기업 사례 연구
상황
대출 심사 시스템에서 "고객", "신청자", "차주"를 혼용하여 사용. 개발팀은 모두 "User"로 처리하고 있었음.
적용한 방법
- • 도메인 전문가(심사역)와 2주간 집중 워크숍 진행
- • 대출 프로세스 단계별 용어 정의: 신청자 → 심사대상자 → 승인자 → 차주
- • 각 단계별 상태와 행위를 명확히 구분
- • 코드의 User 클래스를 4개의 명확한 클래스로 분리
결과
- • 요구사항 오해로 인한 버그 70% 감소
- • 신규 개발자 온보딩 시간 50% 단축
- • 도메인 전문가가 코드 리뷰에 참여 가능해짐
상황
빠른 성장으로 개발팀이 급격히 확대. 각 팀이 독자적인 용어를 사용하기 시작. "주문"이 팀마다 다른 의미로 사용됨.
문제점
- • 주문팀: 주문 = 결제 전 장바구니 확정
- • 결제팀: 주문 = 결제 완료된 거래
- • 배송팀: 주문 = 출고 요청 건
- • 통합 시 데이터 불일치로 대규모 장애 발생
교훈
- • 초기부터 용어집 관리가 필수
- • Context 경계를 명확히 하고 각 Context의 언어를 정의해야 함
- • 팀 간 통합 시 번역 계층(ACL) 필요
핵심 요약
이번 세션에서 배운 것
- ✓유비쿼터스 언어는 모든 곳에서 사용되는 공유 언어다
- ✓언어 불일치는 번역 비용과 지식 손실을 야기한다
- ✓용어집을 만들고 코드에 직접 반영해야 한다
- ✓Intention-Revealing Interface로 의도를 드러내라
- ✓언어는 지속적으로 정제하고 발전시켜야 한다
- ✓테스트 코드도 유비쿼터스 언어를 따라야 한다
- ✓유비쿼터스 언어는 Bounded Context 내에서만 유효하다
- ✓Context 간 통신에는 명시적 번역(ACL)이 필요하다
다음 세션 예고
다음 세션에서는 도메인과 서브도메인에 대해 학습합니다.
- • Core, Supporting, Generic 서브도메인
- • Distillation과 전략적 투자
- • 어디에 DDD를 적용할 것인가
- • Domain Vision Statement
참고 자료
📚 필수 읽기
- • Eric Evans, DDD Chapter 2: "Communication and the Use of Language"
- • Vaughn Vernon, IDDD Chapter 2: "Domains, Subdomains, and Bounded Contexts"
- • Martin Fowler, "UbiquitousLanguage" - martinfowler.com
🎯 실습 과제
- • 현재 프로젝트의 핵심 도메인 용어 10개를 정의해보세요
- • 코드에서 기술 용어로 된 클래스명을 도메인 용어로 바꿔보세요
- • 도메인 전문가에게 코드를 보여주고 피드백을 받아보세요
- • 팀 용어집을 Wiki에 작성하고 공유하세요