注释写得越全,接手的人反而越慢

接手过老项目的人大多有类似体验:函数前面挂着二十行注释,读完更晕。更糟的是注释和代码已经对不上,你按注释去改,运行结果全不一样。

代码评审里经常听到一句要求:「注释覆盖率太低了」。这句话听起来很负责,实际上常常在制造负债。注释会过期,而过期的注释比没有注释更危险。

为什么注释天生容易腐烂

代码有编译器、有测试、有运行结果来检验,一旦写错,系统会立刻报错。注释没有任何机制检验它是否还正确,它只是躺在那里的一段自然语言,改代码的人顺手改它的动力几乎为零。

更麻烦的是,读代码的人默认注释是可信的。当一段注释说「这里最多重试三次」,而代码早已改成五次,后来者会照着注释做判断,排障方向直接跑偏。

一个真实的排障下午

某次线上超时告警,一位工程师花了两小时定位到重试逻辑。代码上方写着「失败后不再重试,直接返回错误」,他因此排除了重试风暴的可能,转去查网络。直到同事提醒,才发现重试已被改成指数退避,注释是两年前的版本。

这两小时的成本,源头就是那行已经过期的注释。过期的注释不是没用的信息,是错误的信息。

该写的是为什么,不是是什么

「把 i 加一」这种注释毫无价值,代码自己写得更清楚。真正值得写下来的是代码表达不了的东西:为什么选了这个看似绕的写法,为什么这里不能优化,这个阈值当初依据什么定下来的。

  • 业务约束:这个上限来自监管要求,不能按性能随意调整
  • 历史坑:这里有并发问题,加锁是为了绕开某个上游缺陷
  • 取舍理由:为了兼容旧客户端,暂时保留这一段兼容逻辑

这类信息无法从代码推断,写下来才有价值;反过来,能从代码读出来的,写下来只是噪音。

比写注释更有效的三条路

第一是改名字。把 doCheck 改成 hasUnpaidInvoice,多数注释当场失去存在必要。第二是拆函数,一段代码需要一个段落来说明它做了几件事,那它本来就应该拆成几个函数。第三是把决策写进提交信息和架构记录,而不是撒在代码里。

好的提交信息会随时间变成一份项目决策史,而注释只会变成一堆无人维护的旧报纸。重构的时候,把「为什么」从注释搬进提交记录,收益更持久。

评审时该问的问题

与其检查注释覆盖率,不如在评审时问三句:这段代码三个月后别人能看懂吗;注释描述的是做法还是原因;代码改过之后,哪条注释需要一起改。

把注释当成需要偿还的债,而不是需要达标的指标,团队读代码的时间会实实在在降下来。

标签:#, #