知识卡片
模块划分质量的可观测信号:规模超限、依赖过多,往往伴随低单元测试覆盖率
内容
“模块内高内聚、模块间低耦合”是大部分设计遵循的经典标准,但这个标准同样属于难以直接量化判断的原则性描述,需要一些具体、可操作的观测信号来落地。一个初步、简单可行的信号是代码长度:一个类的长度超过2000行、或者一个函数的长度超过两屏幕,都是值得警惕的危险信号,说明这个模块很可能承担了过多不相关的职责,没有被恰当地拆分。另一个能反映模块划分水平的信号是依赖关系:如果一个模块依赖了特别多其他模块,甚至出现了循环依赖(A依赖B、B又反过来依赖A),这通常说明作者对模块职责的规划不够清晰,未来维护这个工程时很可能出现”牵一发而动全身”的困境——改动一个模块,会不可预料地波及一大片依赖它或被它依赖的其他模块。现代IDE通常都提供了相应的分析工具(比如IDEA的Dependencies Analysis功能),可以帮助快速识别这类依赖关系是否过于复杂。更值得注意的是一条隐藏的关联规律:绝大多数情况下,不恰当的模块划分会同时伴随极低的单元测试覆盖率——因为一个高度耦合、职责混乱的复杂模块,天生就很难写单元测试(甚至有时候根本无法测试,因为要测试一个功能点,不得不同时准备一大堆和它耦合在一起的其他依赖),所以直接检查单元测试覆盖率,本身就是一个相当可靠的、判断模块划分质量的旁证指标——这条规律和[[用单元测试覆盖率作为异常处理质量的可操作代理指标]]共同揭示了一个更普遍的现象:单元测试覆盖率作为一个单一的可观测指标,实际上同时能间接反映出代码在异常处理和模块设计这两个完全不同维度上的质量水平,因为”容易测试”本身就是好设计的一个自然结果,而不是刻意为了测试才做的额外工作。
参考来源
- 位置:《高可用架构(第1卷)》第5章《运维保障》"5.6 系统运维之评价代码优劣的方法"节,"5.6.1 什么是好代码"(源文件:_epub-src/OEBPS/Text/Chapter5_6_2.xhtml)
- 结论依据:原文说明"一个类的长度大于2000行,或者一个函数的长度大于两屏幕都是比较危险的信号……如果一个模块依赖特别多,甚至出现了循环依赖,那么也可以反映出作者对模块的规划比较差……绝大部分情况下,不恰当的模块划分也会伴随着极低的单元测试覆盖率:复杂模块的单元测试是非常难写的,甚至是不可能完成的任务",直接支撑本卡片结论。
- 原始内容:一个类的长度大于2000行,或者一个函数的长度大于两屏幕都是比较危险的信号……绝大部分情况下,不恰当的模块划分也会伴随着极低的单元测试覆盖率:复杂模块的单元测试是非常难写的,甚至是不可能完成的任务。所以直接查看单元测试覆盖率也是一个比较靠谱的评价方式。