agentleFS
dekozadekoza/oh-my-slop/skills/practice/domain-driven-design/SKILL.md

domain-driven-design

Skill4 starsChanged 8 months agoUnlicenseView on GitHub

Business complexity, model language, lifecycle rules, or cross-team/system boundaries shape the design more than generic technical organization. Synthesized from Domain-Driven Design (Evans), DDD Distilled (Vernon), and Implementing DDD (Vernon). Covers: strategic design (Bounded Contexts, Context Mapping, Subdomains), tactical patterns (Entities, Value Objects, Aggregates, Domain Events, Repositories, Factories), Ubiquitous Language discipline, integration patterns (Anticorruption Layer, Open Host Service), and when DDD is overkill. Triggers on: "DDD", "domain model", "bounded context", "aggregate", "ubiquitous language", "context mapping", "anticorruption layer", "domain event", "subdomain", or when modeling complex business domains.

We split this skill into the rules it gives an agent

30 rules. 0 are common, 27 are distinctive, and 3 are very specific to this project.

  • 0

    Common

    Most of the 22 edited versions we read keep these.

  • 27

    Distinctive

    This author's own choices. Worth a look.

  • 3

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If you are reading this, the user is working on a system where business complexity, language, or boundaries matter more than generic …

    line 19
  2. Distinctive:

    Do not let persistence, UI, frameworks, integration formats, or DDD vocabulary replace an implementation-driving model.

    line 25
  3. Distinctive:

    Every meaningful model gets one explicit Bounded Context.

    line 53
  4. Distinctive:

    Use when identity and lifecycle matter.

    line 78
  5. Distinctive:

    Use for immutable descriptive concepts where identity doesn't matter.

    line 84
  6. Distinctive:

    Use as immediate consistency boundaries for invariants.

    line 90
  7. Distinctive:

    Root-protected: All invariant-changing behavior goes through the root.

    line 92
  8. Distinctive:

    One per transaction: Default to modifying one Aggregate per transaction.

    line 94
  9. Distinctive:

    Use for meaningful past-tense business facts.

    line 98
  10. Distinctive:

    Do NOT publish for every field change.

    line 101
  11. Distinctive:

    Keep business rules out of repository implementations.

    line 108
  12. Distinctive:

    Use when constructing an Aggregate requires multi-step validation or assembly.

    line 112
  13. Distinctive:

    Use for domain-significant operations that involve multiple domain objects and don't fit naturally on any single Entity or Value Object.

    line 116
  14. Distinctive:

    Keep technical transformation, serialization, transport, and persistence mapping OUT of the domain model.

    line 117
  15. Distinctive:

    Application Services must NOT become the real domain model: If they accumulate branching business rules, move the decisions into the domain …

    line 127
  16. Distinctive:

    When terminology is awkward, ambiguous, or inconsistent — pause coding and sharpen the language first.

    line 139
  17. Very specific:

    Anticorruption Layer: When integrating with a messy/legacy/external model, add a translation layer before modeling locally.

    line 144
  18. Very specific:

    Avoid giant shared or common packages for domain concepts.

    line 161
  19. Distinctive:

    Only when the event sequence is the right persistence model:

    line 165
  20. Distinctive:

    Ambiguous terminology: When a term is fuzzy, overloaded, or imported from another context — sharpen the Ubiquitous Language before coding.

    line 177
  21. Distinctive:

    Cross-context coupling: When code wants to import another context's domain package or share enums — add explicit translation instead.

    line 178
  22. Very specific:

    Foreign model leakage: When legacy/vendor/API/persistence shapes appear in domain code — add an Anticorruption Layer.

    line 179
  23. Distinctive:

    Large Aggregate: When one transaction wants multiple Aggregates — list the invariants that require it.

    line 180
  24. Distinctive:

    Anemic domain: When Application Services or controllers accumulate branching business rules — move decisions into domain objects.

    line 181
  25. Distinctive:

    Primitive-carried rules: When a primitive, flag, status code, boolean, or enum carries domain rules — promote it to a richer concept or …

    line 182
  26. Distinctive:

    Awkward conditionals: When new requirements force awkward conditional logic — search for a deeper model or missing implicit concept instead …

    line 183
  27. Distinctive:

    Generic Repository: When a Repository becomes table-shaped or starts enforcing business rules — reshape around Aggregate access.

    line 184
  28. Distinctive:

    Noisy events: When an event reads like a command, exposes framework artifacts, or describes a minor property change — rename, narrow, or …

    line 185
  29. Distinctive:

    Representation pressure: When client rendering or query speed pressures the model shape — use projections, DTOs, or adapters instead of …

    line 186
  30. Distinctive:

    Simple subdomain: When a subdomain is simple CRUD — keep it simple.

    line 187

“Common” is measured: kept by at least 6 in 10 of the 22 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

When This Skill Loads

If you are reading this, the user is working on a system where business complexity, language, or boundaries matter more than generic technical organization. Model the domain first. Let the code follow the model.

Core Principle

Keep domain behavior, code, tests, documents, and team language aligned inside explicit Bounded Contexts.

Do not let persistence, UI, frameworks, integration formats, or DDD vocabulary replace an implementation-driving model.

When DDD Is Warranted

Any one of these justifiers is sufficient to warrant strengthening the model:

  • Business rules are complex (not just CRUD)
  • Domain experts use specific terminology that differs from technical terms
  • Multiple teams or systems share data but have different conceptual models
  • The same word means different things in different parts of the business
  • Invariants and lifecycle rules are non-trivial
  • Integration with external/legacy systems requires translation

When DDD is overkill: Simple CRUD, generic subsystems, or mainly technical problems. Use the lightest approach that works.

Strategic Design

Subdomains

Classify every business capability:

TypeWhat it isModeling effort
Core DomainCompetitive advantage, strategic differentiationHighest — rich model, best people, most iteration
SupportingNeeded for the business, but not a differentiatorModerate — model honestly, but don't over-invest
GenericCommodity (auth, notifications, logging)Lowest — buy/build simple, no custom modeling

Bounded Contexts

Every meaningful model gets one explicit Bounded Context. The context owns:

  • Its language (Ubiquitous Language — one term per concept, one meaning per term)
  • Its rules and semantics
  • Its code structure, tests, and integration contracts

The same word in different contexts may mean different concepts. "Order" in billing is not "Order" in fulfillment. Translate at boundaries.

Context Relationships

Choose deliberately:

RelationshipMeaningWhen to use
PartnershipTeams coordinate closely, models evolve togetherSame team, tightly coupled contexts
Shared KernelSmall shared model, jointly owned and testedStable overlap both teams agree on
Customer/SupplierDownstream depends on upstream; upstream prioritizes downstream's needsClear upstream/downstream dependency
ConformistDownstream conforms to upstream's model exactlyNo leverage to influence upstream
Anticorruption Layer (ACL)Downstream translates upstream's model into its own languageUpstream model is messy, foreign, or legacy
Open Host Service (OHS)Upstream provides a published protocol for multiple downstreamsMany consumers need standardized access
Published LanguageShared format (schema, API contract) for integrationCross-organization or cross-team integration
Separate WaysNo integration; contexts are independentNo real dependency exists

Tactical Patterns

Entities

Use when identity and lifecycle matter. An Entity is defined by its ID, not its attributes.

  • Make identity explicit (e.g., OrderId, not a raw integer).
  • Protect meaningful state transitions — don't expose unrestricted setters.
  • Methods should reveal domain purpose, not just change fields.

Value Objects

Use for immutable descriptive concepts where identity doesn't matter.

  • Validate at construction — a Value Object is always valid.
  • Compare by value, not by reference.
  • Replace raw primitives for meaningful concepts: Money, EmailAddress, DateRange.

Aggregates

Use as immediate consistency boundaries for invariants.

  • Small. One root Entity, few internal objects. If it's large, the boundary is wrong.
  • Root-protected. All invariant-changing behavior goes through the root.
  • Identity-referenced. Reference other Aggregates by ID, not by object reference.
  • One per transaction. Default to modifying one Aggregate per transaction. Use events for cross-Aggregate coordination.
  • Hide internals. Mutable internals are not exposed to callers.

Domain Events

Use for meaningful past-tense business facts.

  • Name in past tense: OrderPlaced, PaymentReceived, ShipmentDelivered.
  • Payload is local to the model — don't leak foreign schemas.
  • Do NOT publish for every field change. Events represent business significance.
  • Consumers must tolerate lag, duplicates, and ordering limits.

Repositories

Provide access to Aggregate Roots, not tables.

  • Define interfaces by domain needs, not by persistence mechanics.
  • Return domain objects, not ORM rows or DTOs.
  • Keep business rules out of repository implementations.

Factories

Hide complex creation logic.

  • Use when constructing an Aggregate requires multi-step validation or assembly.
  • Prevent partially formed objects from escaping.

Domain Services

Use for domain-significant operations that involve multiple domain objects and don't fit naturally on any single Entity or Value Object.

  • Keep technical transformation, serialization, transport, and persistence mapping OUT of the domain model.

Application Services

Coordinate use cases:

  1. Load Aggregates (via Repositories)
  2. Invoke domain behavior (on Aggregates/Entities)
  3. Persist results
  4. Publish resulting Domain Events
  5. Own transaction/integration coordination

Application Services must NOT become the real domain model. If they accumulate branching business rules, move the decisions into the domain objects.

Refactoring Toward Deeper Insight

Refactor toward deeper domain insight, not only mechanical cleanliness. When a constraint, policy, process, or calculation carries domain meaning, make it an explicit named model concept instead of leaving it implicit in conditionals or helper code. If new behavior is hard to explain, test, or extend, a deeper model or missing implicit concept is usually waiting — find it rather than adding procedural branches.

Ubiquitous Language Discipline

  • One concept gets one term inside a context.
  • One term does not carry multiple meanings inside a context.
  • Code, tests, commands, events, repositories, services, and packages must speak the local language.
  • Rename code when understanding improves — don't let technical names drift from domain meaning.
  • When terminology is awkward, ambiguous, or inconsistent — pause coding and sharpen the language first.

Integration and Translation

  • Translate foreign models into the local language. Keep foreign schemas, statuses, and contract models out of local domain objects.
  • Anticorruption Layer: When integrating with a messy/legacy/external model, add a translation layer before modeling locally.
  • Keep integration contracts separate from internal models. Test translations wherever meanings cross a boundary.
  • Integration style matters:
    • RPC: Requires acceptable request/response coupling
    • REST: Resources must not expose Aggregate internals
    • Messaging: Must tolerate lag, duplicates, and ordering limits

Package Structure

Organize by Bounded Context first, then by domain or use-case ownership within the context:

context-name/
  domain/          # Entities, Value Objects, Domain Events, Repositories (interfaces)
  application/     # Application Services, DTOs, Command handlers
  infrastructure/  # Repository implementations, messaging, persistence adapters

Avoid giant shared or common packages for domain concepts.

When to Use Event Sourcing

Only when the event sequence is the right persistence model:

  • Audit trail is a first-class requirement
  • Replay/reconstruction is a core feature
  • The domain naturally thinks in terms of state transitions

Requirements:

  • Streams match Aggregate identity and versioning
  • Replay is deterministic
  • Event meaning changes need versioning, upcasters, or translators

Trigger Rules

  • Ambiguous terminology: When a term is fuzzy, overloaded, or imported from another context — sharpen the Ubiquitous Language before coding.
  • Cross-context coupling: When code wants to import another context's domain package or share enums — add explicit translation instead.
  • Foreign model leakage: When legacy/vendor/API/persistence shapes appear in domain code — add an Anticorruption Layer.
  • Large Aggregate: When one transaction wants multiple Aggregates — list the invariants that require it. Otherwise coordinate by identity and events.
  • Anemic domain: When Application Services or controllers accumulate branching business rules — move decisions into domain objects.
  • Primitive-carried rules: When a primitive, flag, status code, boolean, or enum carries domain rules — promote it to a richer concept or Value Object.
  • Awkward conditionals: When new requirements force awkward conditional logic — search for a deeper model or missing implicit concept instead of adding procedural branches.
  • Generic Repository: When a Repository becomes table-shaped or starts enforcing business rules — reshape around Aggregate access.
  • Noisy events: When an event reads like a command, exposes framework artifacts, or describes a minor property change — rename, narrow, or remove it.
  • Representation pressure: When client rendering or query speed pressures the model shape — use projections, DTOs, or adapters instead of exposing Aggregate internals.
  • Simple subdomain: When a subdomain is simple CRUD — keep it simple. Don't add DDD ceremony.

Final Checklist

  • Bounded Context explicit before interpreting names, modules, events, repositories, APIs?
  • One local term per concept across tests, commands, events, repositories, services, packages?
  • Core Domain effort protected while supporting/CRUD areas stay simpler?
  • Context relationships, translation responsibilities, and upstream/downstream pressures visible?
  • Aggregates small, root-protected, invariant-driven, identity-linked, usually one per transaction?
  • Entities behavior-bearing and Value Objects immutable, validated, and value-equal?
  • Repositories are Aggregate-root access points, not generic DAOs or ORM leaks?
  • Domain Events are meaningful past-tense facts, not noisy field-change notifications?
  • Application Services coordinate use cases instead of owning domain decisions?
  • Client, foreign, persistence, and infrastructure representations kept outside the domain model?
  • Tests read like executable examples of the model and cover invalid transitions?

Reference

FileUse When
Strategic DesignDefining Bounded Contexts, subdomains, and context relationships
Tactical PatternsChoosing between Entities, Value Objects, Aggregates, Events, Repositories
Integration PatternsDesigning cross-context integration, ACL, OHS, published language
Application ArchitectureStructuring Application Services, repositories, package organization

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.

Reviews can't be read right now.

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.