惟客数据DDD实践探索之路 发挥软件系统的业务价值

DDD早在2004年就由埃里克·埃文斯提出,但一直处于不温不火的状态,直到微服务盛行之后,DDD再次回到人们视野之中。京东、美团、华为等巨头也都在自家架构中实践了DDD。

DDD究竟有什么优势?它是如何落地的?实施难点又在哪里?结合惟客数据实践DDD的经验,今天就来一起探讨下。

咱们先从一个场景说起。

通常在研发流程中,需求评审完毕后就交由某个研发做设计,方案的设计完全取决于某个人的经验和对依赖模块的熟悉程度,可能很难识别出模块设计上的不合理。即使可以识别出,往往都会以技术的语言和产品经理进行沟通,产品经理可能很难理解,最终难达到预期的目的。

以惟客服务过的某地产集团案例为例。客户的诉求是实现“转赠功能”,比如用户A下单5件商品,将其中2件转赠给用户B,此时用户B的“我的订单”栏会出现一笔含有2件商品的订单,且不可退款的同时,用户B还可以再次实行转赠。

这意味着需要在订单领域生成一种“特殊的订单”和“特殊的拆单”,该订单仅能使用且不能退款。

需求评审完后,产品、研发一起开始做“领域建模”,由于涉及订单领域,也对照之前的“订单模型图”做了方案的设计,发现订单域承载更多的是交易相关,把转赠业务耦合进来,十分困难。

但研发在模型图里发现了专门承载履约的“核销聚合根”,只要核销权限能转出去,就可以满足业务场景,产品经理也十分认可,最终将产品做了修改,将原先的订单转送,变为了履约权限的转赠。

在上面的案例中,无论从产品设计角度,还是转赠场景和交易场景,划分都更清晰;从代码设计角度,减少冲击到订单域,避免现实中独立的两块业务在系统中耦合成一个模块,从而造成订单的核心代码被冲击,后续难维护的后果。最终实现了“多赢”的局面。

这种“多赢”的局面,就取决于DDD过程中带给我们的几点改变:

1、领域模型设计一定程度上拉齐了团队的设计水平,不再取决于某几个人的“经验”。

2、产品、研发建模的过程中,深究业务场景,推导出技术设计的同时也回补了需求漏洞。

3、团队内统一语言,尤其是产品和研发之间,沟通成本低,减少了由于理解差异导致的风险。

4、原先依赖的模块,也采用了DDD的设计,有完整的模型文档,并且有效识别出来了“订单聚合”、“核销聚合”,才使得转赠模块在做设计有了很好的基础。

基于对以上场景的了解,我们再回归定义,从定义出发,一步步拆解。

概念理解:DDD是什么?

DDD全称是领域驱动设计,这里的“领域”可以理解为业务边界,以及指定范围内待解决的业务问题。因此DDD它不是一种架构,而是一套思想,是一种拆解业务、划分业务、确定业务边界的方法。

DDD可以通过合理运用面向对象的封装、继承、多态等设计要素,降低或隐藏整个系统的业务复杂性,帮助我们设计出清晰的领域和边界,并使得系统具有更好的扩展性,很好的实现技术架构的演进,应对纷繁多变的现实业务问题。

DDD的优势在哪里?

程序员擅长从技术角度来解决项目问题。但一个软件系统是否真正可用,需要通过其提供的业务价值来体现。因此在关注技术的同时,DDD更强调将关注点转向软件系统所提供的业务价值。

我们先回顾下产研团队的协作模式,通常是将一个产品开发上线的各个过程拆出来,由市场/运营、产品、UI交互、前端、后端、测试等角色来做分工,每个过程专人负责。

这么做的好处是标准流水线作业,个体生产效率比较高,但坏处是大家都盯着眼前的一亩三分地,自然很容易忽略整体,更难从整体业务价值出发。同时也容易出现信息不对称的问题,比如产品在讨论A时,前端以为是说B。

那么,根据惟客数据在核心产品“惟客云”中实践DDD的经验总结,其优势可以包含以下几点:

统一语言:领域专家、产品、技术、测试等人员都在一起进行事件风暴(整理出相关联的业务指令和事件),在同一个场景下使用统一语言进行领域模型构建,信息传递不会丢失。

提高效率:设计就是代码、代码就是设计,可以根据领域模型图对编辑进行翻译,即使是新人接手也能快速理解整个业务和代码,上手就能写。

边界清晰:战略设计帮助产品决策人理解哪些投入是最重要的、哪些既有软件资产是可以重新拿来使用的、哪些人应该被加入团队中?战术设计则帮助产品研发人员具体实施。

降低成本:先划分业务边界,确认核心业务,避免伴随功能迭代后的代码不断叠加,导致代码耦合,降低维护成本。

以降低成本为例,假设我们要做一个电商订单下单需求,涉及到用户选定商品,下订单、支付订单、对用户下单时的订单发货:

常见做法是在分析好业务需求之后,开始设计表结构,订单表、支付表、商品表等等,然后编写业务逻辑当功能迭代,订单支付后要支持取消,下单商品要支持退换货,就又需要加表,并针对实现的逻辑不断进行修改。这也意味着当功能不断迭代,代码也会层层上叠。

而DDD要求先划分业务边界。该场景下的核心是订单,那么订单就是业务领域里的聚合逻辑体现。支付、商品信息、地址等等都是围绕订单实体。订单本身的属性决定之后,类似于地址只是一个属性的体现。当你将订单的领域模型构建好之后,衍生了仓库的上下文。

总结来说,DDD优势在质量、效率、成本3方面都得到了体现。

惟客是如何实践DDD的?

从时间线来说,可以分为3个阶段:

2020年7月,引入DDD,在小项目和模块进行试点;

2021年6月,完成在大会员模块进行实践和应用;

2022年3月,完成公司交易、营销、会员、家装产品线的改造和重构。

重点以3月份的项目为例。惟客投入70人参与本次项目,目的是解决老旧项目之间耦合严重、业务边界不清晰、代码重复率高、维护成本高等问题。从落地步骤来拆,包括5个部分:

需求评审

1、过需求、了解相关联业务的用户故事

2、产品输出用户故事地图、原型图、流程图,开发理解相关资料

拆用户故事

1、对照用户故事地图将用户故事进行细分

2、整理出相关联的业务指令和事件(事件风暴)

3、用户故事评审,确保需求没遗漏、业务指令和事件划分正确

领域模型图设计

1、识别应用上下文,划分领域界限(核心、通用、支领域),拆分成多个子域

2、根据用户故事及业务指令区分出查询模型和命令模型

3、在领域内绘制出相关联业务的领域模型图(包含查询模型、聚合、聚合内聚合根、实体、值对象的关系、实体具有的能力、领域服务、领域事件)

4、领域模型图评审

代码实现

1、对照领域模型图建业务指令、事件、实体、值对象、实体能力及领域服务

2、完成领域模块开发,建db入库

3、代码评审,对照领域模型图

4、完成所有业务开发

单元测试

1、对于聚合能力的单元测试

2、领域服务,指令的单元测试

实践过程中遇到哪些问题

为创建通用语言腾出来的时间和精力

通用语言是指非技术岗位也能很容易理解的语言,在目标拉齐的基础上,需要拉齐各个角色对术语都使用统一名词,对业务价值以及规则的描述使用统一的描述方式和规则,并且需要使得每一个人都能听的懂。

以商品条形码为例:

领域专家:从场景角度分析,它主要是供小程序扫描这个条形码进行购买商品

产品:从规则角度分析,商品编码,长度是多少位,组成规则是什么。

开发:按照功能事项的角度去分析,barcode,商品的sku级别的唯一标识,存储方式是什么。

很明显,大家分析问题的角度不一样,给出的语言不同,但本质上商品条形码=商品编码=barCode,因此需要花时间拉齐不同角色间的语言。

领域专家对于实践DDD很重要,但这个角色通常是业务专家,他们工作繁忙、时间难约,较难持续在一个项目中消耗太多时间。

因此在落地中,建议尽可能一次性把业务相关的疑问和问题准备好,减少对接次数、提高效率。

由过程编码 -> 面向对象编码

由数据模型 -> 领域模型

领域模型关注的是领域本身,是业务领域的核心实体,体现在问题域关键概念和之间的联系。构建领域模型的目标是看模型能否清晰表达业务语义、模型能否显性化,扩展性是其次。

数据模型关注的是数据存储,在我们所有的业务中都离不开数据,离不开对数据的CRUD。构建数据模型目标是看扩展性、性能等非功能属性,业务语义的表达则是其次。

人最难转变的是思维惯性,而不是技术和策略本身。因此在实践前,对以上3点有心理预期,并提前做好应对方案,可以更快地落地DDD。

总之,如果企业希望能更好地发挥软件系统的业务价值,从长期价值主义出发,提高代码的可维护性、可扩展性,那么DDD绝对是一套值得尝试的方法

(免责声明:本网站内容主要来自原创、合作伙伴供稿和第三方自媒体作者投稿,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所提供信息的准确性及可靠性,但不保证有关资料的准确性及可靠性,读者在使用前请进一步核实,并对任何自主决定的行为负责。本网站对有关资料所引致的错误、不确或遗漏,概不负任何法律责任。
任何单位或个人认为本网站中的网页或链接内容可能涉嫌侵犯其知识产权或存在不实内容时,应及时向本网站提出书面权利通知或不实情况说明,并提供身份证明、权属证明及详细侵权或不实情况证明。本网站在收到上述法律文件后,将会依法尽快联系相关文章源头核实,沟通删除相关内容或断开相关链接。 )