整洁架构的新理解

1632498308.png

话不多说,直接上图

看到这个图,我想应该很熟悉了,这个图出自《Clean Architecture》这一巨作中。距离第一次看到它,应该有大约2年之久了,当时还是因为刚入职,然后在做的项目的包就是根据这个图按照依赖关系划分的层次。

从图中基本可以得出以下几点

  1. 图中分了四层,每一层都有对应的职责;
  2. 依赖方向,指向圆心,即低层机制指向高层的策略;
  3. 业务规则是在User Cases 和Entities层;

以上几点基本就是看图说话,但是你看到这张图,对你的开发似乎并没有实质的作用,可能只能知道以上几点,也可能这只是张图,很难从多个角度来表达。

下面根据自己这两年的项目设计实战经验来聊聊

我们说新项目立项,大体上开始做的第一件事,就是去和需求人员聊业务,看看一般会有哪些业务场景或者叫User Cases,当我们把所有的情况都了解清楚后,那么我们基本可以知道该系统会有哪些参与者、业务行为等,在标准设计中就可以产出用例图。很巧的是,在上面的图中,我们也发现了User Cases。UML中用例图是用来描述系统参与者之间的交互及用例之间的关系;而图中User Cases是系统的应用场景下的业务逻辑,大体就是代码层面用例图的实现。

所以增加一点

  1. 这张图对应到代码实现,应该是从user Cases层开始;

这一点是我最近才领悟到,因为这张图在之前总是感觉“无用”,现在把架构设计与这种图连起来了,甚至到了开发层面,从User Cases层开始开发。那么也就决定了你的协议也只会有一套,就是User Cases层定义的API。

只有这一套协议,这个问题原先和团队里的同事有争论过,之前一直都理解不了,因为一直认为Controller层才是应用的协议,因为一般与前端约定时就是通过约定JSON协议等。如果真是Controller,那么在MVC里就会发现应该让Service层实现去依赖Controller API,这样依赖方向就发生了变化,如果有一天交互方式替换成了GRPC,那么你的Service依赖就可能会跟着改,所以在MVC里,业务协议其实应该也是Service 层的API。

所以开发就可以更敏捷起来,在需要的时候再去加功能,比如一个系统开始没有对外提供访问的需求,那么就不需要提供Rest API或RPC API等。

这是对第4点的补充说明。

再增加一点

5.由图中的依赖关系,得出DIP 依赖倒置原则;

图中的Controller层与User Cases层,低层次的机制依赖高层次的策略,这里Controller就是次层次的机制,因为它是一种实现,Controller我们一般默认认为是Rest API实现;而User Cases是业务逻辑的核心领域,属于高层次。我们先开发的UserCases且已定义好API协议,低层次的Controller应该依赖高层次的抽象API协议,而控制方向即调用方向, 这里依赖抽象就是符合DIP的。

最后一点

6.应该允许跨层调用,而非只允许相邻层调用

图中DB,在最外层,如果一个系统需要依赖数据库,那么User Cases 层就需要与最外层DB交互。在DDD中有个概念叫 Repository(仓储),用于管理领域对象的生命周期。根据图中的依赖关系,虽然User Cases需要调用DB,但是应该也是DB依赖高层策略,所以这里就需要符合DIP,即定义抽象Repository API,由DB 层具体实现。这是一种跨层调用。还有就是如果只是查询,完全可以跳过领域对象层,直接用DTO对接repository层返回的数据,如CQRS。

理清架构中各个模块的依赖关系,是非常重要的,我觉得有几个原则

  1. 避免循环依赖
  2. 依赖方向应该是一致的
  3. 被依赖的越多,越稳定,就越通用

最最后一点

6.在1点中说有4层,但我觉得实际中可能不应该只有4层

虽然图中Controller与Gateway在一层,如果放在一起,就会难免造成误解,以为Controller是提供提供服务的,而Gateway是访问第三方服务的。

好啦,就这样了~~~

很喜欢一句话:永远不要忘记在这场生命的旅行中,我们永远都在做两个选择,维持现状或是改变自己。

你可能感兴趣的:(整洁架构的新理解)