审查——用头文件验证依赖关系

审查(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),
审查判断依赖是否合理(本线)——
一个管「长什么样」,一个管「对不对」。