3.1 注释与文档:解释为什么而不是是什么


3.1 注释与文档:解释为什么而不是是什么

本节摘要:注释的价值在于解释代码表达不了的信息——设计动机、算法选择、陷阱与约束。本节划定该写与不该写注释的边界(解释为什么、复杂逻辑、公共接口、陷阱标记该写;复述代码、过时信息、注释掉的代码不该写),介绍文档注释的结构化格式与自动化文档生成,并给出 TODO 与 FIXME 标记的管理纪律。

本节导读

阅读完本节,你应当能够:

  1. 用"解释为什么而不是是什么"这条标准过滤一组现有注释
  2. 为公共函数编写包含功能、参数、返回值、异常的文档注释
  3. 说明过时注释比没有注释更危险的原因
  4. 正确使用 TODO、FIXME、HACK 三类标记并定期清理
  5. 说明为什么不该保留注释掉的代码

一、问题与直觉:两种失败注释

失败形态一:注释坟场。一个函数开头挂着三十行注释,仔细读发现描述的是两年前的版本,函数早已改得面目全非。读者比照注释理解代码,得出完全错误的预期——排查两小时后发现"注释是骗人的"。

失败形态二:噪音刷屏。几乎每行代码后面都跟着注释:i++; // i 加一count = 0; // 初始化计数器return result; // 返回结果。这些注释信息量为零,却占据了大量视觉空间,训练读者条件反射地跳过一切注释——于是真正的关键注释也被淹死了。

两种失败指向同一个根源:写注释前没有问"这条注释提供了代码本身提供不了的信息吗"。代码能表达的(这一行在做什么)不需要注释;代码不能表达的(为什么这么做、为什么不用显然的替代方案、这里有什么坑)才需要。这条分界线就是本节的核心。

还有一类历史遗留物要单独点名:注释掉的代码。以前版本控制不普及时,人们用注释"保留"旧实现以备回退。现在版本库记得每一次历史,注释掉的代码只是垃圾:它会随时间腐化(与新代码渐失关联)、误导读者("这是还在用的备选吗")、膨胀文件。正确做法是直接删除,需要时向版本历史找回。

二、核心原理:什么该写、怎么写

2.1 该写注释的五种场合

场合一:解释为什么。这是注释的本职。代码只能说"我在做什么",说不了"我为什么这么做"。典型如:

# 这里用链表而非常见动态数组: # 写日志场景下每毫秒都有插入,链表头插代价稳定 log_buffer = LinkedList()

没有这条注释,未来某个"优化者"看到链表会觉得落伍,换成动态数组,然后在写入高峰期收获性能毛刺。

场合二:复杂算法与业务规则。加密算法的位运算、定价规则的例外条款、为兼容历史数据而存在的特判——这些逻辑的正确性依赖背景知识,不注释等于给每个读者出考题。

场合三:公共接口的文档注释。模块、类、公共函数是给外部使用的,使用者不应被迫读实现。文档注释用固定格式说明功能、参数、返回值、可能抛出的异常,各语言都有对应惯例:Python 的文档字符串、Java 系的文档注释风格、脚本的类文档注释格式。示例(概念代码):

def calculate_days_between(start_date, end_date): """计算两个日期之间的天数差。 参数: start_date: 起始日期。 end_date: 结束日期。 返回: 天数差;起始晚于结束则为负数。 异常: 任一参数为空时抛出参数非法异常。 """

文档注释的最大红利是可机器提取——配套工具能把它们汇集成 API 文档,注释写一次,文档自动生成,永远与代码同处一地。

场合四:陷阱与特殊处理标记。TODO(待完成)、FIXME(已知缺陷待修)、HACK(临时方案欠重构)。它们是代码里的"欠条",让技术债务显性可见。

场合五:文件头与版权信息。开源与商业项目的法律要求,通常由工具自动添加。

2.2 注释的四条纪律

准确性:注释与代码必须同步。改代码不改注释,注释就从文档变成谎言,而谎言比空白更有害——空白只让读者困惑,谎言让读者自信地犯错。简洁性:注释是旁白不是论文,三行说不清的动机考虑先改代码结构。一致性:全项目统一注释风格(文档注释的标签、TODO 的写法),让注释本身可读。语言统一:团队约定一种语言写注释并坚持,中英混杂最伤扫读。

注释决策速查

场合 该不该写 示例 常见错误
设计动机 必写 为什么选链表不选数组 让读者猜
复杂算法 必写 位运算的等价含义 假设读者都懂
公共接口 必写 文档注释四要素 让使用者读实现
性能特例 必写 此处为热点才这样写 被后人"好心"重构
代码字面行为 不写 i 加一 纯噪音
过时描述 删除 描述旧版本的注释 误导读者
注释掉的代码 删除 历史保留心态 版本库可找回

💡 关键直觉:注释的 ROI 取决于"未来读者会在哪里卡住"。会在"为什么"上卡住的注释价值最高;在"是什么"上卡住说明命名或结构有问题——修代码,而不是加注释。

三、工程实践要点

3.1 用好 TODO 的生命周期

TODO 不是免责声明。规范用法包含三要素:事项说明(要做什么)、背景(为什么暂时不做)、责任人或关联任务号(找谁)。// TODO: 处理错误 是不合格的——处理什么错误、为什么现在没处理、谁负责?合格的写法形如 // TODO: 增加网络超时重试,当前版本先快速发布,任务编号 1024,负责人张三。团队要定期(如每次迭代尾声)盘点 TODO 存量:完成的清除、过期的更新、长期滞留的升级为正式技术债务任务。放任不管的 TODO 会繁殖到没人敢信的程度,最终整个标记体系报废。

3.2 自文档化优先

注释是补充手段,第一手段永远是让代码自己说话:好命名(第 2.2 节)、小函数(第 3.3 节)、常量代替魔术数字(第 3.4 节)。每当你想写"这行代码在做 X"的注释,先试试把 X 变成一个函数名或变量名。经验法则是:能用结构解决的不要用注释解决——结构不会过时,注释会。

⚠️ 常见坑:用注释给长函数分段("第一步校验、第二步计算……")却拒绝拆函数。注释分段是拆分的欠条——每段就该是一个函数,函数名就是那段注释。同理,大段"此函数修改时注意以下八点"的注释,往往说明函数复杂度已超标。

3.3 文档注释生成工具

主流生态都有文档提取工具,配置一次持续受益:写完文档注释,构建时自动产出可检索的 API 文档站点。这带来一个隐性约束——文档注释的格式必须严格符合工具的解析规则(标签拼写、缩进层级),格式错位的注释不会被收录,等于白写。团队应提供注释模板(编辑器片段),让四要素(功能、参数、返回、异常)成为肌肉记忆。

要点速记

  • 分界线:注释解释"为什么",代码表达"是什么";跨线的注释是噪音
  • 五种该写的场合:设计动机、复杂算法、公共接口、陷阱标记、版权头
  • 过时注释最危险:它让读者自信地犯错,改代码必须同步改注释
  • 注释掉的代码直接删:版本库是历史,代码里只留现在
  • TODO 三要素:事项、背景、责任人,定期盘点防繁殖
  • 自文档化优先:能用命名与结构解决的,不用注释解决

下一节把镜头拉远:单个文件之外,整个项目的布局该怎么安排。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U