《架构整洁之道》第 14 章 组件耦合

2023-05-30 08:48:30 浏览数 (3)

上一章我们讨论的是如何形成组件。这一章我们关注的是组件之间的关系。

无依赖环原则

组件依赖关系图中不应该出现环。

当我们第二天醒来,发现之前运行好的代码突然间不能工作了。这很有可能是因为别人修改了我们所依赖的组件。主要原因是多个程序员同时修改了同一个源代码文件导致的。在项目小,人数少的项目中,这种情况或许不严重。项目大,人数多时,人们每天就都会很忙碌,因为要修改自己的代码,以此达到适应别人对代码的修改,严重时会导致几周都发布不了一个稳定的版本。

在过去 ,针对这个问题,电信行业演化出了两个针对性方案,第一种是每周构建,第二种是无依赖环原则(ADP)

每周构建

在每周的前四天,让所有程序员在自己的私有库上工作,忽略其他人的修改,也不考虑互相集成问题。周五将所有人的变更提交,进行统一构建。

这对小项目来说可行,可是大型项目或者人数众多,会发现周五的时间远远不够用,集成所花费的时间越来越多。

并且,如果我们想要高效开发,就不能频繁构建。但如果减少构建次数,又会影响项目质量。最终整个项目将越来越难构建与测试,质量也会越来越差。

消除环依赖

我们将项目,划分为一些可单独发布的组件,这些组件可以交由担任或者某组程序员独立完成。当完成一个组建的某个版本时,通过发布机制通知其他程序员,并给该组件打一个版本号,放入一个共享目录中。这样,每个人都可以根据公开组件的版本号来进行自己的组件开发。

每个组件发布新版本时,依赖这个组件的团队都可以自行选择依赖哪个版本。这样就不会出现到处相互依赖的情况了,因为任何一个变更都不会影响到其他团队。最关键的是,程序员也不用集中在一起统一构建了。

但是如果想要推广这个开发流程,就必须控制好组件之间的依赖结构,绝对不能允许该结构中存在循环依赖关系

下图是一个拥有循环依赖的错误例子:

这种依赖会带来什么问题?

Database组件需要发布新版本时,就需要Entities组件进行继承,但是出现了循环依赖,所有Database也需要与AuthorizerInteractors进行兼容。这种循环让EntitiesInteractorsAuthorizer形成了一个大组件,并且都需要使用同一个版本。

这个问题在测试过程中会更加明显,因为这三个组件你不能单独拎出来测试了,每次都需要其他两个组件来参与。

并且这种依赖将会很容易出错。

这种问题,在Go语言中,体现的非常明显,直接就不让你编译通过。

打破循环依赖

我们可以用2种方法打破组件中的循环依赖,并将依赖图转化为DAG

  1. 依赖反转(DIP):使其依赖与接口,被依赖方去实现这个接口。

  1. 创建新组件,将依赖关系全部放入新组件,使得原有的依赖关系,转换为同时依赖另一个组件,打破循环。

抖动

采用第二种解决方案就意味着需求的变更,项目结构将会发生变化,因为多加了个Permissions组件。随着项目的演进,这种为了解决依赖的而产生的新组件,和项目的扩张,就叫做抖动。所以我们必须时刻监控循环依赖关系。

自上而下的设计

我们可以得出一个结论,组件架构图是不可能自上而下被设计出来的,要做好这个心理准备,它不可能在项目之初就被完美设计出来,它是跟随着系统的演进而调整出来的。

因为人们的直觉就是,组件和系统功能是相互对应的。实际上不是这样的。组件依赖结构图并不是用来描述应用程序功能的,比如可以看DatabaseEntities组件,它并没有描述功能。所以组件依赖图不能在项目的开始阶段就被设计出来。

组件依赖图的作用和目标就是指导如何隔离频繁的变更。随着项目演进,根据组件的组合原则和各类设计原则(SOLID),组件将不可避免地发生变更,所以我们需要时刻监控组件结构依赖图。

稳定依赖原则

依赖关系必须要指向更稳定的方向。

设计这件事不可能是完全静止的,如果我们要设计一个可维护的软件,那么就必须将变更敏感和不敏感的部分隔离。任何一个预期多变更改的组件A,都不应该被一个难于修改的组件B所依赖,否则这个组件A也会变得难以修改。

稳定性

稳定性应该与变更的频繁度没有直接关系,而应当与变更所需要的耗费的工作量有关。例如一枚竖着的硬币,轻轻一碰就会倒,而一张桌子,想要掀翻它要花费不少力气。

稳定组件

下图中的X就是稳定性组件,因为它不依赖别的组件。同时三个组件依赖于它,所以X有三个不应该被修改的原因,因为它要对三个组件负责。

不稳定组件

下图中的Y就是不稳定的组件。因为Y依赖于三个组件,没有其他组件依赖YY的变更,通常可能是由三个被依赖的组件所带来的,也就是说变更可能比较频繁。Y是有依赖性的组件。

jiagou

当然不可能要求所有的组件都是稳定组件。但是我们需要将稳定组件和不稳定组件得依赖关系处理好,并做适当的隔离。

稳定抽象原则

高阶策略中应该都是稳定组件,越抽象越高阶,就应当越稳定。

稳定性指标

书里,讲的大部分为如何量化稳定性,是一种测量工具。先不看不记录。

1 人点赞