读书笔记 架构 第三章

第三章:模块化
度量模块化
三个关键概念:

内聚性(cohesion)
耦合性(coupling)
共生性(connascence)
内聚性
内聚性是指一个模块的所有部分必须在一起的程度。换句话说就是度量各个模块必须在一起的程度。理想状态下,一个内聚的模块所有的部分都必须在一起,因为如果把它们分成更小的碎片,就会导致其他模块必须通过模块间调用来得到有用结果,从而使得模块间更加耦合。

内聚性度量,从最好到最差

功能内聚:模块的每个组件都互相关联,并且模块只包含对功能必要的模块
顺序内聚:两个模块互动,一个模块输出数据,成为另一个模块的输入
通讯内聚:两个模块形成一个通讯链,每个模块各自操作信息并且/或者产生一些产出。例如,添加一个记录到数据库并基于这些信息生成一个email
流程内聚:两个模块必须以一定顺序执行代码
时间内聚:模块在时间上依赖
逻辑内聚:模块内的数据逻辑上相关而非功能上相关。例如:有一个模块从文本,序列化对象或流中转化信息。操作是相关的但是功能是很不一样的。
意外耦合:模块中的要素除了在同一个源文件中以外互不相关。这是最糟糕的一种内聚
内聚性并不像耦合性一样有精确的度量指标。
一种度量方法
LCOM(Lack of Cohension in Methods)

没有共用字段的方法数量

耦合性
输入耦合:度量从外向内的连接数
输出耦合:度量从内向外的连接数
抽象性,不稳定性和主序列距离
抽象性是指抽象和实现的比例。度量抽象和实现的比例。例如:假如一个代码仓库只有一个main函数,这个代码仓的抽象度为0.另一个极端是,一个代码库有太多抽象,让开发者难以理解

不稳定性度量代码的易变性。例如,假如一个类调用了很多其他类的方法,那它就很不稳定

抽象的代码通常更稳定,但是更无用,更难理解。
当我们对代码做抽象的时候需要考虑它带来多少稳定性,否则付出的难以理解就是不值得的。

共生性(Connascence)
如果两个模块,其中一个的改变需要另一个也相应改变以保持系统整体的正确性,那么我们说这个两个模块是共生的

两类共生性

静态共生性
动态共生性
各种共生性按从优到差的顺序排列依次是:

静态共生性包括

命名共生性:模块之间必须约定实体命名
类型共生性:模块之间必须约定实体的类型
意义共生性:模块之间必须约定实体的意义
位置共生性:模块之间必须约定实体的顺序
算法共生性:模块之间必须约定算法
动态共生性包括

执行共生性:模块之间的执行顺序影响结果
时间共生性:多个模块的执行时间点影响结果。例如两个线程使用同一内存的同时执行
值共生生性:多个值必须同时更改。例如用四个顶点坐标来表示一个长方形,那么为了保持数据结构的完整性,就不能随意修改单独一个点的坐标
身份共生性:多个模块必须引用同一实体
代码重构时,要把差的共生关系改变成更好的共生关系

区域性
距离很远的模块有强共生性就意味着糟糕的耦合,而距离相近的代码具有共生性是可以的。

程度
共生的程度是指影响的规模。只是影响很少的类还是很多?假如你只有很少几个模块,那么有动态共生性也不是很可怕,但是,通常代码会随时间增长让问题越来越大

提升系统模块化的三个建议

通过把系统拆分成多个封装要素最小化整体共生性
最小化其他遗留的跨越封装边界的共生性
最大化封装边界内部的共生性
传奇的软件架构创新者Jim Weirich的两条建议:

影响法则:把影响大的共生性转化成弱的共生性
区域法则:软件要素之间的距离越远,越要使用更弱的共生性
以上是1990年代的共生性理论,它对于现代架构师面临的问题并没有给出解决方案