关于 code-comments
一份语言无关的代码注释指南,说明如何保留、精简或删除注释。帮助开发者留下代码本身无法表达的理由与约束,同时减少重复和过时内容。
主要功能
- 01仅保留代码无法表达的信息
- 02删除重复或过时的注释
- 03重构由注释辩护的代码
- 04将长注释精简为关键理由
- 05检查文档块与注释位置
适用场景
- 01清理现有文件中的注释
- 02在代码改动时审查注释
- 03使注释符合项目惯例
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ basmilius/ skills --skill code-comments安装后在 Claude Code 中输入/code-comments确认已加载。
详细介绍
代码注释
注释不会参与编译,也没有测试覆盖注释,因此注释会逐渐偏离代码,并在多个文件中不断增多。只保留那些能传达代码本身无法表达的信息。删掉其余注释。
与语言无关:这些规则同样适用于 //、#、/* */、``、文档字符串、PHPDoc 和 JSDoc。如果项目的 CLAUDE.md / AGENTS.md 与此处规则冲突,则以项目文件为准;周边文件中已有的惯例也同样优先。
1. 判断标准
先写代码。然后以一个从未看过这段代码的人的视角重新阅读。只有当你无法从代码本身推断出某些信息时,才添加注释。
注释只有在传达以下信息之一时才有保留价值:
- 代码中看不出来的原因。 为什么采用这种方案,而不是显而易见的方案。
- 文件之外的约束。 返回哨兵值的 API、按大小写不敏感方式排序的列,或不附带基础 CSS 的库。
- 有意做出的偏离。 某段代码看起来有误,但了解故障原因后便会明白。
- 边界。 这个函数负责清理数据;这次比较有意采用恒定时间。
- 来源指引。 规范中的段落、需要匹配的旧行为,或已跟踪工作的议题编号。
其他注释一律删除。代码已经说明了它的作用。
// A node id in this set is collapsed; its children are dropped from the rows.
const collapsed = reactive(new Set<number>());
名称说明了它,类型说明了它,用法也说明了它。删除这一行。
2. 如果注释在为代码辩护,就修复代码
如果一段注释需要一整段文字来解释为什么代码可以接受,那它反映的是问题,而不是在记录问题。提取一个命名函数、重命名变量,或拆分分支。困惑消除后,注释也就不再需要。
同样,逐句叙述代码块内容的注释也应如此。放在二十行代码前的 // Build the rows, then sort them,意味着应该把代码拆成两个分别以这些名称命名的函数。
3. 看到就删的注释
复述下一行。 注释和代码说的是同一件事,因此其中一方就是免费的维护负担。
列出正下方的内容。 数据类上的文档块如果列出其字段(“标识、日期范围、是否已归档”),就是在重复下面十行处的属性列表;只要新增字段,它就会过时。
函数内部的分节标题。 // --- validation --- 标出了一处本该改为函数调用的分界。
注释掉的代码。 版本控制会保留它。把它删掉,也包括它遗留下来的空 try { /* ... */ } catch {}。
已经过时的注释。 移动或重新排序代码时,上方的注释往往会留在原处,结果解释起了旁边的新代码。核对注释所述内容与其下方实际代码是否一致。如果注释适用于别处,就把它移过去;如果所指内容已不存在,就删除注释。
五个文件中重复的同一段内容。 被复制的模板注释会让人不再阅读。将每处精简为一行,或把它集中移到所描述的共享对象旁。
4. 精简长注释
大多数长注释都只是一个原因加上对它的重复说明。保留原因。
删掉由原因直接推导出的结果。删掉从未考虑过的替代方案。删掉改述第一句的第二句。删掉修饰词。
// Rounded to roughly ten meters: two people in the same street share a range, and
// a rounding difference should not cost another request. The rounded position is
// what gets measured as well, so the polygon under a key is the one that key
// describes rather than whoever asked for it first.
改为
// Rounded to roughly ten meters, so two people in the same street share a range. The
// rounded position is measured as well, so a key describes the polygon under it.
保留两句有实质作用的话:为什么要舍入,以及为什么测量的也是舍入后的值。
尽量只写一行。只有在第二句传达了第一句没有的信息时,才写两行。只有在涉及真正独立的问题时,才另起一段,例如当前代码必须继续匹配的历史列。
5. 文档块
如果项目会为每个类和函数编写文档(PHPDoc、JSDoc、文档字符串),就遵循这一惯例。保留文档块,并保持简短。
描述要说明名称无法表达的内容。 用一两句话说明这个东西的用途,以及调用方需要了解什么。如果它只是把名称扩写成一个句子,那么删掉描述会更好。
标签承载类型和名称,而非说明文字。 @param int $limit 已经足够完整。只有当说明文字能提供签名无法表达的信息时才添加,例如单位、格式、领域术语、null 的含义或可接受范围。
@param int $requestId // nothing to add
@param string $date Date in `Y-m-d` format.
@param int|null $branchId Narrows to this branch and everything below it.
@param float $wtf The werktijdfactor, not the raw stored integer.
数组和对象的形状值得占用篇幅。 @return array{items: Row[], total: int} 或带类型的泛型,都胜过用句子描述同样的结构。
不要描述调用方的环境。 哪个屏幕会调用这个函数、它支撑哪个选项卡、哪个版本添加了它:这些信息在重构后都不会保留。直接说明其行为。
6. 始终保留的内容
- **待办事项和备注,**需注明负责人和条件:
// todo(Bas): drop this once frontend 1.0 is gone.没有负责人或触发条件的待办事项,只会成为永远无法解决的注释。 - **许可证和版权声明,**如果项目有使用。
- 安全边界。 说明为什么比较要采用恒定时间,或为什么要在这里而非调用处转义某个值。
- **变通方案,**需注明解除方案的版本或条件。
Node < 20、until the API returns a proper status。 - 外部引用。 规范段落、CAO 或法规条款、供应商特有行为、上游问题链接。
- **有意保持的旧版行为,**包括已不存在的列或端点。没人能从代码中推断出这些信息。
7. 位置和语言
将注释放在所解释内容的正上方,并保持相同缩进。位于一组声明上方的注释应适用于整组声明;如果它只针对其中一项,就将它移到那一项上方。
注释应使用代码库已有的语言,并遵循相应的拼写惯例。注释的详略也应与周围内容一致:一个没有注释的文件,也是在表达其代码需要多少说明。
8. 审查现有文件
先读注释,再读代码,并逐条自问:如果是现在,你还会写这条注释吗?以下三轮检查可以发现大多数问题:
- 下一行是否已经表达了同样的内容?删除。
- 这条注释是否与下一行有关?移动或删除。
- 能否用一半的字数表达这个理由?精简。
对于注释很多的文件,删掉三分之一到一半的注释行是很常见的结果。如果一条都没删,要么文件本来就很精炼,要么检查时不够坦诚。
相关技能
unslop- 将同样的思路用于文字:删掉填充内容,保留重点。- 仓库的
CLAUDE.md/AGENTS.md- 项目关于注释语言、文档块要求和文件头约定的规则;这些规则优先于本文的默认要求。