探秘微信业务优化:DDD从入门到实践

引言 | 本文作者从微信团队维护的带货类项目所遇卡点出发,尝试用领域驱动设计方法(简称DDD),保障在快节奏、多人协作的项目迭代中,维持系统的可维护性、可拓展性、高内聚低耦合和稳定性。作者首先剖解相关概念原理,之后代入亲身参与的微信团队实际项目、围绕DDD方法进行优化实操。


DDD 全称 Domain-Driven Design,中文叫领域驱动设计,是一套应对复杂软件系统分析和设计的面向对象建模方法论。它由Eric Evans于2003年提出,但一开始不愠不火。直到MartinFowler于2014年发表论文《Microservices》,引起大家对微服务的关注,至此DDD重新慢慢的回到了大众的视野中。

DDD这几年升温的同时,也受到了很多行业人员对DDD的负面意见。主要原因大概有“晦涩难懂过于抽象”、“很难找到实际的案例参考”、“不知道怎么落地”等。

在学习DDD的过程中,我们也遇到上述卡点。但经过几个月持续学习和实践DDD,我们对其思想、价值、应用方法有更深入了解。这里尝试用白话去总结我们DDD从入门到实践的全过程,尽量每一个概念都用我们的具体实现做出例子,希望能对想一起学习DDD的开发者们有所帮助。

探秘微信业务优化:DDD从入门到实践

一个维护中的业务系统引出的思考

我所在微信团队由后台和前端工程师一起维护某带货类的项目,这个项目我们用了最传统的三层模型来搭建,大概是如下的模型:

探秘微信业务优化:DDD从入门到实践

当这个项目维护几年之后,逐渐出些了一些有意思的情况,我挑选一些主要环节发现的代表性问题介绍下:

情况1(代码层面):少部分代码可读性在长期不同人员的修改下变得越来越差。如某个带货的核心rpc逻辑没有任何嵌套平铺在一个函数,单函数代码行数达到几百行,可读性和维护性极差,成功化身为“技术护城河”。

情况2(微服务层面): 某些微服务初始职能划分较为简单,导致少量模块在后续高频迭代中快速膨胀。如其中的mp模块,原本职能是用来承接B端门户的功能;当我们决定拆分这个庞大的模块时,这个模块已经承载了204个rpc。过多的能力承担让它编译变慢、变成链路单点、改动较多、一旦出现问题影响较大。

情况3(业务团队层面):带货项目会使用一些其他业务系统的接口和数据结构。当这些业务系统想要修改这些接口和数据结构的时候 ,一方面可能未察觉这里的依赖将导致线上问题, 另一方面可能在业务间沟通后发现耦合处比较多,不容易改动。

维护这个项目的过程中,我们进行了一些思考:在一个复杂业务系统中,代码结构要如何设计、微服务的横/纵向职能要如何划分、业务团队之间如何交互,才能保障在快节奏、多人协作的项目迭代中,维持系统的可维护性、可拓展性、高内聚低耦合和稳定性。

而传统的开发模式不管是面向过程(POP)还是面向对象(OOP)的思维,都没办法从微服务层面指导我们找到这些问题的答案。但我们发现,有两种方法解决这个问题:

1.寻找一个总是有时间、总能做出正确决策的中心节点同事,介入每一处全局/细节的设计并统一做出决策。

2.寻找一个新的规则/规范来做指导,让每一位开发工作者都能有做出正确决策的依据。

在Tencent的氛围和环境中,第二个方法无疑是更合理的,所以我们想到了领域驱动设计(DDD)。
探秘微信业务优化:DDD从入门到实践

DDD的分层架构

DDD最有标志性的一点,就是将传统软件设计三层模型转化为了四层模型,这个转化如下图所示:

       

探秘微信业务优化:DDD从入门到实践

乍看之下,四层架构引入了很多概念,如领域服务、领域对象、 DTO、仓储等等。我们先不用在意这些细节概念,因为下一节会逐个分析并列举我们的实现例子。我们先关注这几个关键的层:用户界面层、应用层、领域层、基础设施层。我们来看下他们的职能分工:

  • 用户界面层:网络协议的转化/统一鉴权/Session管理/限流配置/前置缓存/异常转换

  • 应用层: 业务流程编排(仅编排,不能存在业务逻辑)/ DTO出入转化

  • 领域层:领域模型/领域服务/仓储和防腐层的接口定义

  • 基础设施层:仓储和防腐层接口实现/存储等基础层能力

这里必须要说的是,这四层不一定是指物理四层,也可以在一个微服务中拆分逻辑四层。四层架构有很多变种,如六边形架构、洋葱架构、整洁架构、清晰架构等等。这些繁多的概念我们这里不过多讨论,而是仅以洋葱架构为例。此处我们将着重强调DDD中的依赖倒置(DIP),以便后面更容易介绍仓储/防腐层等概念。

依赖倒置(DIP):

1.高级模块不应依赖于低级模块。两者都应依赖抽象。

2.抽象不应依赖细节。细节应依赖于抽象。

探秘微信业务优化:DDD从入门到实践

如上,洋葱架构越往里依赖越低,越是核心能力。基础设施层在最外面,依赖其他层,这是是因为DDD中其他层等需要定义自己需要的基础能力接口,而基础设施层负责依赖并实现这些接口,从而实现整体依赖倒置。这体现了DDD的由全局入细微、自顶层向下层的设计思维。

探秘微信业务优化:DDD从入门到实践