天天看点

领域驱动设计落地方案

一、现实问题

场景1

需求评审

产品大大:麻烦帮忙看一下xxx功能是什么逻辑,如果在xxx场景下能不能支持xxx

我:稍等我看一下代码的具体实现

一段时间后~

我:之前代码是这样写的,xxx xxx,好像不行,但xxx这样改,可以支持

场景2

线上异常数据出现,技术支持让排查问题

技术支持:入参xxx 出参xxx

我:怎么会呢,这个入参怎么会走这段流程,按理说不应该走这边嘛,然后输出xxx

二、问题原因

  1. 技术实现对于产品大大来说是个黑箱,产品大大一般对于产品本身的大局规划有深度理解,但对于产品功能细节是如何实现的可能模糊不清。所以在复杂场景下,特别是多条件叠加输入时,可能不知道代码流程会走
  2. 一般项目都由多人开发,开发人员对于经过多次版本迭代后的代码存在理解偏差

三、解决思路

对于业务模型进行抽象(DDD),对业务流程进行可视化输出。从而提高业务透明度,代码可维护性。

四、解决方案

第一阶段:战略设计

对业务进行领域战略建模,组织资深业务方、产品和技术进行思维碰撞,沟通目前产品功能和将来的规划。主要探讨产品是在干什么,解决什么问题,能给用户带来什么反馈(比如说交易系统核心就是买卖双方签订某种契约,买方如何付款,卖方如何履约。再比如说结算系统核心问题是根据订单决定给谁分帐,怎么分账)。

该阶段主要是统一目前的业务认知,咱们的系统到底在解决什么问题。

输出:

  1. 典型用户:产品服务对象。用一个人来描述一群人,就像用中间值描述一组数一样。减少修饰,避免误解。根据业务变化,迁移用户画像。
  2. 用户故事:以用户的角度去描述故事,这些故事就是产品使用的主要场景。

问题域的总结有三大好处:

  1. 统一思想。域模型的核心价值在于统一项目中各个相关方对问题的认识, 从而避免下游输出的结果和上游需要解决的问题脱节。
    领域驱动设计落地方案
  2. 清晰团队分工合作。产品可以划分为多个问题子域,由特定团队完成。
  3. 规划。产品往往是不断发展,但我们需解决的核心问题是在特定范围中的,所以提炼出核心问题域后,能减少变化对模型的冲击。
第二阶段:战术设计

对第一阶段总结问题域进行数据模型和业务流程设计。

领域实体类型设计

在第一阶段会输出很多的用户和用户故事,首先我们需按照优先级对故事进行排序,优先级高的就是核心场景。

接着我们需要在这些场景里面找出实体,也就是我们需要在大量的场景描述中找出对应的名词。比如说高中生张三下订单购买复习资料(举个例子,这段描述很简单),张三、订单和复习资料就是我们应该关系的实体,而高中生是形容词(是属性。这个也是业务方应该关心的,因为代表一类群体,能够帮助产品更好的聚焦用户),购买是行为(这是后边会讲到)。

有了实体之后,我们需要对实体进行总结抽象输出实体类型。比如说买家(张三)、订单(订单)和商品(复习资料)。

这个时候有同学可能就要问了,这不是我们常见的数据模型吗?确实领域模型需要被持久化,从而保存当前的状态。个人理解,怎么持久化只是一种方式,我们可以把实体直接持久化到数据库,也可以把实体拆分存到数据库中。比如说,一个人有姓名、身份证号、手机号、地址、买家身份等属性,我们可以把实体直接存到一个表中,也可以把实体拆分成多个表(user,address,role等)按照外键进行关联。

所以实体类型是对实体的抽象,数据模型是对实体当前状态的持久化。

在实体类型设计过程中,我们需要总结问题域中的实体,包括实体属性、关联关系和状态,从而抽象成实体类型。

实体类型能力抽象

有了实体类型之后,可以进行实体能力抽象(当然也可以在实体类型抽象时,顺带抽象实体能力)。能力的意思是实体能触发的行为,比如说人能看听闻触,这些就是基础能力。能力可以以实体类型方法的形式进行实现,也可以使用Manager层进行封装。只要遵循一个原则:实体和能力是一个高度自治的整体,实体状态的变更只能通过实体能力或者事件触发。不能将实体能力实现在各个业务流程中,这样不利于维护。

当然能力可以进行水平扩展,比如说带望远镜看,带听筒听。所以我们在进行实体能力抽象时主要关注基础能力,当然也要保留能力的扩展点(在简单场景中也可以不实现能力扩展点)。扩展点具体实现方式很多,比如说策略模式,SPI等,只要遵循一个原则:能力的消费方,不需要关注能力的具体实现,只关注能力的抽象。

业务流程设计

第一阶段中的用户故事需要抽象成业务场景,也就是一个个业务流程。

具体实现时,比如说下单场景,需要校验库存(商品能力),锁定库存(商品能力),生成订单(订单能力)。再比如说付款场景,需要扣减库存(商品能力),更新付款状态(订单能力),更新积分事件通知(积分能力)等等。

下图是对付款流程的举例,可能现实付款流程更复杂。

领域驱动设计落地方案

编码

编码过程是最简单的,有了之前的输出。我们只需要对实体和实体能力进行实现,具体可以以DDD充血模型进行实现,也可以自己封装高度自治的模块。然后进行业务流程的编排,编排可以用责任链模式。业务流程是根据基础能力进行编排的,是静态的,不存在在代码运行期进行动态编排,所以可以对业务流程进行可视化输出,以便将代码流程透明化输出给业务方。

最后,这是我和我的同事们在实际业务过程中的一些输出,可能有些主观的见解,欢迎指正。

参考:

《实现领域驱动设计》

https://mp.weixin.qq.com/s/LY9cT5P6WilLBKtXeT_p1g

https://developer.aliyun.com/article/6383

继续阅读