第4章:模块内聚性评估方法
4.1 边界定义与评估目标
模块内聚性评估的核心是量化模块内部元素之间的关联强度,以及模块对外部依赖的合理程度。本章聚焦三种互补的评估方法:扇入扇出分析、依赖审计、变更影响面。它们从结构、依赖、动态变化三个维度揭示模块的内聚质量。
| 评估维度 | 关注点 | 典型指标 |
|---|---|---|
| 扇入扇出分析 | 模块的调用入口数与出口数 | Fan-in > 3 且 Fan-out < 7 为健康 |
| 依赖审计 | 模块实际依赖与架构层级的合规性 | 逆向依赖数、循环依赖环 |
| 变更影响面 | 模块修改后波及的编译/运行时范围 | 影响模块数、重编时间增量 |
4.2 分层模型:三级评估体系
将三种方法融入三层评估结构,由浅入深排查内聚问题:
- 第一层(结构层):基于静态代码扫描,计算每个模块的扇入(被调用次数)与扇出(对外调用次数)。扇入高表明模块被广泛复用,扇出高则暗示功能过于分散。
- 第二层(依赖层):通过依赖审计工具(如 Gradle dependencies、JDepend)生成模块依赖图,标记所有跨越架构层级的逆向依赖与循环依赖。
- 第三层(动态层):记录模块变更后,通过编译耗时、测试覆盖、Git 提交关联度等数据,量化变更影响面。
典型模式:
# 扇入/扇出检查示例(假设使用 ClassyShark 或自定义脚本)
模块A: Fan-in=5, Fan-out=2 → 高内聚
模块B: Fan-in=1, Fan-out=12 → 低内聚,需重构
模块C: Fan-in=8, Fan-out=1 → 数据聚合器,内聚中等
4.3 组件职责与数据流
每个评估方法对应一个专门的评估组件,数据流如下:
- 扇入扇出分析器:读取编译后类图,统计每个模块对外部包的所有引用,生成结构化指标。
- 依赖审计器:基于模块间引用关系,自动检测逆向依赖(如业务层依赖数据层)和循环依赖,输出违规清单。
- 变更影响面计算器:结合 Git 提交历史和构建缓存,计算每次模块修改后必须重新编译的模块集合。
4.4 数据流 / 控制流 / 信任链路
评估方法之间的数据流向保证了诊断的连贯性:
- 数据流:静态代码分析结果 → 扇入扇出矩阵 → 输入依赖审计,过滤出高扇出模块;依赖审计报告 → 输入变更影响面计算器,确定高风险模块的波及范围。
- 控制流:每个评估阶段可独立触发,但推荐流水线执行:扇入扇出 -> 依赖审计 -> 变更影响面,前一阶段的结果可作为后一阶段的参数。
- 信任链路:工具生成的原始数据需经过人工复核(如排除框架自动生成的代码),评估结果应通过架构评审会确认,避免自动化误判。
4.5 选型权衡
| 评估方法 | 优势 | 局限 | 适用场景 |
|---|---|---|---|
| 扇入扇出分析 | 快速识别“上帝类”与“贫血模块” | 忽略动态调用与反射 | 单体拆解、模块边界初判 |
| 依赖审计 | 准确发现模块间违规依赖 | 对多语言混合项目支持有限 | 架构治理、合规检查 |
| 变更影响面 | 直接反映重构成本与风险 | 依赖历史数据积累 | 模块重构决策、回滚策略 |
风险提示:变更影响面评估必须结合 编译缓存失效规则,否则可能因增量编译精准度不足而误判。建议在 CI 流程中使用 Gradle 的 --scan 参数记录模块级编译时间。
4.6 落地步骤
- 数据采集:在 CI 流水线中加入自定义 Gradle 插件,每 PR 自动计算各模块扇入扇出并输出 JSON 报告。
- 阈值设定:根据团队历史基线设定健康阈值(推荐 Fan-in ≥ 2 且 Fan-out ≤ 6)。
- 依赖审计规则配置:定义架构层级规则(如 :core:network 不能依赖 :feature:login),写入
.detekt或自定义 checkstyle。 - 变更影响面建模:通过 Gradle Task 依赖图与 Git 文件差异,生成每次提交的影响模块列表。
- 自动化告警:当评估结果超出阈值时,在 MR 评论区或 Slack 发送告警,并附带重构建议。
// 示例:Gradle 插件中获取模块扇出
project.afterEvaluate {
project.tasks.register("computeFanOut") {
doLast {
val deps = project.configurations.getByName("implementation").dependencies
val fanOut = deps.size
println("${project.name} fan-out: $fanOut")
if (fanOut > 8) {
throw GradleException("Fan-out exceeds limit in ${project.name}")
}
}
}
}
4.7 验收标准
- 所有模块的扇出 ≤ 8(可配置,首次设为 10 逐步收紧)。
- 依赖审计报告中的逆向依赖与循环依赖数量归零。
- 每次模块变更引起的重编译模块数不超过该模块直接依赖数量的 1.5 倍(排除公共基础模块)。
- 评估结果可在 CI 日志中追溯,并提供可读的 HTML 或 Markdown 摘要。
最佳实践:在模块化初期优先使用扇入扇出分析快速劣化模块,中期加入依赖审计治理架构,最后引入变更影响面度量重构收益。三个方法形成闭环,持续保障模块内聚性。