agentleFS
kayamankayaman/skills/domain-driven-design/SKILL.md

domain-driven-design

Skill3 starsChanged 8 months agoCC0-1.0View on GitHub

Enforces Domain-Driven Design strategic and tactical patterns including Bounded Contexts, Aggregates, Value Objects, Domain Events, and Context Mapping. Use when modeling a business domain, defining bounded context boundaries, designing aggregates, applying ubiquitous language, running Event Storming workshops, implementing CQRS or Event Sourcing, or reviewing domain models for DDD anti-patterns like Anemic Domain Models.

25 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use review.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • SentrySkill

    review

    Fixture review skill.

    Also in 3 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

26 rules. 0 are common, 26 are distinctive, and 0 are very specific to this project.

  • 0

    Common

    Most of the 23 edited versions we read keep these.

  • 26

    Distinctive

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    MUST NOT apply full DDD tactical patterns to simple CRUD applications — the overhead is not justified.

    line 20
  2. Distinctive:

    MUST use a single, shared language within each bounded context — reflected in code, documentation, and conversation

    line 28
  3. Distinctive:

    MUST NOT translate between "business terms" and "technical terms" — the code IS the language

    line 29
  4. Distinctive:

    MUST define explicit boundaries — a model is valid only within its context

    line 36
  5. Distinctive:

    SHOULD map one bounded context to one deployable unit (microservice, module)

    line 37
  6. Distinctive:

    MUST use an Anti-Corruption Layer when integrating with legacy systems or external services

    line 55
  7. Distinctive:

    SHOULD default to Customer-Supplier for inter-team context relationships

    line 56
  8. Distinctive:

    SHOULD document all context maps and keep them updated as relationships evolve

    line 57
  9. Distinctive:

    MUST identify the Core Domain and invest DDD effort there

    line 67
  10. Distinctive:

    SHOULD NOT apply full DDD tactical patterns to Generic Subdomains

    line 68
  11. Distinctive:

    SHOULD be kept lean — push behavior to Value Objects where possible

    line 78
  12. Distinctive:

    MUST have exactly one Aggregate Root with global identity as the single entry point

    line 99
  13. Distinctive:

    MUST NOT modify multiple aggregates in a single transaction

    line 100
  14. Distinctive:

    SHOULD keep aggregates as small as invariant protection allows

    line 101
  15. Distinctive:

    MUST hide persistence details — the domain layer sees only the interface

    line 107
  16. Distinctive:

    SHOULD be immutable and carry all data needed by consumers

    line 114
  17. Distinctive:

    MUST NOT become a dumping ground — check if the behavior belongs on an entity first

    line 120
  18. Distinctive:

    MUST NOT contain business logic — delegate to domain objects

    line 125
  19. Distinctive:

    Write side: rich domain model with aggregates enforcing invariants

    line 162
  20. Distinctive:

    Read side: optimized projections (denormalized views) for queries

    line 163
  21. Distinctive:

    SHOULD apply CQRS only to bounded contexts with complex domain logic AND different read/write performance needs

    line 164
  22. Distinctive:

    MUST NOT apply CQRS everywhere — it adds significant complexity

    line 165
  23. Distinctive:

    SHOULD use projections to build read-optimized views from the event stream

    line 171
  24. Distinctive:

    SHOULD implement snapshots for aggregates with long event histories (performance optimization)

    line 172
  25. Distinctive:

    MUST NOT use Event Sourcing for simple state management — the complexity cost is high

    line 174
  26. Distinctive:

    Before finalizing a domain model, verify:

    line 193

“Common” is measured: kept by at least 6 in 10 of the 23 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Domain-Driven Design

Reference: Domain-Driven Design (Evans), Implementing DDD (Vernon), Learning DDD (Khononov)

When to Apply

  • Modeling a complex business domain where the logic is the competitive differentiator
  • Defining boundaries between subdomains or microservices
  • Designing aggregates, entities, and value objects
  • Establishing ubiquitous language between developers and domain experts
  • Running Event Storming to discover domain events and bounded contexts
  • Implementing CQRS or Event Sourcing for a specific bounded context
  • Reviewing domain models for anemic models, oversized aggregates, or leaking contexts

MUST NOT apply full DDD tactical patterns to simple CRUD applications — the overhead is not justified.


Strategic Design

Ubiquitous Language

  • MUST use a single, shared language within each bounded context — reflected in code, documentation, and conversation
  • MUST NOT translate between "business terms" and "technical terms" — the code IS the language
  • Different bounded contexts MAY use different terms for the same real-world concept (e.g., "Customer" in Sales vs "Account" in Billing)

Bounded Contexts

A bounded context is the boundary within which a domain model is consistent and a ubiquitous language applies.

  • MUST define explicit boundaries — a model is valid only within its context
  • SHOULD map one bounded context to one deployable unit (microservice, module)
  • Microsoft guidance: "No smaller than an aggregate, no larger than a bounded context"

Context Mapping

Define relationships between bounded contexts using these patterns:

PatternRelationshipUse When
PartnershipMutual dependency, coordinated developmentTwo teams succeed or fail together
Shared KernelSmall shared model subset, joint ownershipLimited overlap that both contexts need identically
Customer-SupplierUpstream serves downstream; downstream can negotiateTeams have a clear provider/consumer relationship
ConformistDownstream conforms to upstream's model without negotiationUpstream has no incentive to accommodate downstream
Anti-Corruption LayerTranslation layer protecting downstream from upstream's modelIntegrating with legacy systems or external services
Open Host ServiceWell-defined public API serving multiple consumersUpstream provides a stable protocol for any consumer
Published LanguageShared exchange format (JSON schema, Protobuf, Avro)Multiple contexts exchange data using a documented format
Separate WaysNo integration — contexts are independentIntegration cost exceeds value
  • MUST use an Anti-Corruption Layer when integrating with legacy systems or external services
  • SHOULD default to Customer-Supplier for inter-team context relationships
  • SHOULD document all context maps and keep them updated as relationships evolve

Subdomains

TypeDescriptionInvestment Strategy
Core DomainCompetitive differentiator — what makes the business uniqueInvest heavily; use best engineers; full DDD
Supporting SubdomainNecessary but not differentiating; custom but simplerModerate investment; simpler models
Generic SubdomainCommodity functionality (auth, email, payments)Buy or use off-the-shelf; do not build
  • MUST identify the Core Domain and invest DDD effort there
  • SHOULD NOT apply full DDD tactical patterns to Generic Subdomains

Tactical Design

Entities

  • Have unique identity that persists over time; equality is by ID, not attributes
  • Are mutable but state changes MUST be modeled as business verbs: order.cancel() not order.setStatus("cancelled")
  • SHOULD be kept lean — push behavior to Value Objects where possible

Value Objects

  • Immutable, defined by their value (not identity), interchangeable when equal
  • Contain behavior: Money.add(other), EmailAddress.validate()
  • Thread-safe by nature (no shared mutable state)
  • Design guidance: aim for many Value Objects and few Entities

Aggregates

An aggregate is a cluster of objects treated as a single unit for data changes, defining a consistency boundary.

Vaughn Vernon's aggregate design rules:

  1. Design small aggregates — prefer single-entity aggregates; add entities only when invariants require it
  2. Protect business invariants inside aggregate boundaries — the aggregate root enforces all rules
  3. Reference other aggregates by identity only — never hold direct object references to other aggregates
  4. Use eventual consistency across aggregate boundaries — do not span transactions across aggregates
  5. Update one aggregate per transaction — if multiple aggregates must change, use domain events
  • MUST have exactly one Aggregate Root with global identity as the single entry point
  • MUST NOT modify multiple aggregates in a single transaction
  • SHOULD keep aggregates as small as invariant protection allows

Repositories

  • Provide a collection-like interface for aggregate persistence: save(), findById(), remove()
  • One repository per aggregate root — MUST NOT create repositories for non-root entities
  • MUST hide persistence details — the domain layer sees only the interface

Domain Events

  • Named in past tense: OrderPlaced, PaymentReceived, InventoryReserved
  • Represent meaningful business occurrences, not technical events
  • Enable eventual consistency across aggregate boundaries
  • SHOULD be immutable and carry all data needed by consumers

Domain Services

  • Stateless operations that don't naturally belong to any entity or value object
  • Typically coordinate multiple aggregates or perform calculations requiring data from several objects
  • MUST NOT become a dumping ground — check if the behavior belongs on an entity first

Application Services

  • Orchestrate use cases by coordinating domain objects, repositories, and infrastructure
  • MUST NOT contain business logic — delegate to domain objects
  • Handle transactions, security, logging, and other cross-cutting concerns

Event Storming

A collaborative workshop technique (Brandolini) for discovering domain events, commands, and bounded context boundaries.

Three Levels

LevelPurposeOutput
Big PictureExplore the entire business domainDomain events timeline, hot spots, bounded context boundaries
Process ModelingDetail a specific business processCommands, actors, policies, read models, external systems
Software DesignTranslate process into architectureAggregates, bounded contexts, event flows

Sticky Note Colors (Standard Convention)

ColorElementExample
OrangeDomain Event (past tense)"Order Placed"
BlueCommand (imperative)"Place Order"
YellowAggregate"Order"
LilacPolicy / Automation"When payment received, ship order"
PinkHot Spot / Question"What if payment fails?"
GreenRead Model / View"Order Summary"
Large PinkExternal System"Payment Gateway"

CQRS and Event Sourcing

CQRS (Command Query Responsibility Segregation)

Separate read and write models. Apply selectively — Greg Young: "CQRS is a supporting pattern, not a top-level architecture."

  • Write side: rich domain model with aggregates enforcing invariants
  • Read side: optimized projections (denormalized views) for queries
  • SHOULD apply CQRS only to bounded contexts with complex domain logic AND different read/write performance needs
  • MUST NOT apply CQRS everywhere — it adds significant complexity

Event Sourcing

Store state changes as an immutable, append-only sequence of events. Current state is derived by replaying events.

  • SHOULD use projections to build read-optimized views from the event stream
  • SHOULD implement snapshots for aggregates with long event histories (performance optimization)
  • Provides: complete audit trail, temporal queries, debugging capability, flexible projection creation
  • MUST NOT use Event Sourcing for simple state management — the complexity cost is high

Anti-Patterns and Remedies

Anti-PatternSignalRemedy
Anemic Domain ModelObjects are data bags; all logic in service classesMove behavior into entities and value objects
Oversized AggregatesLarge object graphs; frequent concurrency conflictsSplit into smaller aggregates; use domain events for cross-aggregate coordination
Ignoring Ubiquitous LanguageDevelopers use different terms than domain expertsEstablish a glossary; rename code to match domain terms
DDD on CRUDFull tactical patterns on simple data entry screensUse DDD strategically (bounded contexts) but skip tactical patterns for simple operations
Shared DatabaseMultiple contexts read/write the same tablesGive each context its own storage; synchronize via events
Leaking ContextOne context's model concepts appear in anotherIntroduce Anti-Corruption Layer or Published Language

Checklist

Before finalizing a domain model, verify:

  • Core Domain is identified and receives the highest modeling investment
  • Each bounded context has its own ubiquitous language reflected in code
  • Context relationships are mapped using explicit patterns (ACL, Customer-Supplier, etc.)
  • Aggregates are small — single entity where possible
  • Aggregate boundaries protect business invariants
  • Other aggregates are referenced by identity only, never by direct object reference
  • One aggregate is updated per transaction; cross-aggregate consistency uses domain events
  • Entities model state changes as business verbs, not setters
  • Value Objects are used for domain concepts without identity (Money, Email, DateRange)
  • Domain events are named in past tense and carry necessary data
  • Repositories exist only for aggregate roots
  • Application services orchestrate but contain no business logic

Key References

BookAuthor(s)PublisherYear
Domain-Driven Design: Tackling Complexity in the Heart of SoftwareEric EvansAddison-Wesley2003
Implementing Domain-Driven DesignVaughn VernonAddison-Wesley2013
Domain-Driven Design DistilledVaughn VernonAddison-Wesley2016
Learning Domain-Driven DesignVlad KhononovO'Reilly2021
Domain Modeling Made FunctionalScott WlaschinPragmatic Bookshelf2018
Patterns, Principles, and Practices of Domain-Driven DesignMillett & TuneWrox2015
Balancing Coupling in Software DesignVlad KhononovAddison-Wesley2024
Architecture for FlowAndrew Harmel-LawO'Reilly2023
Introducing EventStormingAlberto BrandoliniLeanpub~2024

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.