防御性编程是一种过度设计吗  

目录
  1. 防御性编程的必要性
  2. 一次性能问题的教训
  3. 防御性编程的适用边界
  4. 适度才是关键

防御性编程要求开发者在编写代码时考虑各种异常情况,为程序添加额外的保护层。争议在于:这是理性设计,还是过度设计?

我的结论是:取决于你在哪个层面做防御。

防御性编程的必要性

防御性编程不是给代码打补丁,而是降低系统整体的复杂度。

以文件读取为例:

普通写法:打开文件 → 读取
防御写法:检查文件存在 → 检查权限 → 检查编码 → 打开 → 读取

表面看,防御写法代码行数更多。但如果不防御,文件不存在时程序崩溃,后续所有依赖这个文件数据的操作全部失效。单点故障通过异常传播污染整个系统。

防御性编程把运行时崩溃转变为可预期的错误处理。代价是代码更长,收益是系统边界更清晰。

一次性能问题的教训

我曾花了两周排查一个文件读写系统的性能问题。

根因:文件不存在时程序抛异常,异常捕获后再重试,这个重试逻辑没有 timeout。每次文件操作失败都会触发一次指数退避重试,导致某些节点上的操作延迟增加了三倍。

修复方法很简单:加上 timeout 判断,提前结束无效等待。但这个问题的根源是最初没有做边界条件防御。

教训:防御性编程省下来的,是未来排查问题的深夜。

防御性编程的适用边界

过度的防御性编程确实存在。

过度场景:在一个内部工具里给每一个函数参数做类型检查和范围验证,写了两百行 Guard Clause 来防住永远不会被触发的异常输入。

判断标准:防御的成本是否低于不防御的期望损失。

  • 公开 API 的输入:必须防御。攻击面未知。

  • 内部函数的参数:信任调用方,过度防御是浪费。

  • IO 操作(文件、网络、数据库):必须防御。外部环境永远不可控。

适度才是关键

防御性编程是一把尺子。量得准,它是保险;量过头,它是债务。

好的防御性编程发生在系统边界,不发生在核心逻辑内部。把防御层做薄,把业务逻辑做厚——这是值得追求的架构倾向。

44.9k