3. 领域事件定义:概念、命名规范与属性设计
领域事件(Domain Event)是事件风暴的核心产出物,也是分布式事务中实现最终一致性的关键消息载体。本节将系统定义领域事件的概念、命名规范与属性设计原则,确保团队在建模过程中产出高质量、可落地的领域事件。
3.1 领域事件的概念
领域事件是领域专家关心的、发生在过去且对业务有意义的重大状态变化。它记录了“某件事已经发生”的事实,并携带相关的上下文数据,供其他限界上下文或同一上下文内的其他聚合订阅消费。
| 维度 | 说明 | 示例 |
|---|---|---|
| 时间性 | 事件发生在过去,不可撤销 | “订单已支付”发生在支付完成时刻 |
| 业务意义 | 领域专家能理解并认可的事件 | “库存已扣减”而非“数据库行已更新” |
| 不可变性 | 事件一旦发布,内容不可修改 | 补偿通过新事件实现,而非修改旧事件 |
| 因果性 | 事件是命令执行后的结果 | “提交订单”命令 → “订单已提交”事件 |
关键区分:领域事件 ≠ 系统日志。领域事件必须包含业务语义,能被其他限界上下文理解并触发后续业务动作;系统日志仅用于技术排障,不参与业务流转。
3.2 命名规范:过去时动词
领域事件的命名遵循“业务对象 + 过去时动词短语”的格式,使用英文驼峰命名,确保事件名称清晰表达“发生了什么”。
| 规范项 | 规则 | 正确示例 | 错误示例 |
|---|---|---|---|
| 时态 | 必须使用过去时(-ed 或过去分词) | OrderSubmitted |
OrderSubmit(现在时) |
| 业务对象 | 使用领域通用语言中的实体/聚合名称 | PaymentCompleted |
PayDone(非标准术语) |
| 动词选择 | 使用业务动作的精确动词 | InventoryReserved |
InventoryChanged(过于模糊) |
| 大小写 | PascalCase(大驼峰) | OrderShipped |
order_shipped(蛇形) |
常见领域事件命名示例:
OrderSubmitted— 订单已提交PaymentCaptured— 支付已捕获InventoryReserved— 库存已预留ShipmentDelivered— 配送已签收RefundInitiated— 退款已发起
避坑提示:避免使用
OrderCreated 这类过于泛化的事件名。如果“创建订单”和“提交订单”是两个不同的业务节点,应分别命名为 OrderDrafted(草稿已创建)和 OrderSubmitted(订单已提交),以精确表达业务语义。
3.3 属性设计原则
领域事件的属性设计遵循“最小完备”原则:只携带消费者需要的数据,不包含实现细节,同时保证事件可被独立理解和处理。
| 属性类别 | 必选/可选 | 说明 | 示例 |
|---|---|---|---|
| 事件ID | 必选 | 全局唯一标识,用于幂等去重 | evt_20250321_001 |
| 事件时间 | 必选 | 事件发生的业务时间(UTC) | 2025-03-21T10:30:00Z |
| 聚合ID | 必选 | 事件所属聚合的唯一标识 | order_98765 |
| 聚合类型 | 必选 | 事件所属聚合的领域类型 | Order |
| 业务数据 | 按需 | 消费者需要的业务上下文 | totalAmount, items |
| 版本号 | 推荐 | 事件 schema 版本,支持演进 | 1 |
| 来源上下文 | 推荐 | 产生事件的限界上下文名称 | OrderContext |
设计检查清单:
- 消费者能否仅凭事件数据完成业务处理,无需回查源系统?
- 事件数据是否包含敏感信息(如密码、支付密钥)?应排除。
- 事件数据是否包含技术实现细节(如数据库ID、内部IP)?应排除。
- 事件数据是否足够支撑幂等判断?必须包含聚合ID和事件ID。
3.4 领域事件结构示例
以下是一个完整的 OrderSubmitted 事件 JSON 示例,展示属性设计的落地形态:
{
"eventId": "evt_20250321_a1b2c3d4",
"eventType": "OrderSubmitted",
"eventVersion": 1,
"occurredOn": "2025-03-21T10:30:00.123Z",
"sourceContext": "OrderContext",
"aggregateId": "order_98765",
"aggregateType": "Order",
"data": {
"orderId": "order_98765",
"customerId": "cust_12345",
"totalAmount": 299.99,
"currency": "CNY",
"items": [
{
"productId": "prod_001",
"quantity": 2,
"unitPrice": 149.995
}
],
"shippingAddress": {
"province": "Guangdong",
"city": "Shenzhen",
"detail": "Nanshan District"
}
}
}
3.5 领域事件与分布式事务的关系
在分布式事务场景中,领域事件扮演“事务协调信号”的角色。每个本地事务完成后发布一个领域事件,触发下一个限界上下文的本地事务,形成事件驱动的 Saga 或 TCC 补偿流程。
3.6 事件风暴中的领域事件识别技巧
在事件风暴工作坊中,团队通过以下步骤快速识别并定义领域事件:
- 橙色便利贴:用橙色便利贴记录领域事件,贴在时间轴右侧。
- 过去时动词:每张便利贴以过去时动词结尾,如“已提交”、“已支付”。
- 业务验证:邀请领域专家确认“这个事件是否真实发生过且有意义”。
- 属性头脑风暴:围绕事件讨论“消费者需要什么数据”,记录在事件下方。
- 命名评审:团队共同评审事件名称是否清晰、无歧义、符合通用语言。
实战建议:在事件风暴初期,不要过度设计事件属性。先用便利贴记录事件名称和关键数据字段,后续通过“事件溯源”和“消费者访谈”逐步完善属性清单。过度设计会拖慢工作坊节奏,降低领域专家的参与度。