本文来自
很多人在学习DDD的过程中,都会有一个疑问:DDD的概念看着挺多,听起来也很有用。但具体怎么落地实施到项目中?
事件风暴(Event Storming)于2013年首次被提出,2015年被ThoughtWorks技术雷达添加到“实验”阶段,2018年被ThoughtWorks技术雷达添加到“采纳”阶段。
事件风暴是一种快速探索复杂业务领域和对领域建模的实践。
事件风暴从领域中关注的业务事件出发,在此过程中团队经过充分讨论,统一语言,最后找到领域模型。
那到底什么是领域中关注的业务事件呢?
以宠物为例,如果做为宠物主人,你的问题域是如何养好一只猫,那么是不是已经打了疫苗,给宠物饲喂食物等将成为你关注的事情,领域事件会有:疫苗已注射,猫粮已饲喂等。
如果你是宠物医生,问题域是如何治好宠物的病,关注的事情是宠物的身体构成,准确的诊断宠物病情,对症下药,领域事件会有:病情已确诊,药方已开治。虽说二者关注的都是宠物,在不同的问题域下领域事件是不同的。
如果在通用语言中存在“当a发生时,我们就需要做到b。”这样的描述,则表明a可以定义成一个领域事件。领域事件的命名一般也就是“产生事件的对象名称+完成的动作的过去式”的形式,比如:订单已发货(OrderDispatchedEvent)、订单已收货和订单已确认(OrderConfirmedEvent)等事件。
领域事件可以是业务流程的一个步骤,例如订单提交,客户付费100元,订单完工等。领域事件也可以是定时发生的事情,例如每晚对账完成。或者是一个事件发生后引发的后续动作,比如确认收货7天后自动将钱打到卖家账户,比如客户输错密码三次后发生锁定账户。
在事件风暴开始之前,需要准备以下物料:
工作坊由寻找领域事件开始。领域事件一般用橘色的便利贴表示,书写领域实践的规则是使用被动语态,并按照时间顺序贴在白纸上。
最开始可能很多成员都不知道该怎么写,或者不知道该怎么寻找领域事件。可以由组织者写下领域中发生的第一个事件。其它参与者会迅速的开始模仿,这时我们可以让大家快速的进入状态。
在遇到有疑惑的事件时,不必长时间阻塞在那里讨论,把它作为标记记下来即可,后续再进行重点优化。可以贴一个比较醒目的便签纸(比如紫色)在事件旁边。
随着我们对业务认识的不断加深,可以随时回顾和总结之前添加的内容,对于有问题的描述进行更正,对于表述不清楚的内容可以进行重写。
事件是有相对顺序的。可以把一系列有相对顺序关系的事件放在一行上,从左到右排好。这样有助于梳理领域事件,查看是否有遗漏。
在收集完领域事件后,我们可以在此基础上进一步探索系统核心事件的运行机制。这里我们在之前的领域事件的基础上加入指令和角色的概念。
指令代表系统中用户的意图、动作和决定,一般用蓝色的便利贴表示;角色表一类特定用户,一般用黄色便利贴表示。它们之间的关系是“角色”发送“指令”产生了“领域事件”(指令也可由外部系统触发,外部系统通常用粉色的便利贴表示)。
通常来说,一个命令将对应到我们后续应用程序开发的一个API。
在寻找命令和角色的过程中,你可能会遇到某些命令会在“特定的条件下”触发。比如:“当用户通过新的设备登入时,系统会发送提醒通知”。通常,我们将这种系统的行为逻辑称为策略,通常记录在紫丁香色的便利贴上,放在命令旁边。
当我们做完了上一个环节,就可以开始寻找系统中的领域模型和聚合了。我们把跟一个概念相同的指令和事件集合到一起,并用黄色的较大的便利贴表示领域模型。
把跟这个领域模型相关的命令放到左边,事件放到右边。需要注意的是,这个时候会去掉“事件的相对顺序”这个概念,因为我们已经不需要了。
可能有些领域模型不能作为一个独立存在的对象。它应该被另一个领域模型持有和使用。那这时候,可以考虑把两个模型合起来,形成一个聚合。在最上面的模型就是这个聚合的聚合根,其之下的模型都是它的实体或值对象。
找到领域模型以后,我们应当就可以比较轻松地划分子域和限界上下文了。
在划分限界上下文的时候也可以反过来检验领域模型和通用语言的正确性。如果发现一个模型有歧义,那它就应该是限界上下文边界的地方,我们应该重新思考这个模型,必要时进行拆分。
关于子域和限界上下文的概念可以参考本系列上一篇文章。
我们发现在实施事件风暴的过程中会遇到一些问题。这里列举一些常见的问题及解决方案。如果你的团队在实施事件风暴或者实施DDD的过程中遇到什么问题,欢迎留言交流探讨。
我们在讨论这个问题之前,首先要思考事件是什么。事件是领域专家关心的业务事件。所以它不能比领域专家关心的业务更细,因为那将毫无意义。
举个例子,如果我们关心的是一个人一天的作息,那我们可能关心的是用户已起床,用户已吃早餐,用户已上班。但我们不会关心到更细节,比如:用户已睁眼,用户已洗漱,用户已出门,用户已上地铁……
同时,事件粒度也不能太粗,因为太粗粒度的事件不利于寻找领域模型。比如我们在平台上发一篇文章的业务。如果你只写一个“文章已发布”,那就可能会丢失掉一些比较重要的业务流程。
尝试改成:文章已保存,文章已申请审核,文章已通过审核,文章已审核失败,文章已对外发表,文章已加入分类,文章已推荐……你会发现,中间多了一个审核的过程,如果不找到这些命令,就很有可能遗漏掉“文章审核单”之类的模型。
这是好事情,说明你们团队需要讨论了,有时还可以发掘出原本可能没有注意到的业务细节。但在实施事件风暴的时候,不必刚开始就花太多的时间在上面,阻塞了后面的事件发掘。而是应该先前面说的那样,用一个醒目的标记记下来,后面再回过头来充分讨论。
或许最开始有歧义的地方,在事件逐渐完善,领域模型定义出来后,就没有歧义了。
这个是正常的,一个命令可能会触发一个事件或者多个事件。也有可能一个事件触发了另一个事件,只需要把它们贴在一起即可。
这个时候你们应该警惕了。一个领域模型不应该包含过多的领域事件,因为这会让这个模型变得很大,很复杂。你们需要考虑把这个领域模型拆分开了。
仔细思考一下,这个领域模型是不是可以拆成两个?一些下面的实体是不是可以拿出来单独作为一个聚合根?它们中的一些事件表述是不是有歧义?可不可以拆开来划分到两个限界上下文中?
比如“用户”在权限上下文中我们关注的是它的角色和权限,它是否登录成功,它的密码等等。
而在商品上下文中,我们关注的是它的姓名,电话,地址等等。
这种情况,是应该把它们拆开的。
很多时候其实就是这样的。比如角色是用户,命令是发布,产生了事件文章已发布。但也不完全是这样,因为在这个过程中可以统一语言。比如:用户,喝水,产生的事件可以是用户已补充水分,而不是用户已喝水。
也有可能会有一些定时任务或者策略,这都有利于我们熟悉业务。更何况,找到命令可以指导我们后续的API开发,所以寻找命令是有必要的。
可以由领域专家先进行业务大概流程的讲解。如果有UX已经设计好的图就更好了。大家可以在这个环节发出自己的疑问,澄清一些关键信息。
领域专家也可以把主要的业务流程写下来,打印到纸上或者反映到大屏幕上。比如:
产品运营人员可以添加新的商品,编辑产品库存,并发布到京西商城,用户可以进行购买;当商品销售价格和库存数量发生变化后,产品运营人员会进行修改,并重新发布到商城。
团队总得是有人了解业务的。比如BA(有些团队可能是PM、TL等)。如果实在没有,可以让领域专家写一份上面那种主要的业务流程,大家按照这个业务流程来做。
但还是最好有一个领域专家,因为出现分歧的时候是很需要沟通达成一致的。如果没有领域专家在,团队有可能得到一些不准确的模型和语言。
除此之外,团队成员也可以查阅相关的文献资料去了解业务。比如金融系统、医疗系统等等都是有现成的行业案例可以研究的。
敬请期待:
《DDD第4篇 - 架构》
————————————————
版权声明:本文为CSDN博主「Yasinxxx」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yasinshaw/article/details/103307125