审查——用头文件验证依赖关系
审查(Review)是工程控制的一种手段:在代码合入之前,检查它是否符合设计。依赖关系是审查的重点之一——而头文件是审查依赖关系最便宜的工具:不运行代码,看 include 关系就能验证「谁依赖谁」是否符合设计。这一条线:审查时怎么用头文件、能发现什么、不能发现什么。
一、审查依赖关系的目标
设计阶段定了依赖规则(谁能依赖谁),实现阶段要验证代码遵守了没有:
1 2 3 4 5 6 7
| 设计的依赖规则: 入口层 → 业务层 → 基础设施层(单向,不跨层) 业务系统 ← 入口系统;业务系统不依赖入口系统 A 依赖 B,B 不依赖 A(无环)
审查要验证的: 实际代码的依赖 == 设计的依赖?
|
审查依赖 = 对照「设计允许的依赖」检查「代码实际的依赖」。
二、用头文件审查:方法
头文件是依赖关系的静态表达(见依赖关系主题 04),审查时直接读它:
1 2 3 4 5
| 审查步骤: 1. 列出要审查模块的头文件包含关系 2. 画静态依赖图(谁 include 谁) 3. 对照设计的依赖规则 4. 标出违规:反向依赖、循环依赖、依赖泄漏、隐式依赖
|
1 2 3 4 5 6
| 实际包含关系: main.c → app.h → service.h → domain.h └──→ infra.h
设计规则:业务层不依赖基础设施层 发现违规:service.h 包含了 infra.h → 业务层直接依赖了基础设施
|
看头文件就够了——不需要读实现、不需要运行程序。
三、用头文件能发现什么
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ① 循环依赖 a.h ↔ b.h 互相包含 → 两个模块纠缠,无法单独编译/测试
② 反向依赖 底层模块包含上层模块的头文件 → 依赖方向反了,分层被破坏
③ 依赖泄漏 service.h 包含了 infra.h(实现细节) → 本应通过接口依赖,却直接依赖了实现
④ 隐式依赖 头文件没包含但用了符号(靠前向声明/运气编译过) → 依赖没被表达,构建顺序随时会断
⑤ 过度包含 头文件包含了一大堆用不到的头文件 → 编译变慢、依赖面被无谓扩大
|
每一种都是「乱做」(依赖混乱)的具体形态——审查就是工程控制里对「乱」的检查手段。
四、用头文件不能发现什么
1 2 3
| ❌ 运行期调用是否合理(调用频率、调用时机) ❌ 实例怎么传(注入关系对不对) ❌ 依赖是否必要(包含图看不出「这个包含其实没用」——要配合使用检查)
|
头文件审查回答「依赖结构对不对」,回答不了「依赖用得对不对」——后者要靠运行期验证和更细的代码审查。
五、和其他线的关系
1 2 3 4 5 6 7 8 9 10 11 12 13
| 审查(用头文件)←→ 工程控制(本主题 01) 审查 = 控制「乱做」的手段之一 头文件审查 = 依赖维度上的检查
审查(用头文件)←→ 过程与流程(本主题 02) 审查是流程里的一个检查点(任务 → 审查 → 修正 → 再验证)
审查(用头文件)←→ 依赖关系主题 头文件是依赖的静态表达(依赖主题 04)——审查的依据 依赖规则来自依赖方向/边界设计
审查(用头文件)←→ 文档组织(06-设计/04) 文档审查查结构/逻辑,头文件审查查代码依赖——同一件事的两个对象
|
收束
1 2 3 4 5 6 7 8 9 10 11
| 审查 = 对照设计的依赖规则,检查代码实际的依赖
用头文件审查(最便宜的方法): 读 include 关系 → 画静态依赖图 → 对照规则 → 标违规
能发现:循环依赖 / 反向依赖 / 依赖泄漏 / 隐式依赖 / 过度包含 不能发现:运行期调用合理性 / 注入关系 / 依赖是否必要
头文件给依赖事实(依赖主题 04), 审查判断依赖是否合理(本线)—— 一个管「长什么样」,一个管「对不对」。
|