Domain Driven Design in JAVA
Usage
Parse the following from $ARGUMENTS:
- domain description (required): what the domain is about
- aggregate names (required): at least one aggregate name
If either is missing, print the following and STOP:
Usage: /ddd <domain description>: <Aggregate1>, <Aggregate2>, ...
Example: /ddd selling t-shirts online: Order, Product, Customer
Existing Domain Detection
Before starting, check if the domain module contains a CLAUDE.md. If it does, read it. This
contains domain decisions from a previous session. Use it as the starting point instead of
asking the user to re-describe the domain from scratch. When ddd-coach rules conflict with
decisions recorded in a previous CLAUDE.md, the coach rules win. The coach evolves faster
than any single project's documentation.
If the domain module has existing code but the user invoked /ddd with new arguments, ask:
- Add aggregates: extend the existing domain with the new aggregates
- Review: audit existing code against ddd-coach rules and suggest improvements
Process
Follow the rules defined in the ddd-coach skill for all generated code.
1. Sketch the Domain Model
For each aggregate named in the input, propose:
- The aggregate root and its typed ID
- Likely value objects based on the domain description
- Relationships between aggregates (by ID reference, never direct)
- Repository interface
- Ports, if the domain description implies outbound operations
The sketch must follow ddd-coach rules. No raw primitives. Every field in the diagram is a
typed value object. If the code would have Money, the diagram has Money, not int amountCents
and String currency. The sketch is the domain model, not an ER diagram. Show invariants on
value objects in the sketch: Quantity(int > 0), Money(BigDecimal >= 0). The user reviews
constraints before code is generated, not after. Mark non-empty collections:
OrderItems(Set<OrderItem>) non-empty. If the domain requires at least one item, show it.
Use what Java already provides before inventing types. java.util.Currency exists. Don't wrap
a String. For well-known domain concepts like money, time, or locale, research established
patterns and use them intelligently.
Present the sketch as an ASCII class diagram in the conversation. Write the PlantUML version
silently to disk (see step 3 for location). Do not stream the .puml content in the
conversation.
2. Ask the User
After presenting the ASCII sketch, inform the user that PlantUML diagrams have been written to
src/site/domain-classdiagram.puml and src/site/domain-aggregates.puml, then ask:
- Does this look right? Let the user correct, add, or remove before any code is generated. This is an invitation to iterate and clarify.
- Iterate or all at once? The default is to build one aggregate at a time with feedback between each (see Aggregate Build Strategy below). Offer all-at-once as an option for developers who prefer speed over token efficiency.
3. Generate
Aggregate Build Strategy
Build one aggregate at a time, starting from the aggregate with the fewest dependencies. After each aggregate, confirm the public interface before proceeding. Downstream aggregates reference upstream value objects, identity types, and domain events.
Before generating, estimate total output. If the deliverable exceeds 800 lines, present a numbered build plan and proceed aggregate by aggregate. Otherwise, generate in a single pass.
Never generate all aggregates in one pass when there are cross-aggregate references. The cheapest token is the one you never send. Catching a boundary mistake after one aggregate costs one regeneration. Catching it after all aggregates costs a full rework.
Based on the user's choice, generate the domain code:
For each aggregate:
- Aggregate root with typed ID, value objects, and guards
- First-class collections where collections exist
- Repository interface
- Ports if applicable
- Domain events if the domain description implies them
- Unit tests for all types with logic
At the domain root:
Guard.javaConstraintViolationException.java
All PlantUML diagrams go in the project root's src/site/ directory. The do NOT go inside the domain
module. The domain is one module in a multi-module project. This follows the Maven site
convention. For Gradle or other build tools, ask the user where to place it.
Generate two PlantUML diagrams. Both are living documents. Update them as the domain evolves:
src/site/domain-classdiagram.puml: class diagram showing aggregates, value objects, and their fields.src/site/domain-aggregates.puml: component diagram showing aggregates and how they relate to each other. Dependencies flow one direction. No circular references. This diagram makes the aggregate hierarchy visible.
Write a CLAUDE.md in the domain module root describing the domain model: what aggregates exist,
what they contain, key decisions made during the conversation, and any domain rules the user
specified. This file is picked up automatically by Claude in future sessions, so the user never
has to re-explain the domain.
4. Review
After generating, present a summary of what was created and ask if the user wants to adjust anything before moving on.
Author: Benjamin Simpson (bensimpson-ch)