Skip to content

Commit bd186be

Browse files
respencer-nclclaude
andcommitted
Migrate design and developer guides from riddl.tech
Adds Author's Design Guide: - index.md: Design guide overview - contexts.md: Bounded contexts and adaptation patterns - command-event-patterns.md: Consolidated from 4 pattern files - ui-modeling.md: Epics and Applications for UI design Adds Developer Guide content: - principles.md: RIDDL design principles (declarative, formal, etc.) - releasing.md: Release process for maintainers Content consolidated and enhanced from riddl/doc Hugo sources. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 79f1460 commit bd186be

6 files changed

Lines changed: 1013 additions & 0 deletions

File tree

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
---
2+
title: "Command-Event Patterns"
3+
description: "Alternatives and recommendations for command handler messages"
4+
---
5+
6+
# Command-Event Patterns
7+
8+
This guide covers design patterns for structuring commands and their
9+
corresponding events in RIDDL. Choosing the right pattern affects
10+
traceability, message size, and system maintainability.
11+
12+
## Overview
13+
14+
In event-driven systems, commands request actions and events record what
15+
happened. The relationship between command parameters and event parameters
16+
requires careful design.
17+
18+
For background on messages, see the [Message concept](../../../concepts/message.md).
19+
20+
## Example Entity
21+
22+
Throughout this guide, we'll use this Organization entity:
23+
24+
```riddl
25+
entity Organization is {
26+
state Active is {
27+
info: Info,
28+
members: MemberId*,
29+
contacts: Contacts
30+
}
31+
}
32+
33+
type Info is {
34+
name: String,
35+
address: Address?,
36+
isPrivate: Boolean
37+
}
38+
39+
type Contacts is {
40+
primaryContacts: MemberId+,
41+
billingContacts: MemberId*,
42+
distributionContacts: MemberId*
43+
}
44+
45+
command EstablishOrganization is { info: Info, contacts: Contacts }
46+
command ModifyOrganizationInfo is { id: OrganizationId, info: Info }
47+
command AddMembers is { orgId: OrganizationId, members: MemberId* }
48+
command ModifyContacts is { orgId: OrganizationId, contacts: Contacts }
49+
```
50+
51+
## Pattern 1: Same Event for All Commands
52+
53+
**Question:** Should all commands on an entity yield the same event?
54+
55+
```riddl
56+
event OrganizationModified is {
57+
id: OrganizationId,
58+
info: Info,
59+
members: MemberId*,
60+
contacts: Contacts
61+
}
62+
```
63+
64+
### Assessment
65+
66+
!!! warning "Generally Not Recommended"
67+
In an event-driven system, distinct events for each operation are important
68+
for traceability and understanding system behavior.
69+
70+
**Problems:**
71+
72+
- No way to distinguish what changed by looking at the event
73+
- Event consumers must diff current and previous state
74+
- Poor audit trail
75+
76+
**When it might work:**
77+
78+
- Very simple entities with few modifications
79+
- Systems where change tracking isn't important
80+
81+
## Pattern 2: Distinct Events, Full Entity Data
82+
83+
**Question:** Should each command have its own event containing the full entity?
84+
85+
```riddl
86+
event OrganizationEstablished is {
87+
id: OrganizationId,
88+
info: Info,
89+
members: MemberId*,
90+
contacts: Contacts
91+
}
92+
93+
event OrganizationInfoModified is {
94+
id: OrganizationId,
95+
info: Info,
96+
members: MemberId*,
97+
contacts: Contacts
98+
}
99+
100+
event OrganizationMembersModified is {
101+
id: OrganizationId,
102+
info: Info,
103+
members: MemberId*,
104+
contacts: Contacts
105+
}
106+
```
107+
108+
### Assessment
109+
110+
!!! note "Better Traceability, But Verbose"
111+
Event names tell you what changed, but events carry unnecessary data.
112+
113+
**Advantages:**
114+
115+
- Clear what operation occurred
116+
- Event consumers always have full context
117+
118+
**Disadvantages:**
119+
120+
- Extraneous data in modification events
121+
- Larger message sizes
122+
- Potential for confusion about what actually changed
123+
124+
**Recommendation:** Use for establishment events; consider other patterns for
125+
modification events.
126+
127+
## Pattern 3: Optional Parameters
128+
129+
**Question:** Should modification events use optional versions of types?
130+
131+
```riddl
132+
type InfoUpdate is {
133+
name: String?,
134+
address: Address?,
135+
isPrivate: Boolean?
136+
}
137+
138+
event OrganizationEstablished is {
139+
id: OrganizationId,
140+
info: Info,
141+
contacts: Contacts
142+
}
143+
144+
event OrganizationInfoModified is {
145+
id: OrganizationId,
146+
info: InfoUpdate
147+
}
148+
149+
event OrganizationContactsModified is {
150+
id: OrganizationId,
151+
contacts: Contacts
152+
}
153+
```
154+
155+
### Assessment
156+
157+
!!! tip "Recommended for Complex Types"
158+
Good balance between clarity and payload size.
159+
160+
**Advantages:**
161+
162+
- Clear what changed (non-None fields)
163+
- Reduced message size
164+
- Type safety maintained
165+
166+
**Disadvantages:**
167+
168+
- Requires maintaining "Update" versions of types
169+
- Event consumers must handle optional fields
170+
171+
**When to use:**
172+
173+
- Types with many fields where partial updates are common
174+
- When message size matters (high-frequency events)
175+
176+
## Pattern 4: Surfaced Parameters
177+
178+
**Question:** Should events contain only the changed fields directly?
179+
180+
```riddl
181+
event OrganizationMembersModified is {
182+
id: OrganizationId,
183+
members: MemberId*
184+
}
185+
186+
command AddPrimaryContacts is {
187+
orgId: OrganizationId,
188+
contacts: MemberId*
189+
}
190+
191+
event PrimaryContactsAdded is {
192+
id: OrganizationId,
193+
addedContacts: MemberId+
194+
}
195+
196+
event PrimaryContactsRemoved is {
197+
id: OrganizationId,
198+
removedContacts: MemberId*
199+
}
200+
```
201+
202+
### Assessment
203+
204+
!!! tip "Recommended for High-Frequency Changes"
205+
Most direct access to changed data; minimal overhead.
206+
207+
**Advantages:**
208+
209+
- Minimal message size
210+
- Clear exactly what changed
211+
- Fine-grained operations
212+
213+
**Disadvantages:**
214+
215+
- More event types to manage
216+
- Event consumers may need to maintain state
217+
218+
**Key decision:** For collection changes, decide whether the event contains:
219+
220+
- The items added/removed (delta), or
221+
- The new complete collection (full state)
222+
223+
Document this decision clearly:
224+
225+
```riddl
226+
event MembersAdded is {
227+
id: OrganizationId,
228+
addedMembers: MemberId+ // Only newly added members, not full list
229+
} briefly "Contains only the members that were added in this operation"
230+
```
231+
232+
## Pattern Selection Guide
233+
234+
| Scenario | Recommended Pattern |
235+
|----------|---------------------|
236+
| Entity creation | Full entity data (#2) |
237+
| Infrequent updates, simple types | Full entity data (#2) |
238+
| Frequent updates, complex types | Optional parameters (#3) |
239+
| High-frequency, specific field updates | Surfaced parameters (#4) |
240+
| Audit/compliance requirements | Surfaced parameters (#4) |
241+
242+
## Best Practices
243+
244+
1. **Document conventions** - Use `briefly` or `description` to clarify what
245+
events contain
246+
247+
2. **Consistency within context** - Use the same pattern for similar operations
248+
249+
3. **Consider consumers** - How will event processors use this data?
250+
251+
4. **Size vs. simplicity** - Larger events are simpler but may impact performance
252+
253+
5. **Separate creation from modification** - Creation events should always
254+
contain complete initial state
255+
256+
## Related Concepts
257+
258+
- [Message](../../../concepts/message.md) - Message fundamentals
259+
- [Handler](../../../concepts/handler.md) - Processing commands and events
260+
- [Entity](../../../concepts/entity.md) - Stateful business objects

0 commit comments

Comments
 (0)