Formal Code Diagnostics
用形式化诊断谓词替代直觉——让审计可复现。
代码审查通常依赖个人直觉和经验。问题在于:直觉不可复现,不可传授,不可自动化。
形式化诊断将审计转化为对谓词的求值——每个诊断有精确的数学定义,对同一代码的审计结论一致。
诊断谓词是对代码元素(类型或函数)的布尔判定函数。
| 谓词 |
定义 |
含义 |
| $\text{WrongTier}(x)$ |
$\text{tier}(x) \ne \text{natural_tier}(x)$ |
类型在错误的抽象层级 |
| $\text{Leak}(x)$ |
$\sigma(x) = ◆ \wedge \text{visible}(x)$ |
内部实现泄露到公开表面 |
| $\text{DRY}(f, g)$ |
$f \cong g \wedge f \ne g$ |
同构代码重复 |
| $\text{Partial}(f)$ |
$f: A \rightharpoonup B \wedge \exists f': A \to B$ |
可全函数化的偏函数 |
| $\text{VerticalBloat}(T)$ |
$\exists m \in T : m\ \text{默认返回 NotSupported}$ |
接口包含非普适方法 |
| $\text{DeadCode}(x)$ |
$\nexists \text{path}(\text{root}, x)$ |
无可达路径的死代码 |
| $\text{SemanticAmbiguity}(x)$ |
$\lvert\text{interpretations}(x)\rvert > 1$ |
同一表示有多种互不兼容的语义 |
-
$\text{Leak}(x) \implies \text{WrongTier}(x)$——泄露一定意味着层级错误
-
$\text{DeadCode}(x) \implies \neg\text{Leak}(x)$——不可达的代码不可能泄露
| 级别 |
触发条件 |
行动 |
| SEVERE |
$\text{WrongTier} \vee \text{Leak}$ |
必须立即修复——结构性缺陷 |
| MEDIUM |
$\text{DRY} \vee \text{Partial}$ |
应当修复——代码质量问题 |
| LOW |
$\text{VerticalBloat} \vee \text{SemanticAmbiguity}$ |
记录并计划——设计改进空间 |
| INFO |
无违规但可优化 |
知悉即可 |
对任意代码库,依次执行:
对每个类型 $T$:写出代数形式 $T = \ldots$,标注层级 $\text{Tier}_n$,标注特异性 $\sigma(T)$。
示例:
$$\text{Config} = \text{Name} \times \text{Timeout} \times \text{RetryCount}$$
$$\text{tier}(\text{Config}) = \text{Tier}_1,\quad \sigma(\text{Config}) = ★$$
对每个函数/方法 $f$:写出签名 $f : A \to B$,验证全性,验证层级。
示例:
$$\text{resolve} : \text{Intent} \to \text{Result}(\text{Target}, \text{Error})$$
$\text{resolve}$ 是全函数 ✓,$\text{tier} = \text{Tier}_3$ ✓
对每个 $(T, f)$ 执行 §1 的全部诊断谓词,记录所有命中。
$$\text{物理路径}(x) \cong \text{逻辑路径}(x)$$
文件目录结构必须与类型代数层级一致。路径即文档。
触发谓词:$\text{Partial}(f)$
信号:函数体中出现 panic!、unreachable!、或 todo! 处理"不应该发生"的情况。
修正:扩展输入的和类型以覆盖所有情况,或收窄函数的定义域以排除非法输入。
触发谓词:$\text{VerticalBloat}(T)$
信号:接口中某些方法的默认实现返回"不支持"。
修正:将非普适方法提取为独立接口。
$$\text{Fat Interface} \to \text{Core Interface} + \text{Extension Interface}$$
只有真正需要扩展能力的实现者才实现扩展接口。
触发谓词:$\text{Leak}(x)$
信号:内部实现类型出现在公开 API 签名中,或用户代码直接构造内部类型。
修正:
- 降低类型可见性
- 引入工厂方法或 Builder 模式
- 使用不透明类型(
impl Trait 等)
触发谓词:$\text{DRY}(f, g)$
信号:N 个函数骨架相同,仅在类型参数或少量值上不同。
修正:
- 差异在类型 → 泛型参数
- 差异在值 → 函数参数
- 差异在行为 → 接口方法
- 禁止"文本级复制"代替"代数级抽象"
每次审计产出标准化报告:
| # | 严重性 | 发现 | 谓词 | 修正方向 |
|---|--------|------|------|----------|
| 1 | SEVERE | ... | WrongTier | ... |
| 2 | MEDIUM | ... | DRY(f, g) | ... |
$$\text{健康度} = 1 - \frac{|\text{SEVERE}| \cdot 4 + |\text{MEDIUM}| \cdot 2 + |\text{LOW}|}{|\text{总元素}| \cdot 4}$$
$$|★| \leq |●| + |○| \implies \text{框架吸收了足够的复杂性} \checkmark$$
诊断是重构的前置分析。重构不应该从"感觉哪里不对"开始,而应该从诊断报告的 SEVERE 项开始。
$$\text{审计} \xrightarrow{\text{诊断谓词}} \text{诊断报告} \xrightarrow{\text{按严重性}} \text{重构优先级} \xrightarrow{\text{手术}} \text{修复}$$
这确保了重构是有目标的手术,而非无方向的重写。