关于代码注释的争论,我站哪一边

作者:晚风信箱 发布时间: 2025-06-23 阅读量:46 评论数:0

组里为这件事吵过好几次。一方说好代码是自解释的,需要写注释说明恰恰证明代码写得不够清楚;另一方说没有注释的代码就是天书,半年后连作者自己都读不懂。

我两边都不站,因为我觉得这个争论从一开始就问错了问题——它把「注释」当成了一个东西,但注释其实至少有五种,价值天差地别。

第一种:解释代码在做什么

比如在一行自增语句上面写「计数器加一」。这类注释我百分之百支持删除,它没有增加任何信息,还要跟着代码一起维护。

但要小心一个变体:当一段代码很长很绕,有人在上面写了一段说明「这里在做什么」。这种时候删注释是不够的,该做的是把那段代码抽成一个函数,用注释里的话来命名它。注释是症状,不是病。

第二种:解释为什么这么做

这是我认为价值最高的一类,而且是代码无论如何都表达不出来的。

举个真实的例子。我们有段代码在两次调用之间加了 200 毫秒的等待,看起来完全多余。下面有一行注释,大意是某个上游系统在写入后有一小段窗口读不到最新数据,实测 150 毫秒内必然读不到,200 毫秒是留了余量,并写了对应的问题单编号。

后来有个新同事觉得这行等待影响性能,删掉了。上线后偶发查不到数据,排查了大半天。如果没有那行注释,我们连这个方向都想不到。有了它,回滚加恢复只用了十分钟——而且那个注释还告诉我们,正确的做法不是加等待,而是推动上游提供强一致的读接口。

第三种:解释为什么那么做

这一类被严重低估。当一段代码看起来应该用某个显而易见的方案,但作者没用,如果不写清楚,后来人一定会去改,然后重新踩一遍坑。

我现在写这种注释有个格式:试过什么、为什么不行、如果条件变了可以重新考虑。最后半句很重要,它给未来留了门,而不是一句死板的「不要改这里」。

第四种:警告

比如某个方法不是线程安全的、某个参数传空会有特殊语义、某个类被反射调用所以看起来没有引用但不能删。最后这个我删过一次,删完编译通过、测试通过、上线炸了。

第五种:待办标记

我对这一类的态度经历过反复。以前我觉得它是垃圾,因为绝大多数永远不会被做。后来我改成有条件地支持:必须带上人名和条件,比如「等某个依赖升级后可以去掉这段兼容逻辑」。不带任何上下文的待办标记,我在评审里会要求删掉或者写成正式的任务。

我统计过一次我们的仓库,一共 143 个待办标记,最老的一条是四年前的。这个数字本身就说明了问题。

我实际的做法

  • 写完一段代码,先问能不能通过改名字、拆函数、调结构把注释消掉。能消掉的,注释就是多余的。
  • 消不掉的,说明这里有代码之外的信息——外部系统的怪癖、业务上的历史约定、一次事故的教训、一个性能取舍。这些必须写下来,而且要写清楚来源。
  • 注释里带上可追溯的线索:问题单号、日期、决策文档的位置。光写结论,后来人无法判断这个结论是不是过期了。
  • 公开接口的文档注释单独算一类,那不是给读代码的人看的,是给调用的人看的,标准不一样,该写还得写。

最后一点私货

那些说「好代码不需要注释」的人,我发现有个共同点:他们大多在写业务逻辑相对简单、外部依赖比较干净的代码。而一旦你的代码要跟五个不受控的外部系统打交道、要兼容三个历史版本的数据格式,代码本身能表达的东西就到顶了。

代码能告诉你「是什么」,很难告诉你「为什么是这样而不是那样」。而在维护阶段,后一个问题才是让人卡住的那个。

评论