事件风暴法以其独特的魅力,帮助我们将复杂业务领域的「已然发生」之事(领域事件)清晰地呈现出来。然而,要将这些「事实」转化为可执行的软件,我们还需要深入挖掘「谁做了什么」以及「什么因此而改变」。
这就是「命令风暴(Command Storming)」 的舞台。它作为事件风暴的自然延伸,引导我们从事件的因果链中,反向推导出触发事件的命令,并在此过程中,识别出承载业务逻辑的领域对象 —— 那些赋予软件系统「生命」的实体和值对象。
这篇文章,雪狼将带你从事件到命令,再到领域对象,一步步揭示这个 DDD 的核心实践。
一、从事件到命令:构建因果链#
-
回顾事件风暴:我们通过事件风暴识别了业务流程中的所有领域事件(Domain Events),并按时间顺序排列。
-
问题:领域事件是结果,软件系统需要执行动作来产生这些结果。为了构建系统,我们需要知道是哪些「动作」或「意图」导致了这些事件。
-
命令风暴的核心:针对每个领域事件,追溯其发生的原因 —— 即命令(Commands)。命令是用户或系统对领域模型发出的操作意图。
命令风暴活动#
-
细化局部流程:针对事件风暴中识别出的每个关键领域事件,深入探索其触发前的局部流程。
-
建立因果图:用蓝色便利贴代表命令,将它放置在导致相应橘黄色领域事件之前。
- 示例:「订单已创建」(事件)前面是「创建订单」(命令)。
-
识别发起者(Actors):用小人图标(或紫色便利贴)代表发出命令的人或外部系统(例如,用户、后台管理员、定时任务、第三方支付系统)。
二、识别候选领域对象#
在命令风暴的过程中,我们会发现大量与命令和事件相关的名词和名词短语,它们是潜在的领域对象(Domain Objects)。
-
原则:业务概念不一定都是领域对象,需要仔细甄别。
-
筛选标准:
-
排除技术细节:像「消息队列(MQ)」、「数据库服务器」这类技术基础设施,虽然是系统的一部分,但它们不属于业务领域的概念,不是领域对象。
-
排除外部系统:如果某个业务概念(例如「客户」)主要由一个外部系统管理,且在本系统内我们只进行查询或简单关联,那么它可能是外部实体,而非本系统核心领域对象。
-
聚焦核心业务:只保留那些封装了重要业务逻辑、状态和行为的核心业务概念。
-
定义关键术语:对筛选出的关键领域对象,和领域专家一起,用统一语言明确其定义、属性和行为。
-
三、区分实体与值对象:领域对象的「双生子」#
领域对象主要分为实体(Entity)和值对象(Value Object)。正确区分它们,对于构建健壮的领域模型至关重要。
1. 实体 (Entity)#
-
核心:拥有唯一标识符(Identity),且该标识符在其生命周期内保持不变。即使其属性发生变化,它依然是同一个实体。
-
示例:
订单 (Order)、用户 (User)、商品 (Product)。 -
特征:
-
身份:通过 ID 识别,而非属性。
-
生命周期:具有明显的生命周期。
-
行为:封装与自身身份相关的业务逻辑。
-
2. 值对象 (Value Object)#
-
核心:没有唯一标识符,其身份由其所有属性的值决定。当所有属性的值都相同时,两个值对象被认为是相等的。
-
示例:
地址 (Address)、金额 (Money)、日期范围 (DateRange)。 -
特征:
-
无身份:通过属性值识别。
-
不可变性:一旦创建,其属性不可更改(如果需要更改,则创建一个新的值对象)。
-
行为:通常是简单的计算或验证。
-

四、精炼领域对象:定义清晰职责#
在识别出初步的实体和值对象后,需要进一步精炼它们:
-
原子化命令:将复合命令拆解为职责更单一的原子命令(例如,「保存并发送」拆分为「保存」和「发送」)。
-
归并命令到领域对象:将所有与某个领域对象相关的命令和行为归并到该对象下,确保其职责清晰。
-
识别属性与行为:明确每个领域对象所需的属性和它能够执行的行为,以及它需要强制执行的业务规则。
-
与领域专家讨论:对于模糊、歧义或矛盾之处,必须与领域专家反复讨论,直到达成共识。
结语#
命令风暴法是将事件风暴的宏观洞察,转化为软件系统微观构成(领域对象)的关键步骤。通过系统地解剖命令,辨析实体与值对象,并精炼它们的职责,架构师能够构建出一个精确反映业务动作和核心实体的领域模型。
这个过程,不仅让代码更好地「说话」,更确保了软件系统能够精确地模拟业务世界,为后续的聚合设计和限界上下文划分奠定坚实的基础。
正如《韩非子·说林上》所言:「见微知著。」 命令风暴的精妙之处,便在于它引导我们从业务中那些微小的、已发生或将发生的「事件」和「命令」中,洞察出驱动业务运作的核心「领域对象」和「业务规则」。这种由表及里、抽丝剥茧的能力,正是构建高精度领域模型,让代码精准反映业务「心跳」的关键。