1
0
Fork 0
mirror of https://github.com/s-frick/effigenix.git synced 2026-03-28 15:29:34 +01:00
effigenix/bin/.claude/skills/ddd-model/workflow.md
2026-02-18 23:25:12 +01:00

11 KiB

DDD Modeling Workflow

This document provides detailed instructions for each phase of the DDD modeling workflow.

Phase 1: Domain Discovery

Step 1.1: Gather Domain Information

Use AskUserQuestion to understand the domain:

{
  "question": "What domain or subdomain are you modeling?",
  "header": "Domain",
  "multiSelect": false,
  "options": [
    {"label": "New domain", "description": "Starting from scratch with a new business domain"},
    {"label": "Existing domain", "description": "Refactoring or extending an existing domain"},
    {"label": "Subdomain extraction", "description": "Extracting a bounded context from a monolith"}
  ]
}

Step 1.2: Classify Subdomain Type

{
  "question": "What type of subdomain is this?",
  "header": "Type",
  "multiSelect": false,
  "options": [
    {"label": "Core (Recommended)", "description": "Competitive advantage, complex business logic, high DDD investment"},
    {"label": "Supporting", "description": "Necessary for Core, moderate complexity, simplified DDD"},
    {"label": "Generic", "description": "Commodity functionality, low complexity, CRUD is fine"}
  ]
}

Step 1.3: Determine DDD Investment Level

Based on subdomain type:

Subdomain Type DDD Investment Patterns to Use
Core Full Aggregates, Domain Events, Domain Services, CQRS, Event Sourcing (optional)
Supporting Simplified Aggregates, basic Value Objects, simple Domain Services
Generic Minimal CRUD, Transaction Script, Active Record

Step 1.4: Identify Business Processes

Ask about key business processes:

{
  "question": "What are the main business processes in this domain?",
  "header": "Processes",
  "multiSelect": true,
  "options": [
    {"label": "Create/Register", "description": "Creating new domain entities"},
    {"label": "Update/Modify", "description": "Changing existing entities"},
    {"label": "Workflow/State machine", "description": "Multi-step processes with state transitions"},
    {"label": "Calculations", "description": "Complex business calculations or rules"}
  ]
}

Phase 2: Bounded Contexts

Step 2.1: List Domain Concepts

Ask the user to list key concepts:

"List the main concepts/nouns in your domain. For example: Account, Transaction, Customer, Payment, etc."

Step 2.2: Group Concepts into Bounded Contexts

Look for:

  • Concepts that share the same ubiquitous language
  • Concepts that change together
  • Concepts with the same lifecycle
  • Natural boundaries (teams, deployability)

Step 2.3: Propose BC Boundaries

Present a Context Map diagram:

Example Context Map:

    ┌──────────────────────────────────────────────────────────┐
    │                      CORE DOMAIN                         │
    │  ┌─────────────┐          ┌─────────────┐               │
    │  │   Accounts  │─────────>│  Transfers  │               │
    │  │             │ Customer │             │               │
    │  │  - Account  │  Supplier│  - Transfer │               │
    │  │  - Balance  │          │  - Payment  │               │
    │  └─────────────┘          └─────────────┘               │
    │         │                        │                       │
    │         │ Conformist             │ Partnership           │
    │         v                        v                       │
    │  ┌─────────────┐          ┌─────────────┐               │
    │  │    Fees     │          │   Loyalty   │               │
    │  │ (Supporting)│          │   (Core)    │               │
    │  └─────────────┘          └─────────────┘               │
    └──────────────────────────────────────────────────────────┘

Step 2.4: Define Ubiquitous Language

For each BC, create a glossary:

## Accounts BC - Ubiquitous Language

| Term | Definition |
|------|------------|
| Account | A financial account owned by a customer |
| Balance | Current amount of money in the account |
| Holder | Person or entity that owns the account |
| Freeze | Temporarily block all operations on account |

Step 2.5: Map Context Relationships

Define relationships between BCs:

  • Partnership: Teams cooperate, shared evolution
  • Customer-Supplier: Upstream provides, downstream consumes
  • Conformist: Downstream adopts upstream model as-is
  • Anti-corruption Layer: Downstream translates upstream model
  • Open Host Service: Upstream provides well-defined protocol
  • Published Language: Shared language (XML schema, Protobuf)

Phase 3: Tactical Modeling

Step 3.1: Identify Entities

{
  "question": "Which concepts have a unique identity that persists over time?",
  "header": "Entities",
  "multiSelect": true,
  "options": [
    {"label": "User/Customer", "description": "Has ID, identity matters even if attributes change"},
    {"label": "Order/Transaction", "description": "Tracked by ID throughout lifecycle"},
    {"label": "Account/Wallet", "description": "Unique identifier, state changes over time"},
    {"label": "Other (specify)", "description": "I'll describe other entities"}
  ]
}

Step 3.2: Identify Value Objects

{
  "question": "Which concepts are defined purely by their values (no identity)?",
  "header": "Value Objects",
  "multiSelect": true,
  "options": [
    {"label": "Money/Amount", "description": "$100 = $100, no unique identity"},
    {"label": "Address/Location", "description": "Same address values = same address"},
    {"label": "DateRange/Period", "description": "Defined by start and end dates"},
    {"label": "Email/Phone", "description": "Value-based, immutable"}
  ]
}

Step 3.3: Identify Aggregates

Decision questions:

  1. "What entities must always be consistent together?"
  2. "What is the smallest unit that must be loaded together?"
  3. "What defines a transaction boundary?"
{
  "question": "Which entity should be the Aggregate Root (entry point)?",
  "header": "Aggregate Root",
  "multiSelect": false,
  "options": [
    {"label": "Account", "description": "Controls Balance, Transactions within it"},
    {"label": "Order", "description": "Controls OrderLines, ShippingInfo"},
    {"label": "Customer", "description": "Controls Addresses, Preferences"},
    {"label": "Other", "description": "Different aggregate root"}
  ]
}

Step 3.4: Define Aggregate Boundaries

For each aggregate, determine:

  • Root Entity: The entry point (only public access)
  • Child Entities: Internal entities (private, accessed via root)
  • Value Objects: Immutable data within aggregate
  • Invariants: Rules that must always hold

Example:

Account Aggregate
├── Account (Root)
│   ├── AccountID (VO)
│   ├── Balance (VO)
│   ├── Status (VO/Enum)
│   └── Holders[] (Entity)
│       ├── HolderID (VO)
│       └── Role (VO)
└── Invariants:
    - Balance >= 0 (for standard accounts)
    - At least one holder with OWNER role
    - Cannot debit frozen account

Phase 4: Invariants

Step 4.1: Gather Business Rules

{
  "question": "What business rules must ALWAYS be true for this aggregate?",
  "header": "Rules",
  "multiSelect": true,
  "options": [
    {"label": "Non-negative values", "description": "Balance, quantity, amount >= 0"},
    {"label": "Required relationships", "description": "Must have at least one X"},
    {"label": "State constraints", "description": "Cannot do Y when in state Z"},
    {"label": "Consistency rules", "description": "Sum of parts equals total"}
  ]
}

Step 4.2: Formalize Invariants

Convert business rules to formal invariants:

// Invariant: Account balance cannot be negative for standard accounts
// Invariant: Account must have at least one holder with OWNER role
// Invariant: Frozen account cannot process debit operations
// Invariant: Transfer amount must be positive
// Invariant: Source and destination accounts must be different

Step 4.3: Map Invariants to Enforcement Points

Invariant Enforcement Point
Balance >= 0 Account.Debit() method
At least one owner Account constructor, RemoveHolder()
No debit when frozen Account.Debit() method
Positive amount Money constructor

Phase 5: Code Generation

Step 5.1: Create Folder Structure

Use templates/folder-structure.md to create:

internal/
├── domain/
│   └── <bc>/
│       ├── aggregate.go      # Aggregate roots
│       ├── entity.go         # Child entities
│       ├── value_objects.go  # Value objects
│       ├── repository.go     # Repository interfaces
│       ├── errors.go         # Domain errors
│       └── events.go         # Domain events (optional)
├── application/
│   └── <bc>/
│       ├── service.go        # Application services / Use cases
│       └── dto.go            # Data transfer objects
└── infrastructure/
    └── <bc>/
        ├── postgres_repository.go
        └── memory_repository.go

Step 5.2: Generate Domain Code

For each aggregate, use templates:

  1. templates/aggregate.go.md - Generate aggregate root
  2. templates/entity.go.md - Generate child entities
  3. templates/value-object.go.md - Generate value objects
  4. templates/repository.go.md - Generate repository interface

Step 5.3: Apply Uber Go Style Guide

  • Use pointer receivers for Aggregates/Entities
  • Use value receivers for Value Objects
  • Add compile-time interface checks
  • Create domain-specific error types
  • Use constructor functions with validation

Phase 6: Validation

Step 6.1: Run DDD Checklist

Read rules/ddd-rules.md and check each rule:

### Aggregate Validation
- [ ] Aggregate Root is the only public entry point
- [ ] Child entities are not directly accessible
- [ ] All changes go through Aggregate Root methods
- [ ] Invariants checked in constructor
- [ ] Invariants checked in mutation methods
- [ ] No direct references to other Aggregates
- [ ] References to other Aggregates use ID only

Step 6.2: Output Validation Report

Generate a validation report:

## DDD Validation Report

### ✅ Passed
- Aggregate boundaries are clear
- Value Objects are immutable
- Repository interfaces in domain layer

### ⚠️ Warnings
- Consider extracting X into separate Value Object
- Y method might be better as Domain Service

### ❌ Issues
- Direct reference to other Aggregate (should use ID)
- Invariant not enforced in Z method

Step 6.3: Suggest Improvements

Based on validation, suggest:

  • Missing Value Objects
  • Potential Domain Events
  • Domain Services that might be needed
  • Possible CQRS opportunities