记一次事件风暴工作坊实践&总结

起因:

项目遇到的问题?
随着团队&项目的发展,团队的业务复杂度增加。

  • 代码本身复杂度变高,维护难度变大,改动容易引发没想到的错误;
  • 单体服务越来越大,测试、构建、部署的时间越来越长,开发部署效率降低;同时测试成本变高;
  • 业务上的改动在代码层因为高耦合导致难以修改;
  • 项目复杂度导致的沟通成本增加,尤其是业务人员与技术人员之间,经常出现沟通反复确认的情况;

对于上述问题,期望通过领域驱动设计的方式:

  • 对于代码中的类、模块等,进行设计与拆分;
  • 通过将单体服务拆分为微服务,降低测试、构建、部署的时间,提高开发效率,同时享有微服务带来的一系列优势;
  • 通过与业务人员&领域专家一同建模的方式,从业务出发进行类似于面向对象的建模;最后产出高内聚,低耦合的多个独立的服务,每个服务专注在自己独立的业务上。
  • 通过合作建模,制定项目不同上下文之间,的通用语言。

人员:

项目中的主要业务&技术成员:包括PM, PO,BA, UX,TL, DEV,QA
(基于团队对行业的理解,并未邀请专门的领域专家)

主要产出物:

  • 识别系统的核心域,以及多个子域。
  • 系统的聚合
  • 系统的多个 限界上下文 以及 限界上下文地图

准备阶段:

  • 时间:根据业务复杂度以及业务场景数量;平均一个比较复杂的业务场景花了半天(4h非6h)
  • 场地:带墙面的足够容纳多人的会议室
  • 人员:确保团队关键角色参与(至少有一个能代表领域专家、业务专家、以及技术专家的人员)
  • 其他物料:4色以上便利贴,笔
  • 基本概念的拉齐: 毕竟通用语言是DDD的核心,如果在做DDD的workshop之前团队通用语言都没拉齐,那不是逗我? 包括关于DDD的认知拉齐、事件风暴方法论的拉齐
  • Persona(业务方输入): 明确产品的目标用户是什么样的一群人
  • 电梯演讲(业务方输入):明确项目愿景。明确用户、需求,产品名称、定位、竞争对手、解决问题、卖点。可以快速定义产品的核心域(卖点)和其他子域(现成方案或者与对手差不多的地方)。

电梯演讲模板:
For (Target User)
Who (Statement of needs or opportunity)
The (Product/Service name)
Is a (Product/Service category)
That (Statement of benefit)
Unlike (primary competitive alternative)
Our product (statement of primary differentiation)

事件风暴工作坊流程

团队核心概念的拉齐

  • DDD的概念包括:问题域、解决方案域、通用语言、限界上下文、核心域、子域、领域事件、领域命令、上下文地图、领域模型、聚合、实体、值对象。
  • 业务输入包括上面提到的:Persona,电梯演讲。主要目的是确保大家的项目愿景一致。

事件风暴

  • 什么是事件
    领域专家关心的,业务上真实发生的事情。例如:订单已提交,密码已锁定


    事件
  • 为什么用事件
    通过事件的方式对过去发生的事情进行溯源。能够让领域专家与其他按参与者一起梳理出什么领域模型发生了什么改变

  • 如何确定事件

  1. 确定业务场景,最好是单一且清晰;不要同时梳理过多业务场景
  2. 用“xx 已 xx”的格式在便利贴上写下事件,所有人就事件要达成一致;
  3. 时间顺序将事件贴在白板上;
  4. 事件梳理中的可以用不同颜色便利贴记录问题点
  5. 走查关联关系,确保事件的完整性,防止遗漏。

命令风暴

  • 什么是命令
    命令产生了事件。比如提交订单 -> 订单已提交


    命令
  • 为什么是命令
    命令与事件对应输入输出 (如果了解Redux的,跟Redux中的Action与State有点异曲同工)

  • 如何进行命令风暴

  1. 常见的有:用户的UI操作、定时任务触发、外部系统触发
  2. 一个命令可以产生多个事件
  3. 可以区分发出命令的是人还是外部系统

寻找聚合

  • 什么是聚合
    一组相关领域模型的结合,封装业务的不变性,确保关联关系紧密的领域模型能够内聚在一起。

  • 为什么要做聚合
    封装业务的不变性,同时强迫大家尽可能的简化领域模型之间的关联关系。在业务层面进行高内聚低耦合的设计

  • 如何寻找聚合

  1. 按照事件顺序提问:
    这个事件会改变的领域模型是什么?明确领域模型。(简单理解就是事件中涉及的业务名词)
    这个领域模型是否可以独立访问? 能就是聚合
    不能独立访问的话需要通过哪个领域模型来访问?
  2. 基于聚合的原则来回顾与验证上面划分的聚合,并进行调整。

聚合的原则

  • 聚合根执行业务规则
  • 聚合根有全局标识,边界内实体只有局部标识。
  • 边界外的对象只能访问聚合根,边界内的对象可以持有外部的聚合根
  • 删除聚合根时候边界内的资源都会被删除
  • 只有聚合根能直接从持久化系统查询得到,边界内实体访问只能从聚合根导航
Aggregate Pattern示例

划分限界上下文

  • 什么是限界上下文?
    某个场景下的业务边界
  • 为什么要限界上下文?
    随着业务扩展,软件也变得庞大复杂,业务人员与技术人员的沟通成本也变高且容易误解出bug。所以需要通过限界上下文明确定义模型范围与职责。
    例如:
    在一个电商中,“商品”的概念在订单中、商品列表中、库存中都不大一样。订单中的商品是购买时候的商品信息,那个点的优惠、价格、描述等等;而商品列表中是商品的实时被卖家更新的信息;而库存中不关心价格描述等等,只关心一个库存数量信息;
    还有账户信息,在个人信息上下文可能是个人的基础信息;在认证上下文可能是认证信息。也有可能是第三方登录(比如微信登录),那么微信在这里是一个提供身份的第三方系统
  • 如何划分限界上下文?
  1. 根据前面的聚合和领域模型,他们是否解决同一个业务问题?是则在一个限界上下文,不是就不在;
  2. 如果一个聚合在多个不同业务问题中使用,则可以进行拆分,拆分后划分到不同的限界上下文中。(概念、用法、系统依赖等等)
  3. 问题的大小划分、细节是否要考虑等等,需要和领域专家共同讨论

TIPS && 踩到过的坑

  • 不要事件风暴中同时处理多个复杂业务场景。
    事件风暴并不合适这么用,因此在第一次事件风暴的时候,建议只挑选核心域中的部分业务场景;否则会看到整面墙的业务流程;
  • 不要在事件风暴中引入过量细节。同时业务场景中非核心的部分可以先不关注。
    模型是对现实的抽象,只关注需要关注的细节,不然会陷入泥潭无法自拔。
  • 不要过度追求模型的准确性而花大量时间进行非常精细的设计
    模型本身也是演进式的。再牛x的领域专家也无法在前期预测到软件的走向;再精细的设计随着时间推移也有可能腐化。
  • workshop中可以关注成员的参与程度,确保成员充分发声。
  • 用英文建模有利于通用语言的达成。不然写代码写成英文还得翻译一遍,可能最后叫法又不一样了。
  • 事件风暴之后,注意journey中的逻辑完整,能够形成闭环。避免有关键事件丢失;

你可能感兴趣的:(记一次事件风暴工作坊实践&总结)