cover_image

DDD之业务系统搭建的设计思考

锦越 蚂蚁研发效能
2022年11月14日 09:30

图片

DDD( Domain Drive Design)领域驱动设计,它最擅长的是解决复杂的业务问题,无论你是产品,开发还是测试同学,都能通过一套/多套领域模型来洞悉整个系统的设计,以及多个系统之间的边界。本文从一个具体的案例来分享,如何利用 DDD 思想去落地一个从 0 到 1 的业务系统。
在开始阅读本文之前,我非常建议各位同学在工作中去养成画图的能力。画图不是画饼,更不是吹嘘自己的架构设计能力,而是要着眼当下的问题,把知识「传递」给其他的同学,无论是技术也好,还是业务,我们需要通过模型将我们所知、所想、所悟清晰的表达出来。知识的传递是领域驱动设计中重要的一个思想。


01

知识的传递


我们常常遇到这样的问题:
业务:我们要造一艘豪华邮轮,里面是 5 星级配置
......
最终的交付可能是一艘快艇。
图片
在《领域驱动设计》一书中,作者 Eric Evans 讲过:在项目的最初阶段,需要业务,产品和技术同时参与进来。尽可能用 UML 建模语言把业务含义和产品功能描述清楚,让知识传递。这里的 UML(模型)语言可能有很多种,有产品视角的,有开发视角的,也有测试视角的。
在公司中,每个团队往往是各司其职,很多人只会接收「他的上游」给他的知识,却忽略了更上游的知识。在这种情况下,知识的传递可能会出现不完整,甚至是断层。这种糟糕的情况发生后,下面的开发人员往往会按照自己的「经验」来办事,认为他们做的是合理的。这种做法的最终结果可能就是把豪华邮轮变成了一艘快艇。

图片

在项目进行的过程中,每个环节都会有部分知识流失掉,我们可以采用模型将各个环节的知识描绘出来,清晰传递给下游。模型相比文字更加直观,并且让不同时间段进来的人都可以得到一致的理解。
本文将分享我之前的一次实战经历:客服系统我会从业务调研、业务划分、领域确定、项目研发等方面来进行分享。如果大家有更好的想法,可以留言一起探讨。


02

业务迭代周期


在构建这个系统之前,我经过了漫长的业务调研,首先是公司现有的业务和系统能力,其次调研了市面上已经产品化的客服系统,包括:互联网公司的产品,传统的企业级解决方案的产品等。基于此调研,我做了归纳和总结:

图片

在业务的调研阶段,我们先不关注业务具体的实现细节,否则我们很容易在一开始就进入了「点状思维」。
借用一句诗,是这么说的:横看成岭侧成峰,远近高低各不同。
在项目伊始,我们需要有全局观,把当下的业务想清楚,抽出主线「Domain Model」,往往这个核心的模型是整个项目的精髓所在,把握好了这个会让我们会很有底气和信心面对未来复杂而多变的新增业务场景。当然,也需要把未来的业务思考一下,看看当前的业务和未来的业务是否能在这个主线中很好得串联起来。
图片
乍一看,这么多业务,都需要做吗?不一定都需要做,且需要做的模块也是分批上线。我们需要进一步来梳理系统的核心业务模块(不做整个系统就会run不起来)。

图片


03

领域模型

在构建领域模型的时候,尽可能的把每个域(Domain)的职责表达清楚,并把不同域之间的交互(Context)大致确认下来。因为无论未来每个域的业务如何变化,我们总能找到设计的初心,以至于不会在业务迭代的过程中,整个项目框架发生大的变化。

图片

在客服系统中,重要的一个概念是会话(session),会话id(sessionId)将会是一个非常重要的设计。一个会话包含了一个完整的客户咨询:用户发起会话,智能机器人问答,人工客服介入,知识库内容的选取,会话评分,会话标签等等。在不同的域中,我们要抽象一个核心的主线出来,在客服系统中,这个主线便是会话id。
另外,我们需要明确现阶段我们的目标是什么,以及未来我们的产品的扩展能力(未来要做的),在我们的领域模型中去验证。在加入新的模型后,我们需要验证:
  • 是否影响到了现有的域,是否让现有的域变得不稳定甚至有大的重构?
  • 与现有域之间的上下文界限


04

系统划分


在划分系统边界的过程中,如何更高效和清晰的把控系统的边界问题?这是架构设计的过程中必须要思考的一个问题。可以按照下面的思路来进行:
  • 整个系统的业务子模块梳理出来
  • 做一层抽象,把业务关联性比较强的业务划分到一起,形成各个子域
  • 各个子域中的上下文明确出来,用最清晰的表达
  • 不断地做微调,形成一个最终的领域划分
图片图片

图片

领域驱动并不是一个最终的系统划分指导思想,它是一个动态调整和适应的过程,在这个过程中,我们朝着最合适的方向前进。


05

研发规范

研发规范最好的做法是在框架层面落地,其中框架主要是指项目的骨架(Archetype),这里面最主要的包含了:
  • 一个标准的项目骨架
  • 清晰的项目分层
  • 各个分层清晰的依赖关系
  • 框架与RPC组件的分离,对多 RCP 组件的支持,如:dubbo,thrift,HSF,SOFA 等,有更多的灵活性
图片
上面的这个图,大家已经很熟悉了。我们还是要能跳出骨架本身去思考为什么要这样去设计。如果去掉 SOFA RPC 还能 run 起来吗?
在上述骨架(Archetype)中,很好定义了分层:
  • test(测试层)
  • biz(业务层)
  • core(领域核心)
  • common(通用层)

图片

我们需要准确把握各层的设计初衷,归纳起来讲就是:将业务实现与数据接耦,通过在 core 层做抽奖(core service & core model),将通用的服务能力下沉。避免在业务层直接调用数据层服务,从而有过多的耦合让服务「不够通用」,是「定制化的实现」,这不是一个好的业务系统所期望的结果。


06

总体架构


一个简单的客服系统架构图示例如下:

图片


07

总结


领域驱动设计比较适合复杂的业务系统,尤其适合构建从 0-1 的业务系统,这里会没有历史的业务包袱,把设计进行地更加深入和合理。
图片

代码设计推荐:
从0到1教你写好系分
设计模式实践&技巧大盘点:帮你打开思路,灵活变通各类应用场景
代码设计技巧(一):运用三个层次构建代码

代码设计 · 目录
上一篇从0到1教你写好系分下一篇代码设计技巧(一):运用三个层次构建代码
继续滑动看下一个
蚂蚁研发效能
向上滑动看下一个