Agent Skills: Domain-Driven Design Tactical Patterns

Domain-Driven Design tactical patterns for complex business domains. Use when modeling entities, value objects, domain services, repositories, or establishing bounded contexts.

document-asset-creationID: yonatangross/orchestkit/domain-driven-design

Install this agent skill to your local

pnpm dlx add-skill https://github.com/yonatangross/orchestkit/tree/HEAD/src/skills/domain-driven-design

Skill Files

Browse the full folder contents for domain-driven-design.

Download Skill

Loading file tree…

src/skills/domain-driven-design/SKILL.md

Skill Metadata

Name
domain-driven-design
Description
Domain-Driven Design tactical patterns for complex business domains. Use when modeling entities, value objects, domain services, repositories, or establishing bounded contexts.

Domain-Driven Design Tactical Patterns

Model complex business domains with entities, value objects, and bounded contexts.

Overview

  • Modeling complex business logic
  • Separating domain from infrastructure
  • Establishing clear boundaries between subdomains
  • Building rich domain models with behavior
  • Implementing ubiquitous language in code

Building Blocks Overview

┌─────────────────────────────────────────────────────────────┐
│                    DDD Building Blocks                       │
├─────────────────────────────────────────────────────────────┤
│  ENTITIES           VALUE OBJECTS        AGGREGATES         │
│  Order (has ID)     Money (no ID)        [Order]→Items      │
│                                                              │
│  DOMAIN SERVICES    REPOSITORIES         DOMAIN EVENTS      │
│  PricingService     IOrderRepository     OrderSubmitted     │
│                                                              │
│  FACTORIES          SPECIFICATIONS       MODULES            │
│  OrderFactory       OverdueOrderSpec     orders/, payments/ │
└─────────────────────────────────────────────────────────────┘

Quick Reference

Entity (Has Identity)

from dataclasses import dataclass, field
from uuid import UUID
from uuid_utils import uuid7

@dataclass
class Order:
    """Entity: Has identity, mutable state, lifecycle."""
    id: UUID = field(default_factory=uuid7)
    customer_id: UUID = field(default=None)
    status: str = "draft"

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Order):
            return NotImplemented
        return self.id == other.id  # Identity equality

    def __hash__(self) -> int:
        return hash(self.id)

Load Read("${CLAUDE_SKILL_DIR}/references/entities-value-objects.md") for complete patterns.

Value Object (Immutable)

from dataclasses import dataclass
from decimal import Decimal

@dataclass(frozen=True)  # MUST be frozen!
class Money:
    """Value Object: Defined by attributes, not identity."""
    amount: Decimal
    currency: str

    def __add__(self, other: "Money") -> "Money":
        if self.currency != other.currency:
            raise ValueError("Cannot add different currencies")
        return Money(self.amount + other.amount, self.currency)

Load Read("${CLAUDE_SKILL_DIR}/references/entities-value-objects.md") for Address, DateRange examples.

Key Decisions

| Decision | Recommendation | |----------|----------------| | Entity vs VO | Has unique ID + lifecycle? Entity. Otherwise VO | | Entity equality | By ID, not attributes | | Value object mutability | Always immutable (frozen=True) | | Repository scope | One per aggregate root | | Domain events | Collect in entity, publish after persist | | Context boundaries | By business capability, not technical |

Rules Quick Reference

| Rule | Impact | What It Covers | |------|--------|----------------| | aggregate-boundaries (load ${CLAUDE_SKILL_DIR}/rules/aggregate-boundaries.md) | HIGH | Aggregate root design, reference by ID, one-per-transaction | | aggregate-invariants (load ${CLAUDE_SKILL_DIR}/rules/aggregate-invariants.md) | HIGH | Business rule enforcement, specification pattern | | aggregate-sizing (load ${CLAUDE_SKILL_DIR}/rules/aggregate-sizing.md) | HIGH | Right-sizing, when to split, eventual consistency |

When NOT to Use

Under 5 entities? Skip DDD entirely. The ceremony costs more than the benefit.

| Pattern | Interview | Hackathon | MVP | Growth | Enterprise | Simpler Alternative | |---------|-----------|-----------|-----|--------|------------|---------------------| | Aggregates | OVERKILL | OVERKILL | OVERKILL | SELECTIVE | APPROPRIATE | Plain dataclasses with validation | | Bounded contexts | OVERKILL | OVERKILL | OVERKILL | BORDERLINE | APPROPRIATE | Python packages with clear imports | | CQRS | OVERKILL | OVERKILL | OVERKILL | OVERKILL | WHEN JUSTIFIED | Single model for read/write | | Value objects | OVERKILL | OVERKILL | BORDERLINE | APPROPRIATE | REQUIRED | Typed fields on the entity | | Domain events | OVERKILL | OVERKILL | OVERKILL | SELECTIVE | APPROPRIATE | Direct method calls between services | | Repository pattern | OVERKILL | OVERKILL | BORDERLINE | APPROPRIATE | REQUIRED | Direct ORM queries in service layer |

Rule of thumb: DDD adds ~40% code overhead. Only worth it when domain complexity genuinely demands it (5+ entities with invariants spanning multiple objects). A CRUD app with DDD is a red flag.

Anti-Patterns (FORBIDDEN)

# NEVER have anemic domain models (data-only classes)
@dataclass
class Order:
    id: UUID
    items: list  # WRONG - no behavior!

# NEVER leak infrastructure into domain
class Order:
    def save(self, session: Session):  # WRONG - knows about DB!

# NEVER use mutable value objects
@dataclass  # WRONG - missing frozen=True
class Money:
    amount: Decimal

# NEVER have repositories return ORM models
async def get(self, id: UUID) -> OrderModel:  # WRONG - return domain!

Related Skills

  • aggregate-patterns - Deep dive on aggregate design
  • ork:distributed-systems - Cross-aggregate coordination
  • ork:database-patterns - Schema design for DDD

References

Load on demand with Read("${CLAUDE_SKILL_DIR}/references/<file>"): | File | Content | |------|---------| | entities-value-objects.md | Full entity and value object patterns | | repositories.md | Repository pattern implementation | | domain-events.md | Event collection and publishing | | bounded-contexts.md | Context mapping and ACL |

Capability Details

entities

Keywords: entity, identity, lifecycle, mutable, domain object Solves: Model entities in Python, identity equality, adding behavior

value-objects

Keywords: value object, immutable, frozen, dataclass, structural equality Solves: Create immutable value objects, when to use VO vs entity

domain-services

Keywords: domain service, business logic, cross-aggregate, stateless Solves: When to use domain service, logic spanning aggregates

repositories

Keywords: repository, persistence, collection, IRepository, protocol Solves: Implement repository pattern, abstract DB access, ORM mapping

bounded-contexts

Keywords: bounded context, context map, ACL, subdomain, ubiquitous language Solves: Define bounded contexts, integrate with ACL, context relationships