Tactical DDD — aggregate design rules, entities, value objects, domain events, repositories, domain services, and anti-pattern detection
npx skills add https://github.com/nWave-ai/nWave --skill nw-ddd-tactical
Implementation patterns within a bounded context. Tactical DDD answers: "How do we structure the domain model?"
An aggregate is a consistency boundary -- a cluster of domain objects that must be transactionally consistent.
ProductId not Product. Direct object references create accidental cross-aggregate transactions and prevent independent scaling.| Smell | Signal | Fix |
|-------|--------|-----|
| God Aggregate | >5 entities, frequent concurrency conflicts | Split by invariant analysis |
| Anemic Aggregate | All logic in services, aggregate = data bag | Move business rules into aggregate methods |
| Cross-Aggregate Transaction | Two aggregates modified in one DB transaction | Use domain events + eventual consistency |
| Deep Nesting | Aggregate root -> entity -> entity -> value | Flatten; promote nested entities to own aggregates |
| Missing Aggregate | Business rules scattered in application services | Identify invariant cluster, create aggregate |
Objects with identity that persists across state changes. An entity is the "same" entity even when all its attributes change (a person who changes name, address, and job is still the same person).
Design rules: Identity is assigned once and never changes | Equality by identity, not attributes | Track lifecycle (created, modified, archived) | Place business rules that depend on identity here
Objects defined by their attributes, not identity. Two value objects with the same attributes are interchangeable.
Design rules:
Money object exists, it has a valid amount and currencyExamples: Money(amount, currency) | Email(address) | DateRange(start, end) | Address(street, city, zip, country) | Temperature(value, unit)
Context sensitivity: Whether something is Entity or Value Object depends on bounded context. Address is a VO in e-commerce (shipping destination) but an Entity in utility billing (service location with lifecycle).
Represent something that happened in the domain. Always past tense.
| Correct (past tense) | Wrong (imperative) |
|----------------------|-------------------|
| OrderPlaced | PlaceOrder (that's a command) |
| PaymentReceived | ReceivePayment |
| UserRegistered | RegisterUser |
| InventoryReserved | ReserveInventory |
OrderConfirmed not OrderStatusChangedDomain events (in-process): Within a bounded context, dispatched via mediator. Collected during command handling, dispatched before/after commit.
Integration events (distributed): Cross bounded-context via message brokers. Always asynchronous. Published only after successful persistence. May use different schema than domain events (translated at boundary).
One repository per aggregate (not per entity). Interface defined in domain layer, implementation in infrastructure.
Collection-oriented: add/remove/find -- repository tracks changes (Unit of Work pattern). Natural for ORMs.
Persistence-oriented: explicit save/load -- caller manages lifecycle. Natural for document DBs and event-sourced systems.
Rules: Never expose persistence details (SQL, JSON) to domain | Return domain objects, not DTOs | Query methods use domain language (findActiveOrders, not findByStatusEquals)
Stateless operations that span multiple aggregates or don't naturally belong to any single entity.
When to use: Operation involves multiple aggregates | Logic doesn't belong to any entity | Named using ubiquitous language
Danger: Overuse creates anemic domain models. First try to place the behavior on an entity or aggregate. Domain service is the last resort for truly cross-aggregate logic.
| Domain Service | Application Service |
|---------------|-------------------|
| Domain logic (rules, calculations) | Orchestration (transaction, security, events) |
| Domain types only | Domain + infrastructure ports |
| Domain layer | Application layer |
| TransferFunds, CalculateDiscount | PlaceOrderHandler, RegisterUserUseCase |
When analyzing existing code, look for these patterns:
| Anti-Pattern | Code Signal | Recommendation |
|-------------|-------------|----------------|
| Anemic Domain Model | Entities = data classes, services contain all if logic | Move business rules to entities/aggregates |
| Primitive Obsession | String email, double amount, int quantity | Create value objects: Email, Money, Quantity |
| Database-Driven Design | Entities mirror DB tables 1:1, foreign keys as navigation | Model domain first, map to persistence second |
| Missing Boundaries | Single model used by all features, vocabulary conflicts | Identify contexts via language divergence |
| Logic in Wrong Layer | Business rules in controllers/handlers | Push down to domain objects |
| Service Bloat | Service class with 20+ methods | Split by use case, push logic to aggregates |
| Event as RPC | Event handler returns result that caller depends on | Events are fire-and-forget; use command for request-response |
Integration with protocols.io API for managing scientific protocols. This skill should be used when working with protocols.io to search, create, update, or publish protocols; manage protocol steps and materials; handle discussions and comments; organize workspaces; upload and manage files; or integrate protocols.io functionality into workflows. Applicable for protocol discovery, collaborative protocol development, experiment tracking, lab protocol management, and scientific documentation.
Analyzes job descriptions and generates tailored resumes that highlight relevant experience, skills, and achievements to maximize interview chances
Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw.
Build and distribute Expo development clients locally or via TestFlight
Use when you have a written implementation plan to execute in a separate session with review checkpoints
Data structure for annotated matrices in single-cell analysis. Use when working with .h5ad files or integrating with the scverse ecosystem. This is the data format skill—for analysis workflows use scanpy; for probabilistic models use scvi-tools; for population-scale queries use cellxgene-census.
Benchling R&D platform integration. Access registry (DNA, proteins), inventory, ELN entries, workflows via API, build Benchling Apps, query Data Warehouse, for lab data management automation.
Comprehensive molecular biology toolkit. Use for sequence manipulation, file parsing (FASTA/GenBank/PDB), phylogenetics, and programmatic NCBI/PubMed access (Bio.Entrez). Best for batch processing, custom bioinformatics pipelines, BLAST automation. For quick lookups use gget; for multi-service integration use bioservices.
Take nwave-ai/nw-ddd-tactical from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.