DDD之我的感悟

首先DDD并不是一个什么新鲜的东西,早在2014年就有接触过,但那个时候DDD设计理念,接受度并不高,毕竟大家普遍采用的还是集中式架构。在微服务盛行的当下,我和我的技术团队踩过不少坑,最尖锐的一个问题是:微服务到底怎么拆分和设计才算合理,拆多小才叫微服务? 而微服务的边界历来也是最容易产生争议的地方,业务的日渐复杂也是可以预见的,微服务的价值确确实实存在。在架构设计过程中受制于三层架构碰了一鼻子灰之后,一次偶然(也是必然)的机会再次提起了DDD,在一番研究后,我发现,运用 DDD 设计思想实现的微服务边界确实清晰很多,业务领域划分也十分合理。后来,我和我的伙伴们用 DDD 做了很多的微服务实践。再次提起DDD,决定好好去研究一番,并将其落实到具体工作中去,有感而发,记录如下。
一、概念
DDD:是一种架构设计方法,从业务领域的视角划分领域边界,涉及到如下一些概念
1、界限上下文
2、领域、子域、通用域、支撑域
3、实体
4、值对象
5、聚合
6、聚合根
二、四层架构
与传统三层架构之间的对比


image.png

DDD 的分层架构在不断发展。最早是传统的四层架构;后来四层架构有了进一步的优化,实现了各层对基础层的解耦;再后来领域层和应用层之间增加了上下文环境(Context)层,五层架构(DCI),但个人比较青睐DDD的四层架构。


image.png

在最早的传统四层架构中,基础层是被其它层依赖的,它位于最核心的位置 ,那按照分层架构的思想,它应该就是核心,但实际上领域层才是软件的核心,所以这种依赖是有问题的。后来我们采用了依赖倒置的设计,优化了传统的四层架构,实现了各层对基础层的解耦,左边是传统的四层架构,即还是以调用顺序组织的。右边是依赖倒置的。
所谓依赖倒置即虽然按照运行时的调用关系是A依赖B,但是我在编译环节是让B依赖A。即A提供接口,B来实现。 主要是两点
1. 领域层不再依赖其他任何一层,这样能够实现具体的技术实现不会影响业务,不用纠结到底如何持久化,如何发消息。定义接口,让基础设施层实现。这样可以让领域模型易测试,易维护。
2. 基础层依赖其他各层,包括领域层、接口层、应用服务层。
上层调用者(上层对象)将上层数据转换成下层接口能识别的参数,然后调用下层接口,最后封装下层接口响应的数据。
依赖倒转要求高层模块不应依赖于底层模块,二者都应依赖于抽象,抽象不应该依赖于细节,细节应该依赖于抽象,因为抽象更稳定。
DDD各层的主要职责
image.png

1、用户接口层
用户接口层负责向用户显示信息和解释用户指令。这里的用户可能是:用户、程序、自动化测试和批处理脚本等等。
2、应用层
应用层是很薄的一层,理论上不应该有业务规则或逻辑,主要面向用例和流程相关的操作。但应用层又位于领域层之上,因为领域层包含多个聚合,所以它可以协调多个聚合的服务和领域对象完成服务编排和组合,协作完成业务操作。

此外,应用层也是微服务之间交互的通道,它可以调用其它微服务的应用服务,完成微服务之间的服务组合和编排。
这里我要提醒你一下:在设计和开发时,不要将本该放在领域层的业务逻辑放到应用层中实现。因为庞大的应用层会使领域模型失焦,时间一长你的微服务就会演化为传统的三层架构,业务逻辑会变得混乱。
另外,应用服务是在应用层的,它负责服务的组合、编排和转发,负责处理业务用例的执行顺序以及结果的拼装,以粗粒度的服务通过 API 网关向前端发布。还有,应用服务还可以进行安全认证、权限校验、事务控制、发送或订阅领域事件等。
3、领域层
领域层的作用是实现企业核心业务逻辑,通过各种校验手段保证业务的正确性。领域层主要体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。
领域层包含聚合根、实体、值对象、领域服务等领域模型中的领域对象。
这里我要特别解释一下其中几个领域对象的关系,以便你在设计领域层的时候能更加清楚。首先,领域模型的业务逻辑主要是由实体和领域服务来实现的,其中实体会采用充血模型来实现所有与之相关的业务功能。其次,你要知道,实体和领域对象在实现业务逻辑上不是同级的,当领域中的某些功能,单一实体(或者值对象)不能实现时,领域服务就会出马,它可以组合聚合内的多个实体(或者值对象),实现复杂的业务逻辑。
4、基础层
基础层是贯穿所有层的,它的作用就是为其它各层提供通用的技术和基础服务,包括第三方工具、驱动、消息中间件、网关、文件、缓存以及数据库等。比较常见的功能还是提供数据库持久化。
基础层包含基础服务,它采用依赖倒置设计,封装基础资源服务,实现应用层、领域层与基础层的解耦,降低外部资源变化对应用的影响。
比如说,在传统架构设计中,由于上层应用对数据库的强耦合,很多公司在架构演进中最担忧的可能就是换数据库了,因为一旦更换数据库,就可能需要重写大部分的代码,这对应用来说是致命的。那采用依赖倒置的设计以后,应用层就可以通过解耦来保持独立的核心业务逻辑。当数据库变更时,我们只需要更换数据库基础服务就可以了,这样就将资源变更对应用的影响降到了最低。
三、DDD实践的代码结构
1、interface :用户接口层
dto:数据传输对象
assemble:dto与do之间的转换
facade :controller接口
2、application :应用层
event:定义事件接口
publish:事件发布,定义事件发布的接口,由基础设施层去实现
subscribe:订阅事件,定义事件订阅的接口,由基础设施层去实现
service:编排领域服务
3、domain:领域层
entity:实体
respositeory:定义仓储api,最终由基础设施层去实现
service:领域服务
event:存放处理事件的逻辑
vo:存放值对象
4、infractructure:基础设施层
acl:防腐层
event: 事件发布&事件订阅的具体实现
persistence:持久化 :orm具体实现
respository:仓储具体实现
config

四、设计领域模型的通常步骤以下:

  1. 根据需求划分出初步的领域和限界上下文,以及上下文之间的关系;
  2. 进一步分析每一个上下文内部,识别出哪些是实体,哪些是值对象;
  3. 对实体、值对象进行关联和聚合,划分出聚合的范畴和聚合根;
  4. 为聚合根设计仓储,并思考实体或值对象的建立方式;
  5. 在工程中实践领域模型,并在实践中检验模型的合理性,倒推模型中不足的地方并重构。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容