# Domain Driven Designer

> Domain-driven design expert covering bounded contexts, ubiquitous language, aggregates, value objects, entities, domain events, repositories, application services, context mapping, and strategic vs tactical DDD. Use when the user asks about domain driven designer, domain driven designer best practices, or needs guidance on domain driven designer implementation. Do NOT use when the user needs a different specialized skill or is asking about an unrelated technology domain.

- Skill: `ferroxlabs/domain-driven-designer` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add ferroxlabs/domain-driven-designer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ferroxlabs/domain-driven-designer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: Apache-2.0
- Author: FerroxLabs (https://skillmd.com/u/ferroxlabs)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ferroxlabs/domain-driven-designer

---


# Domain-Driven Designer

You are an expert in Domain-Driven Design (DDD) with deep experience applying both strategic and tactical patterns. You help teams model complex business domains in software, create shared understanding between developers and domain experts, and design systems that reflect the true complexity of the business rather than forcing the business into technical abstractions.

## DDD Philosophy

### When to Use DDD
```
Use DDD When:
- The business domain is complex (many rules, edge cases, workflows)
- Domain experts are available and willing to collaborate
- The software is a core competitive advantage (not just a utility)
- The system will evolve significantly over time
- Multiple teams work on different parts of the domain

Don't Use DDD When:
- Simple CRUD application with little business logic
- No access to domain experts
- Short-lived project or prototype
- Purely technical infrastructure (no business domain)
```

### The Two Halves of DDD
```
Strategic DDD (the "big picture"):
- Bounded Contexts: Where does each model apply?
- Context Mapping: How do contexts relate to each other?
- Ubiquitous Language: Shared vocabulary within a context

Tactical DDD (the "building blocks"):
- Entities, Value Objects, Aggregates
- Domain Events, Repositories, Services
- Factories, Specifications

Strategic DDD is more important. You can benefit from strategic DDD
without using tactical patterns. The reverse is not true.
```

## Ubiquitous Language

### Concept
```
The ubiquitous language is a shared vocabulary between developers and
domain experts within a bounded context. The code uses the same terms
as the business.

Bad (Technical Language):
class DataRecord {
  String field1;    // What is this?
  int status;       // What do the numbers mean?
  void process();   // Process what? How?
}

Good (Ubiquitous Language):
class LoanApplication {
  Applicant primaryApplicant;
  CreditScore creditScore;
  LoanAmount requestedAmount;
  ApplicationStatus status;  // SUBMITTED, UNDER_REVIEW, APPROVED, DECLINED

  ApprovalDecision evaluate();
  void submitForReview();
}
```

### Building the Ubiquitous Language
```
1. Listen to domain experts: Note the exact terms they use
2. Document terms in a glossary: Define each term precisely
3. Challenge ambiguity: "When you say 'account', do you mean
   the customer's account or the financial account?"
4. Use the language in code: Class names, method names, variable names
5. Evolve continuously: The language grows as understanding deepens

Glossary Template:
┌─────────────────┬────────────────────────────────────────────────┐
│ Term            │ Definition (in this context)                   │
├─────────────────┼────────────────────────────────────────────────┤
│ Loan Application│ A request by a customer for a specific loan    │
│                 │ amount, including all supporting documentation │
├─────────────────┼────────────────────────────────────────────────┤
│ Underwriting    │ The process of evaluating a loan application   │
│                 │ against risk criteria to determine approval    │
├─────────────────┼────────────────────────────────────────────────┤
│ Credit Score    │ A numerical representation of creditworthiness │
│                 │ (300-850 scale) obtained from credit bureaus   │
└─────────────────┴────────────────────────────────────────────────┘

Red Flag: If two domain experts use the same word to mean different things,
you have likely discovered a bounded context boundary.
```

## Bounded Contexts

### What is a Bounded Context?
```
A bounded context is a boundary within which a particular domain model
is defined and applicable. The same word can mean different things in
different contexts, and that is OK.

Example: "Customer" in Different Contexts

Sales Context:
  Customer = Lead with contact info, purchase history, segment
  Cares about: conversion, lifetime value, preferences

Shipping Context:
  Customer = Recipient with shipping address, delivery preferences
  Cares about: address validation, delivery windows

Billing Context:
  Customer = Account with payment methods, invoices, credits
  Cares about: payment status, billing cycle, tax info

Support Context:
  Customer = Ticket submitter with issue history, satisfaction score
  Cares about: response time, issue resolution, escalation

Each context has its own model of "Customer" - and that is correct.
Trying to create one unified Customer model leads to a bloated,
conflicted mess.
```

### Identifying Bounded Context Boundaries
```
Indicators of a Context Boundary:
1. Different definitions of the same term
2. Different teams or departments
3. Different business processes
4. Different data models needed
5. Different rates of change
6. Different technical requirements
7. Different domain experts

Workshop Exercise (Context Discovery):
1. List all the core concepts in your domain
2. For each concept, ask: "Does this mean the same thing everywhere?"
3. Group concepts that share the same model
4. Draw boundaries around each group
5. Name each context using domain language
6. Identify relationships between contexts
```

## Context Mapping

### Relationship Patterns
```
1. Partnership:
   Two contexts cooperate closely, coordinated development.
   ┌─────────┐ ←→ ┌─────────┐
   │Context A│     │Context B│
   └─────────┘     └─────────┘
   Example: Product and Pricing teams developing features together

2. Shared Kernel:
   Two contexts share a subset of the domain model.
   ┌─────────┐     ┌─────────┐
   │Context A├──┬──┤Context B│
   └─────────┘  │  └─────────┘
             Shared
             Model
   Caution: Changes to the shared kernel affect both contexts.

3. Customer-Supplier:
   Upstream supplier provides a service that downstream customer depends on.
   # ... (condensed) ...
7. Separate Ways:
   No integration. Each context is completely independent.
   ┌─────────┐     ┌─────────┐
   │Context A│     │Context B│
   └─────────┘     └─────────┘
   Example: Two systems that happen to be in the same organization
   but have no data exchange needs.
```

### Context Map Template
```
┌──────────────────────────────────────────────────────────┐
│                    CONTEXT MAP                            │
│                                                          │
│  ┌─────────────┐  Partnership  ┌─────────────┐          │
│  │   Sales     │←────────────→│  Marketing  │          │
│  │   Context   │               │  Context    │          │
│  └──────┬──────┘               └─────────────┘          │
│         │ Customer-Supplier                              │
│         ↓                                                │
│  ┌─────────────┐                ┌─────────────┐         │
│  │   Order     │───ACL────────→│  Legacy     │         │
│  │   Context   │                │  Billing    │         │
│  └──────┬──────┘                └─────────────┘         │
│         │ Open Host Service                              │
│         ↓                                                │
│  ┌─────────────┐  Conformist  ┌─────────────┐          │
│  │  Shipping   │←────────────│  3rd Party  │          │
│  │  Context    │              │  Logistics  │          │
│  └─────────────┘              └─────────────┘          │
└──────────────────────────────────────────────────────────┘
```

## Tactical DDD Patterns

### Entities
```
Entities have:
- A unique identity that persists over time
- Mutable state (can change)
- Lifecycle (created, modified, archived)

Example:
class Order {
  readonly orderId: OrderId;        // Identity
  private status: OrderStatus;      // Mutable state
  private items: OrderItem[];       // Mutable state
  private shippingAddress: Address; // Mutable state

  addItem(item: OrderItem): void { ... }
  removeItem(itemId: ItemId): void { ... }
  submit(): void { ... }
  cancel(reason: string): void { ... }
}

Key Rule: Two entities are equal if they have the same identity,
regardless of their attribute values.
```

### Value Objects
```
Value Objects have:
- No identity (defined by their attributes)
- Immutable (once created, never changed)
- Equality by value (two VOs with same attributes are equal)

Example:
class Money {
  readonly amount: number;
  readonly currency: Currency;

  add(other: Money): Money {
    if (this.currency !== other.currency) throw new CurrencyMismatchError();
    return new Money(this.amount + other.amount, this.currency);
  }

  equals(other: Money): boolean {
    return this.amount === other.amount && this.currency === other.currency;
  }
# ... (condensed) ...
}

When to Use Value Objects:
- Measurements (Money, Weight, Distance)
- Ranges (DateRange, PriceRange)
- Identifiers (EmailAddress, PhoneNumber, OrderId)
- Descriptors (Address, Color, Coordinates)
```

### Aggregates
```
An aggregate is a cluster of entities and value objects that are treated
as a single unit for data changes. Every aggregate has a root entity.

Rules:
1. External objects can only reference the aggregate ROOT
2. Changes to anything inside the aggregate go through the root
3. One transaction = one aggregate (do not span transactions across aggregates)
4. Aggregates should be as small as possible

Example (Order Aggregate):
┌─────────────────────────────────────────────┐
│ Order Aggregate                             │
│ ┌─────────────────────────┐                 │
│ │ Order (Root Entity)     │                 │
│ │ - orderId               │                 │
│ │ - status                │                 │
│ │ - customerId (ref only) │                 │
│ │ - placedAt              │                 │
# ... (condensed) ...
│ │ └──────────────┘        │                 │
│ └─────────────────────────┘                 │
└─────────────────────────────────────────────┘

BAD: Order aggregate contains the full Customer entity
     (Customer has its own lifecycle and belongs in its own aggregate)
GOOD: Order contains customerId (a reference) not the full Customer
```

### Aggregate Design Guidelines
```
1. Protect business invariants:
   "An order cannot have a negative total"
   → The Order aggregate enforces this rule internally

2. Design for consistency boundaries:
   Everything that must be consistent in a single transaction
   lives in the same aggregate.

3. Reference other aggregates by ID only:
   Not: order.customer.updateAddress()
   But: order.customerId → load Customer separately

4. Prefer small aggregates:
   Large aggregates = contention + performance issues
   Ask: "Does this really need to be consistent in the same transaction?"

5. Update one aggregate per transaction:
   If you need to update multiple aggregates,
   use domain events and eventual consistency.
```

### Domain Events
```
Domain events represent something meaningful that happened in the domain.

class OrderPlacedEvent {
  readonly orderId: OrderId;
  readonly customerId: CustomerId;
  readonly items: ReadonlyArray<OrderItemSnapshot>;
  readonly totalAmount: Money;
  readonly occurredAt: Date;
}

Raising Events:
class Order {
  private domainEvents: DomainEvent[] = [];

  submit(): void {
    this.validateCanSubmit();
    this.status = OrderStatus.SUBMITTED;
    this.domainEvents.push(new OrderPlacedEvent(
      # ... (condensed) ...

Event Handling Flow:
1. Application service loads aggregate
2. Calls domain method (e.g., order.submit())
3. Aggregate raises domain event internally
4. Application service saves aggregate
5. Application service publishes events (after commit)
```

### Repositories
```
Repositories provide collection-like access to aggregates.

Interface (Domain Layer):
interface OrderRepository {
  findById(id: OrderId): Promise<Order | null>;
  save(order: Order): Promise<void>;
  nextId(): OrderId;
}

Implementation (Infrastructure Layer):
class PostgresOrderRepository implements OrderRepository {
  async findById(id: OrderId): Promise<Order | null> {
    const row = await this.db.query('SELECT * FROM orders WHERE id = $1', [id.value]);
    if (!row) return null;
    return this.toDomain(row);
  }

  async save(order: Order): Promise<void> {
    const data = this.toPersistence(order);
    await this.db.upsert('orders', data);
  }
}

Rules:
- One repository per aggregate root
- Repository interface belongs to the domain layer
- Repository implementation belongs to the infrastructure layer
- Repositories return fully constructed aggregates (not raw data)
```

### Application Services
```
Application services orchestrate use cases. They coordinate between
domain objects, repositories, and infrastructure.

class PlaceOrderService {
  constructor(
    private orderRepo: OrderRepository,
    private customerRepo: CustomerRepository,
    private eventPublisher: DomainEventPublisher
  ) {}

  async execute(command: PlaceOrderCommand): Promise<OrderId> {
    // 1. Load necessary aggregates
    const customer = await this.customerRepo.findById(command.customerId);
    if (!customer) throw new CustomerNotFoundError(command.customerId);

    // 2. Create/modify aggregates (domain logic lives in the aggregate)
    const orderId = this.orderRepo.nextId();
    const order = Order.create(orderId, customer.id, command.items);
    # ... (condensed) ...
}

Rules:
- Application services contain NO business logic
- Business logic belongs in aggregates and domain services
- Application services coordinate the workflow
- One application service per use case (or group of related use cases)
```

## Layered Architecture for DDD

```
┌─────────────────────────────────────────┐
│ Presentation Layer (Controllers, API)   │
├─────────────────────────────────────────┤
│ Application Layer (Use Cases, Services) │
├─────────────────────────────────────────┤
│ Domain Layer (Entities, VOs, Events)    │  ← Core, no dependencies on outer layers
├─────────────────────────────────────────┤
│ Infrastructure Layer (DB, Messaging)    │
└─────────────────────────────────────────┘

Dependency Rule:
- Inner layers NEVER depend on outer layers
- Domain layer has ZERO infrastructure dependencies
- Application layer depends on domain interfaces (not implementations)
- Infrastructure layer implements domain interfaces
```

## DDD Anti-Patterns

```
1. Anemic Domain Model:
   Entities with only getters/setters, all logic in services.
   Bad: class Order { getId(); setStatus(); getItems(); setItems(); }
   Good: class Order { submit(); cancel(reason); addItem(item); }

2. Big Ball of Mud:
   No bounded contexts, one giant model for everything.
   Fix: Identify bounded contexts and split.

3. Smart UI / Dumb Domain:
   Business logic in controllers or UI, domain is just data transfer.
   Fix: Push logic into domain objects.

4. Database-Driven Design:
   Starting with the database schema instead of the domain model.
   Fix: Model the domain first, map to persistence second.

5. Shared Kernel Everywhere:
   Everything is shared between contexts, defeating the purpose.
   Fix: Minimize shared kernel, prefer anti-corruption layers.
```

## Quick Decision Guide

When asked about DDD:
- **"Where to start with DDD?"** → Strategic patterns first (bounded contexts, ubiquitous language)
- **"How to model entity X?"** → Determine if it's an entity, value object, or aggregate root
- **"How to structure the code?"** → Layered or hexagonal architecture with domain at the core
- **"How to handle cross-aggregate operations?"** → Domain events + eventual consistency
- **"When to use a domain service?"** → When logic involves multiple aggregates or doesn't belong to one entity
- **"How to integrate two contexts?"** → Choose a context mapping pattern based on team relationship

## When to Use

**Use this skill when:**
- Designing or implementing domain driven designer solutions
- Reviewing or improving existing domain driven designer approaches
- Making architectural or implementation decisions about domain driven designer
- Learning domain driven designer patterns and best practices
- Troubleshooting domain driven designer-related issues

**Do NOT use this skill when:**
- The question is about a fundamentally different technology domain
- A more specific sibling skill covers the exact topic needed
- The user needs a complete hands-on tutorial rather than expert guidance

## Output Format

```markdown
# Domain Driven Designer Analysis

## Context Assessment
[Situation summary and constraints]

## Recommended Approach
[Primary recommendation with rationale]

## Implementation Steps
1. [Step with specific details]
2. [Step with specific details]
3. [Step with specific details]

## Trade-offs and Considerations
- [Key trade-off 1]
- [Key trade-off 2]

## Next Steps
- [Immediate action item]
- [Follow-up action item]
```

## Example

**Input:** "Help me implement domain driven designer for a medium-scale production application"

**Output:** A structured analysis covering current state assessment, recommended domain driven designer approach with specific patterns, implementation roadmap with milestones, and risk mitigation strategies tailored to the application scale and constraints.

## Edge Cases

- **Legacy system integration:** When domain driven designer must coexist with legacy approaches, provide a gradual migration path rather than a complete rewrite
- **Scale mismatch:** When the solution complexity exceeds the project scale, recommend a simpler approach and note when to revisit
- **Team skill gaps:** When the team lacks experience with the recommended approach, include learning resources and simpler alternatives
- **Conflicting requirements:** When constraints conflict (e.g., performance vs. maintainability), explicitly state the trade-off and recommend based on stated priorities

