首页/开发/代码质量与评审速查/手法:Introduce Assertion(引入断言)
重构手法62 条

手法:Introduce Assertion(引入断言)

用断言显式化代码所依赖的前提:断言是团队对调用契约的记录,帮助快速定位违反点;生产环境注意断言开关(如 Java -ea)与替代方案(抛异常)。

是什么

引入断言把代码内部依赖的前提条件与不变量显式写成断言:断言是团队对调用契约与实现假设的记录,能让违反点在发生处立即暴露,而不是把错误状态带到更远的地方。它与对外部输入的校验是两件事——外部输入必须始终校验并做错误处理,断言只用于描述代码内部认为不可能出现的情况。

作用与区别

作用把前提与不变量显式化,违反时快速失败
对内对内部假设使用断言,表达不允许出现的情况
对外对外部输入使用校验与错误处理,不能只靠断言
运行开关部分语言的断言默认关闭,需要显式启用

典型使用场景

  • 循环不变量:明确指出循环过程中始终保持成立的条件,便于后续修改时自查
  • 参数前提:内部函数约定参数取值区间,违反说明调用方有缺陷
  • 状态迁移:方法调用前必须处于某个状态,断言可以在开发阶段立即发现误用
  • 算法中间结果:对关键的中间计算做断言,帮助定位逻辑走偏的位置
  • 重构保护:拆分复杂逻辑时用断言固定原有假设,避免拆分过程改变行为

示例

示例
# Java:断言表达式与提示信息
assert discount >= 0 && discount <= 1 : "discount out of range";

# Python:断言条件与消息
assert total >= 0, "total must be non-negative"

# 注意:断言只用于内部假设;外部输入必须先做校验

断言与校验对照

场景手段失败时的处理
用户输入格式错误参数校验返回明确错误信息
外部接口返回异常结构校验并容错记录日志并按策略降级
内部函数假设参数非空断言开发与测试阶段立即失败
状态机迁移前置条件断言或状态检查开发阶段暴露误用;生产可转为显式异常
业务规则约束校验并返回错误属于正常业务分支,不能只写断言
不要把断言当生产校验手段:部分语言与运行时默认关闭断言,代码一旦在关闭状态下运行,所有检查都被静默跳过。对外部输入必须使用校验与错误处理。
断言的表达式不应包含副作用:断言被关闭时,表达式根本不会求值,副作用会随之消失,这类缺陷在开发环境完全看不出来。

落地检查清单

  • 断言表达式无副作用,关闭时行为不受影响
  • 内部假设用断言,外部输入用校验
  • 断言消息说明期望条件,便于快速定位
  • 运行环境是否正确开启断言有明确说明

易错点

  • 断言写副作用表达式:断言关闭时逻辑静默丢失,问题在开发环境完全看不出来
  • 对外部输入只写断言不校验:生产环境断言关闭后没有任何防护,输入错误直达业务逻辑
  • 把业务约束写成断言:正常的业务分支被当成缺陷处理,断言一关就失去约束
  • 断言消息过于笼统:失败时只看到条件不成立,无法判断是哪个调用方违反了前提

数据来源与参考

  • 《重构》第 2 版 · 第 10 章(Introduce Assertion)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌