Skip to content

Commit 7209eef

Browse files
author
lijiawei
committed
docs: 收紧 DDD 事件筛选规则
1 parent 4b7e00b commit 7209eef

3 files changed

Lines changed: 39 additions & 15 deletions

File tree

skills/df-ddd-event-storming-design/SKILL.md

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Use event storming as the core entry point for DDD modeling. Requirements intake
1111

1212
When the input is a raw requirement, meeting note, feature list, user story dump, or mixed CRUD/page/API description, first run a lightweight requirements intake before domain modeling. Requirements intake is pre-modeling discovery: identify stakeholders, requirement items, business subjects, triggers, constraints, inputs/outputs, assumptions, and gaps. Do not turn this intake directly into aggregates, commands, events, APIs, packages, or code.
1313

14-
Treat event storming as collaborative brainstorming followed by disciplined convergence. First create a broad candidate event pool from business language, actor goals, lifecycle changes, failures, external facts, and query needs. Then filter candidates into accepted domain events only when they have business meaning, a production path, and a consequence for actors, rules, policies, aggregates, or read models.
14+
Treat event storming as collaborative brainstorming followed by disciplined convergence. First create a broad candidate event pool from business language, actor goals, lifecycle changes, failures, external facts, and query needs. Then filter candidates into accepted domain events only when they have business meaning, a production path, and at least one business consumer that changes actor options, command-side rules, policies/processes, aggregates, or downstream business capabilities. Read-model projection, page display, cache refresh, or query completeness alone is not a sufficient reason to accept a domain event.
1515

1616
Do not treat the first brainstormed event list as the final model. Candidate events are working material; accepted domain events are design conclusions.
1717

@@ -33,7 +33,7 @@ Always translate data-driven or CRUD-driven requests into business-event explora
3333

3434
Do not echo the user's data model back as a DDD model. If the user asks in CRUD terms, first explain the translation boundary briefly, then proceed through the confirmation gates in business language.
3535

36-
Always identify the business actors, external systems, timers, and affected subjects before finalizing commands and events. Commands are issued by an actor; events change something that matters to one or more actors or read models.
36+
Always identify the business actors, external systems, timers, and affected subjects before finalizing commands and events. Commands are issued by an actor; accepted events change something that matters to one or more actors or business capabilities. Treat read models as projection consumers and discovery clues, not as standalone proof that a domain event exists.
3737

3838
Unless the user explicitly asks for implementation, produce only domain design artifacts. Do not generate code, tests, framework structure, persistence mapping, or TDD plans.
3939

@@ -108,6 +108,8 @@ For each candidate event, capture enough information to support convergence:
108108
- possible event name in completed business tense
109109
- initiating actor or external system if known
110110
- affected subject and downstream consumer
111+
- non-read-model business consumer and the behavior, rule, policy, process, or capability it changes
112+
- whether the candidate is only needed for query/display/projection and should be downgraded
111113
- possible producing command, aggregate, policy, process, or external fact
112114
- business reason to keep it
113115
- reason to reject, split, rename, downgrade to read-model data, or mark unresolved
@@ -187,7 +189,7 @@ Treat these files as ordered design artifacts, not as a checklist to complete im
187189
4. `events.md` must distinguish candidate-event screening notes from accepted domain events. Accepted events require business meaning, production path, and downstream consequence.
188190
5. `commands.md`, `policies.md`, and `relationships.md` depend on accepted events and actor authority.
189191
6. `aggregates/<aggregate-name>.md` depends on a coherent command-event-rule model. Do not create aggregate files merely because nouns or tables exist.
190-
7. `read-models.md` depends on accepted events and projection needs. If a read model cannot be projected, return to events or command fields before persisting it.
192+
7. `read-models.md` depends on accepted events, projection needs, and explicit non-event query sources. If a read model cannot be projected from accepted domain events, do not invent events for projection; first check current-state query, query-side joins, technical projection inputs, enriched payloads of already accepted events, or an external integration source.
191193
8. `completeness-check.md` is the final gate and should record remaining unresolved questions instead of hiding them in downstream artifacts.
192194

193195
File responsibilities:
@@ -235,7 +237,7 @@ Do not regenerate the whole model unless the user asks or the existing model is
235237
- Model behavior before structure.
236238
- For admin-system requirements, treat "management" pages as a discovery clue, not as the domain model. Reframe noun lists into lifecycle events, assignments, approvals, ownership changes, synchronization facts, and cross-role consequences.
237239
- Treat CQRS as a modeling perspective: commands change business state through the domain model; queries are satisfied by read models.
238-
- Read models must be derivable from domain events.
240+
- Read models should record their information sources, but query needs must not create domain events by themselves. A read-model-only field can come from current-state lookup, query-side joins, technical projection inputs, external sources, or accepted event payloads.
239241
- Iterate when commands, events, aggregates, or read models do not explain each other.
240242

241243
## Traceability Rules
@@ -345,7 +347,8 @@ Screen each candidate with these questions:
345347

346348
- Does the business care that this fact happened?
347349
- Can an actor, timer, policy, process manager, aggregate, or external system produce it?
348-
- Does it change an actor's options, an affected subject's lifecycle, a rule decision, a policy reaction, or a read model?
350+
- Does it change an actor's options, an affected subject's lifecycle, a command-side rule decision, a policy reaction, a process, another aggregate, or a downstream business capability?
351+
- Is the only consumer a read model, page, report, cache, or projection? If so, reject it as a domain event and capture the need as query-side data, technical projection, current-state lookup, or audit/log material.
349352
- Is it specific enough, or should it be split or renamed?
350353
- Is it inside the current problem domain, or only an integration/technical detail?
351354
- Does keeping it improve the event-command-read-model explanation, or only mirror CRUD data changes?
@@ -354,7 +357,7 @@ Screen each candidate with these questions:
354357

355358
Extract already-happened business facts as candidate events.
356359

357-
Keep only facts that the current problem domain needs for business rules, state decisions, workflow progress, or read model construction.
360+
Keep only facts that the current problem domain needs for business rules, state decisions, workflow progress, policy/process reactions, aggregate collaboration, or downstream business capabilities. Do not keep a fact as a domain event only because a read model needs to refresh or display a field.
358361

359362
Rules:
360363

@@ -433,10 +436,11 @@ For each read model, specify:
433436
- requirement ID(s) when available
434437
- identity
435438
- fields
436-
- events that create or update it
437-
- whether it can be built from domain events
439+
- accepted domain events that create or update it, if any
440+
- non-event sources such as current-state lookup, query-side joins, technical projection inputs, enriched accepted-event payloads, or external read sources
441+
- whether any missing field reveals a real domain-event gap or only a query-side sourcing decision
438442

439-
If a read model cannot be built from events, adjust events, command fields, or aggregate behavior. Do not pollute aggregates with report or page fields.
443+
If a read model cannot be built from accepted domain events, do not invent events for projection. First decide whether the field can come from current-state query, query-side joins, accepted event payload enrichment, technical projection, audit/log data, or external read sources. Add or change a domain event only when a non-read-model business consumer exists and the event has a production path.
440444

441445
## Relationship Rules
442446

@@ -525,12 +529,15 @@ Before finalizing, check:
525529
- Meaningful modeling alternatives were compared before choosing contested event, policy, process, aggregate, or read-model boundaries.
526530
- Every command has an initiating actor or external system.
527531
- Every domain event has a production path from actor -> command -> aggregate/process -> event.
528-
- Every important event has an affected actor, subject, read model, policy, or downstream relationship.
532+
- Every accepted domain event has at least one business consumer other than read models, pages, reports, caches, or projection completeness.
533+
- No accepted domain event is justified only by read-model refresh, page display, cache update, report fields, or projection completeness.
534+
- Every important event has an affected actor, subject, command-side rule, policy/process, aggregate, or downstream business relationship.
529535
- Current-domain state-changing events are published by aggregates unless a clear exception is recorded.
530536
- Every command has the information it needs from command fields plus aggregate state/history.
531537
- Meaningful command outcomes are represented as events.
532538
- Generic events such as `信息已变更` have been replaced by specific facts or explicitly justified.
533-
- Every read model can be built from domain events.
539+
- Every read model records whether each field comes from accepted events, current-state lookup, query-side joins, technical projection inputs, enriched payloads, or external read sources.
540+
- Every read-model-only field is marked as query-side data, technical projection input, current-state lookup, audit/log material, or external-source data instead of being promoted to a domain event.
534541
- Policies do not hide aggregate invariants.
535542
- Domain services do not become procedural service layers.
536543
- Aggregates are derived from behavior, rules, identity, lifecycle, and invariants, not tables, CRUD resources, or noun lists.
@@ -552,6 +559,7 @@ Refuse or correct these patterns:
552559
- Using vague data-change events such as `信息已变更` when a concrete business fact is available.
553560
- Treating external master-data sync as a simple upsert when ordering, dependency, failure, or conflict resolution has business meaning.
554561
- Creating domain events for technical actions the business does not care about.
562+
- Creating domain events only because a read model, page, report, cache, or projection needs a field refreshed.
555563
- Putting report/page/query fields into aggregates for convenience.
556564
- Putting most business rules into command handlers, application services, listeners, repositories, or policies.
557565
- Splitting bounded contexts before understanding the current problem domain.

skills/df-ddd-event-storming-design/references/anti-patterns.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
- Combined outcome event: merge different facts such as `已停用或解散` into one event even though they can trigger different policies or actor consequences.
1414
- Upsert sync modeling: treat external master-data synchronization as a simple create/update when the business cares about dependency ordering, conflict handling, missing parent records, retries, or failure status.
1515
- Read model leakage: add page/report fields to aggregate state only because a query needs them.
16+
- Projection-driven event: create a domain event only because a read model, page, report, cache, or projection needs a field refreshed.
1617
- Framework-shaped domain: treat controllers, DTOs, repositories, or packages as the domain model.
1718
- Unproduced event: keep a domain event without a command, policy, process, or external fact that can produce it.
18-
- Unprojectable read model: define a read model that cannot be built from domain events without identifying the missing event or field.
19+
- Unexplained read source: define a read model field without identifying whether it comes from accepted events, current-state lookup, query-side joins, technical projection input, enriched payloads, audit/log data, external sources, or a confirmed domain-event gap.
1920
- Premature bounded contexts: split contexts before the current problem domain has enough evidence.
2021
- Artifact flooding: fill every `event-storming/` file in one pass for a new ambiguous requirement, causing speculative downstream events, commands, aggregates, and read models to look confirmed.

skills/df-ddd-event-storming-design/references/eval-cases.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,22 @@ Prompt: "Order details page shows risk score, but no event carries risk data."
5555
Expected guardrail:
5656

5757
- Identify the projection gap.
58-
- Adjust events, command fields, or external-system relationship instead of polluting aggregate state.
58+
- Do not create a domain event just to refresh the order details page.
59+
- First check whether risk score is current-state query data, a query-side join, technical projection input, accepted-event payload enrichment, or an external read source.
60+
- Add or adjust a domain event only if risk score changes a command-side business rule, policy/process, aggregate behavior, or downstream business capability.
61+
- Do not pollute aggregate state with report-only fields.
62+
63+
## Case 6b: Read-Model-Only Field Change
64+
65+
Prompt: "Department options and employee pages need the latest department name, so add DepartmentRenamedEvent."
66+
67+
Expected guardrail:
68+
69+
- Treat department name refresh as a read-model/query need until a non-read-model business consumer is identified.
70+
- Ask who consumes the rename as a business fact and what behavior, rule, process, or downstream business capability changes.
71+
- Reject or downgrade the event when the only consumers are pages, options, reports, caches, or projections.
72+
- Record the read source as current-state lookup, query-side join, technical projection input, accepted-event payload enrichment, audit/log data, or external-source data.
73+
- Accept the event only when a command, policy/process, aggregate, or downstream business capability consumes the rename as a business fact.
5974

6075
## Case 7: CRUD-Looking Admin Nouns
6176

@@ -97,7 +112,7 @@ Prompt: "Let's brainstorm all events for a recruitment workflow. Candidates incl
97112
Expected guardrail:
98113

99114
- Treat the list as a candidate event pool, not the final event list.
100-
- Screen candidates by business meaning, production path, affected subject, policy/read-model impact, and current-domain boundary.
115+
- Screen candidates by business meaning, production path, affected subject, non-read-model business consumer, policy/process impact, and current-domain boundary.
101116
- Reject or downgrade technical facts such as email delivery unless the business explicitly cares.
102117
- Split or rename vague data-change events such as `候选人资料已更新` when specific business facts matter.
103118
- Compare plausible modeling approaches when approval, offer, and onboarding boundaries could be aggregate, process manager, or external-system responsibilities.
@@ -187,7 +202,7 @@ Expected guardrail:
187202
- Keep requirement IDs as traceability anchors.
188203
- Link accepted commands to requirement IDs.
189204
- Link read models to query/view requirement IDs.
190-
- Link trigger/follow-up requirements to accepted events plus policies/processes, read-model projection, external integration concern, or rejected/downgraded candidate with a reason.
205+
- Link trigger/follow-up requirements to accepted events plus policies/processes, read-model sourcing/projection, external integration concern, or rejected/downgraded candidate with a reason.
191206
- Mark any requirement with no command, event, read model, or explicit rejection as uncovered in completeness check.
192207

193208
## Case 18: Learning-Oriented Review

0 commit comments

Comments
 (0)