This commit is contained in:
by931
2022-09-06 22:30:37 +08:00
parent 66970f3e38
commit 3d6528675a
796 changed files with 3382 additions and 3382 deletions

View File

@@ -424,7 +424,7 @@ function hide_canvas() {
<h4>决策命令</h4>
<p>通观事件之起因,除了外部系统是直接发布事件之外,无论是用户活动,还是满足某个条件,都需要一个<strong>命令Command<strong>来响应它才是直接导致事件发生的“因”。在事件风暴中Alberto Brandolini 将命令称之为“决策命令Decision Command使用</strong>浅蓝色即时贴</strong>表示。决策命令往往由动宾短语组成,例如 Place Order、Send Invitation 等。</p>
<p>由于决策命令和事件存在因果关系因此二者往往是一一对应的。例如Cancel Order 决策命令会触发 OrderCancelled 事件Subscribe Course 决策命令会触发 CourseSubscribed 事件。正是这种一一对应关系,使得它们存在语义上的重叠,区别仅在于时态。故而有的事件风暴实践者认为可以在事件风暴中省略决策命令。我并不敢苟同这一观点,相反,我反而极为强调<strong>决策命令在事件风暴中的重要性</strong>,它是领域分析建模的一个重要驱动力,因为通过<strong>它连接了用户、策略、聚合、读模型和事件</strong>,如下图所示:</p>
<p><img src="assets/d54afa70-bca4-11e9-b095-45b8601f64cd" alt="74748976.png" /></p>
<p><img src="assets/d54afa70-bca4-11e9-b095-45b8601f64cd" alt="png" /></p>
<p>从图中可以看出,由<strong>事件</strong>可以驱动出<strong>决策命令</strong>,在它们之间借由<strong>聚合</strong>对象来发布事件。当事件发生后,如果某个<strong>策略</strong>满足条件,也会引发决策命令,而<strong>用户</strong>在引发决策命令时,需要足够的<strong>读模型</strong>来帮助它做出正确的决策。</p>
<p>那么该如何正确地理解决策命令显然Alberto Brandolini 使用决策来修饰命令并非空穴来风因为这一名词突出了命令往往需要更多的信息来帮助参与者Actor做出决策。参与者是用例图的设计要素在事件风暴中可以认为是对所有事件起因的抽象用户、条件满足如定时器与外部系统。其中外部系统对我们而言是一个黑盒子不用考虑它是如何触发了事件因而可以忽略。因此参与者在基于业务场景做出决策时需要如下两方面数据的支撑</p>
<ul>
@@ -436,7 +436,7 @@ function hide_canvas() {
<p><img src="assets/eb379e60-bca4-11e9-8296-ad04873de5ea" alt="img" /></p>
<p>读模型是用户执行决策命令必需的输入信息在代码层面这些读模型就是执行决策命令的领域行为所需的输入参数。用户发起决策命令的方式是因为执行了某个活动例如决策命令“提交订单”实则是因为用户点击了“提交订单”按钮。用户活动的执行与用户体验User eXerperienceUX直接有关。现实世界的业务场景通过用户体验将用户与读模型结合起来把信息传输给事件风暴的决策命令。这一过程牵涉到用户、查询和命令操作恰好符合组成用例的要素。若建模人员熟悉用例也可借助用例图来分析。</p>
<p>注意,上图是将读模型 ShoppingCart 提供给 Place Order 决策命令,而非查询操作与命令操作之间的交互。有的事件风暴实践者将查询操作也纳入到事件风暴的模型中,认为是用户执行查询操作获得读模型后,触发了决策命令,如下图所示:</p>
<p><img src="assets/f96deca0-bca4-11e9-ac77-f5b1a77a87b3" alt="58315254.png" /></p>
<p><img src="assets/f96deca0-bca4-11e9-ac77-f5b1a77a87b3" alt="png" /></p>
<p>我认为这样的模型设计并不恰当,因为它<strong>将活动流程图与事件的因果关系混为一谈</strong>了。实际上,活动流程图反应了现实世界的问题域,事件风暴表现的事件因果关系却是解决方案域的内容,这是领域建模活动中两个不同的层次。买家先查询购物车,然后提交订单,这是买家的操作流程。但从事件的因果关系看,并非“查询购物车”触发了“提交订单”这个决策命令,而是用户通过查询获得了购物车读模型之后,由用户发起“提交订单”的决策命令,再通过订单聚合发布了 OrderCreated 事件。“查询购物车”和“提交订单”是两个不同的用户活动,它们并不具有时序上的连续性,可以认为是两个独立的业务场景。由于查询操作并不会触发事件的发生,从模型上看,它也不会导致命令的发生,因而在事件风暴中,<strong>并没有查询操作的位置</strong>,而是以读模型的形式出现。这也变相地促使建模人员在识别用户活动时,需要分辨该活动究竟是查询还是命令,有利于 CQRS 模式的落地。</p>
<p>当决策命令由策略引发时,就表示事件发生后某些数据满足了某条业务规则。一旦该策略被满足,就会引起目标对象的状态变更,然后根据业务规则的规定触发下一个决策命令。例如,策略“提交订单后,一旦超过规定时间未支付,则取消订单”会触发 Cancel Order 命令,从而引起 OrderCancelled 事件的发生。策略引发的决策可以是自动的如定时器检测到支付时间超时也可以是用户手动触发如用户登录时输入错误密码的次数太多还可以二者并存如在取消订单业务场景中Cancel Order 命令既可以由定时器自动触发,也可以由用户手动触发。</p>
<h4>聚合</h4>
@@ -462,9 +462,9 @@ function hide_canvas() {
<p>首先是审批人参与的“开卡申请已审批”事件,执行第一步,由该事件可以反向驱动出决策命令“审批开卡申请”。第二步是根据决策命令推导出触发事件需要的读模型。审批开卡申请的前置信息是“申请”和“用户征信”,若缺乏这两个信息,审批人无法做出“审批开卡申请”的决策。第三步是确定决策命令与事件之间的聚合对象。显然,“开卡申请已审批”事件影响到的就是申请的状态,它就是我们要寻找的聚合对象:</p>
<p><img src="assets/20e512e0-bca5-11e9-ac77-f5b1a77a87b3" alt="img" /></p>
<p>接着进入第四步,选择下一个后置事件“卡号已生成”。该事件与策略有关,细化策略为“卡号规则”。由事件驱动出决策命令为“生成卡号”,进入第三步,识别两者之间的聚合对象。卡号的生成影响了信用卡的属性,可以认为该事件影响状态的目标对象为“信用卡”:</p>
<p><img src="assets/2a10a370-bca5-11e9-ac77-f5b1a77a87b3" alt="64620751.png" /></p>
<p><img src="assets/2a10a370-bca5-11e9-ac77-f5b1a77a87b3" alt="png" /></p>
<p>继续第四步,选择下一个后置事件“信用卡制作完毕”。由于该事件由外部系统发布,可以忽略该建模过程,仅仅标记外部系统即可:</p>
<p><img src="assets/330397d0-bca5-11e9-8296-ad04873de5ea" alt="64725757.png" /></p>
<p><img src="assets/330397d0-bca5-11e9-8296-ad04873de5ea" alt="png" /></p>
<p>通过这个简单案例,可以清晰地看到我总结的领域分析建模过程具有一定的可操作性。事件风暴工作坊的参与人员可以按照建模步骤一步一步执行。执行每一步都需要团队与领域专家进一步讨论和确认,保证识别出来的模型对象遵循该领域的统一语言。在这个分析建模过程中,每个模型对象都有着建模的参考依据,包括模型对象的身份特征、彼此之间的关系、承担的职责,这就在一定程度上减轻了对建模人员经验的依赖。</p>
<p>事件风暴的两个层次恰好可以对应领域驱动设计的战略阶段与战术阶段。前者主要用于识别限界上下文,后者主要用于建立领域分析模型,这恰恰填补了 Eric Evans《领域驱动设计》书中的关键空白。当然Alberto Brandolini 提出的事件风暴不仅于此,它还能用于企业的流程改进、业务创新和对新型服务的探索。这些实践与领域驱动设计没有直接关系,这里就不再叙述。若有兴趣了解事件风暴的更多内容,可以访问<a href="https://www.eventstorming.com/">事件风暴的官方网站</a></p>
<h3>分享交流</h3>