用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/puk0806/gugbab-claude --skill ddd命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | ddd |
| user-invocable | false |
| description | DDD(Domain-Driven Design) 아키텍처 핵심 패턴 - 유비쿼터스 언어, 서브도메인, 바운디드 컨텍스트, Aggregate, Entity/VO, 도메인 서비스/이벤트, 레이어드 아키텍처 |
소스: Eric Evans, "Domain-Driven Design: Tackling Complexity in the Heart of Software" (Addison-Wesley, 2003) 소스: Vaughn Vernon, "Implementing Domain-Driven Design" (Addison-Wesley, 2013) 소스: https://www.domainlanguage.com/ddd/reference/ (Evans DDD Reference) 검증일: 2026-08-26 (최초 2026-04-17 · 08-26 freshness 재검증: 서적 기반이라 내용 변경 없음. 프론트엔드 폴더 구조에 바운디드 컨텍스트를 적용하는 절은
architecture/frontend-domain-structure스킬이 담당)
도메인 전문가와 개발자가 동일한 용어를 사용하여 소통하는 공유 언어.
핵심 원칙:
실천 방법:
// 나쁜 예: 기술 용어 중심
class DataProcessor { fn handle_record(r: Record) }
// 좋은 예: 유비쿼터스 언어 반영
class OrderFulfillment { fn ship_order(order: Order) }
비즈니스 도메인을 전략적으로 분류하는 단위.
주의: Core Domain과 Generic Subdomain은 Evans 원저(2003) Chapter 15(Distillation)에서 명시됨. 3종 분류(Core/Supporting/Generic)의 명시적 체계화는 Vernon IDDD(2013) Chapter 2·9에서 이루어짐.
| 유형 | 설명 | 투자 수준 | 예시 |
|---|---|---|---|
| Core Domain | 비즈니스 핵심 경쟁력. 차별화 요소 | 최고 투자, 최고 인재 | 추천 알고리즘, 가격 책정 엔진 |
| Supporting Subdomain | Core를 지원하지만 차별화 요소는 아님 | 중간 투자 | 재고 관리, 배송 추적 |
| Generic Subdomain | 범용적, 어디서나 비슷한 솔루션 | 최소 투자, 외부 솔루션 활용 | 인증, 결제, 이메일 발송 |
판단 기준:
유비쿼터스 언어가 일관된 의미를 가지는 명시적 경계. 같은 용어라도 컨텍스트가 다르면 의미가 다를 수 있다.
핵심 원칙:
// 주문 컨텍스트: "Product"는 이름, 가격, 수량을 가진다
mod ordering {
struct Product { name: String, price: Money, quantity: u32 }
}
// 카탈로그 컨텍스트: "Product"는 설명, 이미지, 카테고리를 가진다
mod catalog {
struct Product { description: String, images: Vec<Url>, category: Category }
}
바운디드 컨텍스트 간의 관계를 시각화하는 전략적 도구.
주의: Evans DDD Reference(2015 개정판) 기준 9가지 패턴. Partnership과 Big Ball of Mud는 Evans 원저(2003) 초판에는 명시적 패턴으로 없었으며, Evans DDD Reference(2015)에서 정식 수록됨. (출처: ddd-crew/context-mapping)
| 패턴 | 설명 | 사용 시점 |
|---|---|---|
| Shared Kernel | 두 컨텍스트가 모델 일부를 공유 | 긴밀히 협력하는 팀, 공유 비용 < 중복 비용 |
| Customer-Supplier | 상류(Supplier)가 하류(Customer) 요구를 수용 | 상류가 하류 니즈를 반영할 의지가 있을 때 |
| Conformist | 하류가 상류 모델을 그대로 수용 | 상류가 변경에 비협조적일 때 |
| Anticorruption Layer (ACL) | 하류가 번역 계층으로 상류 모델을 격리 | 레거시 연동, 외부 시스템 통합 |
| Open Host Service (OHS) | 상류가 공개 프로토콜/API를 제공 | 다수 하류 컨텍스트가 접근할 때 |
| Published Language (PL) | 공유 언어(JSON Schema, Protobuf 등)로 교환 | OHS와 함께 사용, 표준 포맷 필요 시 |
| Separate Ways | 통합하지 않고 독립적으로 구현 | 통합 비용 > 중복 비용 |
| Partnership | 두 팀이 동시에 조율하며 통합. 한쪽이 변경하면 다른 쪽도 함께 변경 | 두 팀의 목표가 강하게 연결될 때 |
| Big Ball of Mud | 경계가 없는 혼재 상태. 피해야 할 반패턴 | 현실 레거시 시스템 현황 파악 시 |
Aggregate: 일관성(consistency) 경계를 형성하는 관련 객체의 클러스터.
Aggregate Root: Aggregate의 진입점. 외부에서 Aggregate 내부 객체에 직접 접근하지 못하게 막는다.
핵심 규칙:
// Order가 Aggregate Root
struct Order {
id: OrderId,
items: Vec<OrderItem>, // 내부 Entity
status: OrderStatus,
}
impl Order {
// 불변식: 주문 총액이 0 이하이면 안 됨
pub fn add_item(&mut self, product_id: ProductId, qty: u32, price: Money) -> Result<(), OrderError> {
let item = OrderItem::new(product_id, qty, price);
self.items.push(item);
self.validate_total()?;
Ok(())
}
// 외부에서 OrderItem을 직접 변경할 수 없음
pub fn items(&self) -> &[OrderItem] {
&self.items
}
}
struct Customer {
id: CustomerId, // 식별자
name: String, // 변경 가능
email: Email, // 변경 가능
}
// 두 Customer는 id가 같으면 동일 Entity
#[derive(Clone, PartialEq, Eq)]
struct Money {
amount: u64,
currency: Currency,
}
#[derive(Clone, PartialEq, Eq)]
struct Address {
street: String,
city: String,
zip: String,
}
// 모든 필드가 같으면 동일 Value Object
판단 기준:
특정 Entity나 Value Object에 자연스럽게 속하지 않는 도메인 로직을 담는 무상태(stateless) 서비스.
사용 조건 (3가지 모두 충족 시):
// 도메인 서비스: 두 계좌 간 이체 로직
// -> Account 하나에 속하지 않고, 도메인 개념이며, 무상태
trait TransferService {
fn transfer(
&self,
from: &mut Account,
to: &mut Account,
amount: Money,
) -> Result<(), TransferError>;
}
주의: 도메인 서비스를 남용하면 빈약한 도메인 모델(Anemic Domain Model)이 된다. Entity/VO에 로직을 넣을 수 있다면 그쪽이 우선이다.
도메인에서 발생한 의미 있는 사건을 표현하는 객체. 과거형으로 명명한다.
출처 구분:
핵심 원칙:
OrderPlaced, PaymentCompleted, ItemShippedstruct OrderPlaced {
order_id: OrderId,
customer_id: CustomerId,
items: Vec<OrderItemSnapshot>,
total: Money,
occurred_at: DateTime<Utc>,
}
// Aggregate 내에서 이벤트 발행
impl Order {
pub fn place(/* ... */) -> (Self, OrderPlaced) {
let order = Order { /* ... */ };
let event = OrderPlaced { /* ... */ };
(order, event)
}
}
Evans가 제시한 4계층 구조. 핵심 원칙: 의존성은 위에서 아래로만 흐른다.
┌─────────────────────────────────┐
│ User Interface (Presentation) │ ← API 핸들러, DTO, 직렬화
├─────────────────────────────────┤
│ Application │ ← 유스케이스 오케스트레이션, 트랜잭션
├─────────────────────────────────┤
│ Domain │ ← Entity, VO, Aggregate, Domain Service
├─────────────────────────────────┤
│ Infrastructure │ ← DB, 외부 API, 메시징, 프레임워크
└─────────────────────────────────┘
| 계층 | 책임 | 포함 요소 |
|---|---|---|
| User Interface | 사용자 요청 수신, 응답 반환 | Controller, Handler, DTO, Serializer |
| Application | 유스케이스 조합, 흐름 제어 | Application Service, Command/Query Handler |
| Domain | 비즈니스 규칙, 불변식 | Entity, VO, Aggregate, Domain Service, Domain Event |
| Infrastructure | 기술적 구현 | Repository 구현체, DB 클라이언트, 메시지 브로커 |
의존성 규칙:
// 폴더 구조 예시
src/
├── presentation/ # User Interface 계층
│ ├── handlers/
│ └── dto/
├── application/ # Application 계층
│ ├── commands/
│ └── queries/
├── domain/ # Domain 계층
│ ├── models/
│ ├── services/
│ └── events/
└── infrastructure/ # Infrastructure 계층
├── persistence/
└── external/
적합한 경우:
적합하지 않은 경우:
| 실수 | 올바른 접근 |
|---|---|
| 모든 프로젝트에 DDD 적용 | Core Domain에만 전술적 패턴 적용, Generic은 단순하게 |
| Aggregate를 크게 설계 | 작은 Aggregate + 도메인 이벤트로 결과적 일관성 |
| Entity에 로직 없이 getter/setter만 | 비즈니스 로직을 Entity/VO 안에 캡슐화 (Rich Domain Model) |
| 바운디드 컨텍스트 무시하고 공유 모델 사용 | 컨텍스트별 독립 모델, ACL로 번역 |
| 도메인 서비스 남용 | Entity/VO에 로직을 먼저 배치, 서비스는 최후 수단 |
| 기술적 관심사가 Domain 계층에 침투 | Domain 계층은 프레임워크/DB 무관하게 순수 비즈니스 로직만 |