nuke-comments

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Nuke comments

注释清理

A comment costs attention on every read, and goes stale the moment the code moves. It earns that cost only by carrying what the code cannot.
每次阅读代码时,注释都会消耗注意力,而且代码一旦变更,注释就会过时。只有承载代码无法表达的信息时,注释才有存在的价值。

What a comment must earn

注释的留存标准

Four keepers, and nothing else:
  • Trap: library or framework behaviour that bites the next editor. "This Checkbox spreads external props over its own click handler, so an
    onClick
    here would replace the toggle rather than compose with it."
  • Contract: an invariant, a unit, or an order that the code does not show. "
    riskCells
    stays row-major; the heatmap rebuilds its axes from that order."
  • Directive: text the tooling reads, for example
    oxlint-disable
    ,
    eslint-disable
    ,
    use no memo
    ,
    @ts-expect-error
    ,
    @vitest-environment
    , or
    prettier-ignore
    . These are machinery, not prose. Keep every one, and shorten a long trailing rationale to a clause. The legal comment (
    /*!
    or
    @preserve
    ) marks a comment a human has exempted from a sweep, so keep it word for word. This one is enforced mechanically: esbuild keeps a legal comment in minified output, so
    verify-comments-only.sh
    reports a deleted one as
    CODE CHANGED
    .
  • Signpost: a single terse JSDoc line on a shared util, a hook, or a project-level abstraction. Also a section marker that names a real structural division a reader must navigate, for example a Dockerfile build stage, or the grouped blocks of a config file.
The test, applied to every comment: delete it, and ask whether a competent engineer could now plausibly break this code. If not, it was noise. Default to deleting.
A keeper that runs past two lines is usually a trap with a story wrapped around it. Keep the trap, and cut the story.
只有四类注释值得保留,其余一律删除:
  • 踩坑提示:库或框架中容易让后续开发者踩坑的行为。 “这个 Checkbox 会将外部 props 覆盖到自身的 click 处理函数上,因此此处的
    onClick
    会替换切换逻辑,而非与之合并。”
  • 契约说明:代码无法体现的不变量、单位或顺序约定。 “
    riskCells
    保持行优先顺序;热力图会基于该顺序重建坐标轴。”
  • 工具指令:供工具读取的文本,例如
    oxlint-disable
    、
    eslint-disable
    、
    use no memo
    、
    @ts-expect-error
    、
    @vitest-environment
    或
    prettier-ignore
    。 这些是机器指令而非说明文字,需全部保留,若后面跟了很长的说明理由,可精简为短句。 法定注释(
    /*!
    或
    @preserve
    )是人工标记为无需清理的注释,需逐字保留。 这一点是由工具强制保障的:esbuild 会在压缩输出中保留法定注释,因此
    verify-comments-only.sh
    会将删除法定注释的情况判定为
    CODE CHANGED
    。
  • 路标注释:在共享工具函数、Hook 或项目级抽象上的简短 JSDoc 单行说明。 也包括标记真实结构划分的区块标题,方便读者导航,例如 Dockerfile 的构建阶段、配置文件的分组块等。
判断每条注释的标准是:假设删掉它,问自己一个合格的工程师会不会因此有可能写出有问题的代码。 如果不会,那这条注释就是噪音。默认选择删除。
如果一条该保留的注释超过两行,通常是踩坑提示里夹杂了背景故事,保留核心提示内容,删掉无关的背景叙述。

Noise

无用注释类型

These are noise by construction, whatever they say:
  • Restating the line, the function name, or the type below it
  • A per-field description on a type where the field name already says it
  • A file-header essay, and a divider over a single logical unit or a section the code already labels
  • A design-doc or issue reference, for example
    #116
    , "matches the design", or "see inventory section 9"
  • Narration of mock and fixture data
  • Arrange, act, and assert steps, or a comment that restates the
    it(...)
    description
  • Commented-out code
  • Rationale for a decision nobody would question
When a comment exists to explain what the code does, the code is the problem. Rename or restructure, and the comment dissolves.
以下注释天生就是噪音,无论内容是什么:
  • 重复说明下方的代码行、函数名或类型
  • 类型中每个字段的说明,但字段名本身已经表达清楚含义
  • 文件头的长篇大论,以及单个逻辑单元或代码已有标记的区块上方的分割线注释
  • 设计文档或 issue 引用,例如
    #116
    、“与设计稿一致”或“参见库存部分第9节”
  • 对 mock 和 fixture 数据的叙述性说明
  • 测试的准备、执行、断言步骤说明,或是重复
    it(...)
    描述内容的注释
  • 被注释掉的代码
  • 对没人会质疑的决策的理由说明
如果一条注释的存在是为了解释代码做了什么,那问题出在代码本身。通过重命名或重构代码,就可以消除这类注释。

Writing code

编写代码时的原则

Apply the test as you write. The comment you never type is free, and the one you type gets deleted later by someone who pays to read it first.
写代码时就用上面的标准来判断。你没写出来的注释是零成本的,而你写了的注释,之后会被某个花时间读它的人删掉。

Sweeping a codebase

批量清理代码库注释

A sweep changes comments and whitespace only, so no code, logic, type, string, or JSX moves.
Asked to review rather than to sweep, for example a CI job or a pull request diff, edit nothing: classify each comment as a keeper or as noise, and report it.
  1. Establish green. Run the typecheck, lint, format check, unused-code check, and tests of the project, and record the result. Every later check compares against this, so a failure that is already there must be known now.
  2. Find the density. Rank the files by comment lines, to see where the weight sits. Exclude a generated file, for example
    *.gen.*
    or codegen output, because its generator rewrites it.
  3. Partition and fan out. Split by directory into scopes that do not overlap, and dispatch one subagent per scope, in a single message, so they run at the same time. Give each subagent its exact file scope, the four keepers, the noise list, the comments-and-whitespace-only rule, and the instruction to run the typecheck and the lint but not the test suite, because parallel agents that share a tree trip over each other's runs. Name the worst offender in a scope, so its owner condenses it rather than deletes it blindly.
  4. Verify, do not trust. A subagent reports its own diff, so confirm the claim yourself. Re-run the full baseline, then prove that the diff is comments only with the
    verify-comments-only.sh
    script beside this file:
    <this-skill-directory>/verify-comments-only.sh [base-ref]
    It minifies every changed file at the base ref and in the working tree and compares them. Identical output means the comments moved and the code did not. It reports two things it cannot judge, and both need your eyes: a type-only file, which erases to nothing, and a file that is not JS, for example HTML or Markdown. For those, diff the file and confirm that every
    +
    and
    -
    line is a comment or a blank line.
    Read the failures of the script, and not the exit code alone. A green run means something only when the tool really ran, because an esbuild call that errors prints nothing and compares empty output to empty output, which looks identical and proves nothing.
    Then audit the directives, which the minification cannot see, because it strips them as comments:
    git grep -c 'oxlint-disable\|eslint-disable\|@ts-expect-error\|vitest-environment\|use no memo\|@public\|@internal\|@beta\|@alias'
    Compare the counts against the base ref. A drop means a directive died, unless the lost hit was prose that only mentioned a directive inside a deleted essay, which is fine. Confirm which one it is before you move on.
    The last four belong to knip, when the project uses it: a JSDoc
    @public
    on an export that nothing else references is what keeps knip quiet about it, so a deleted comment turns a green unused-code check red.
  5. Report the numbers. Total comment lines before and after, the files touched, and the checks that passed. Name a few comments you kept on purpose and why, so the judgement is reviewable rather than a wall of deletions.
Done means: the baseline is green, the minified output is identical, and the directive counts reconcile.
批量清理只修改注释和空白字符,不能改动代码、逻辑、类型、字符串或 JSX。
如果是要求评审而非清理(例如 CI 任务或 PR 差异评审),不要做任何修改:只需将每条注释分类为留存或无用,并给出报告。
  1. 建立绿色基线 运行项目的类型检查、lint、格式检查、未使用代码检查和测试,记录结果。 后续所有检查都要和这个基线对比,因此必须先确认哪些问题是原本就存在的。
  2. 定位注释密集区 按注释行数对文件排序,找出注释最多的地方。 排除自动生成的文件,例如
    *.gen.*
    或 codegen 的输出,因为这些文件会由生成器重写。
  3. 拆分任务并行处理 按目录拆分为互不重叠的范围,在一条消息中为每个范围分配一个 subagent,使其并行运行。 告知每个 subagent 其负责的精确文件范围、四类留存注释、无用注释列表、仅修改注释和空白的规则,以及要求其运行类型检查和 lint,但不要运行测试套件——因为共享同一代码树的并行 Agent 会互相干扰运行。 指出每个范围内注释问题最严重的文件,让负责的 Agent 精简注释而非盲目删除。
  4. 验证而非轻信 subagent 会自行报告其修改的 diff,你需要亲自确认结果。 重新运行完整的基线检查,然后使用本文件旁的
    verify-comments-only.sh
    脚本证明 diff 仅涉及注释:
    <this-skill-directory>/verify-comments-only.sh [base-ref]
    该脚本会对 base 版本和工作区中每个变更的文件进行压缩,然后对比结果。输出一致说明只有注释被修改,代码没有变动。 脚本会报告两类无法判断的情况,都需要人工检查:一类是纯类型文件,压缩后会变成空内容;另一类是非 JS 文件,例如 HTML 或 Markdown。 对于这些文件,需要手动对比 diff,确认所有
    +
    和
    -
    行都是注释或空行。
    要查看脚本的具体失败信息,不能只看退出码。只有工具确实正常运行时,运行通过才有意义——因为 esbuild 调用出错时不会输出任何内容,会将空输出和空输出对比,结果看起来一致,但什么也证明不了。
    然后还要审计工具指令,因为压缩过程会将它们当作注释删掉,无法通过上面的对比检测到:
    git grep -c 'oxlint-disable\|eslint-disable\|@ts-expect-error\|vitest-environment\|use no memo\|@public\|@internal\|@beta\|@alias'
    将统计结果与 base ref 版本对比。数量减少说明有工具指令被删掉了,除非减少的只是被删除的大段注释中提及指令的文字,这种情况是没问题的。 在继续下一步前,要确认属于哪种情况。
    最后四个指令属于 knip(如果项目使用了 knip 的话):在没有被其他地方引用的导出上添加 JSDoc
    @public
    可以让 knip 不报错,因此如果删掉了这条注释,原本通过的未使用代码检查就会失败。
  5. 报告清理结果 包括清理前后的总注释行数、涉及的文件数、通过的检查项。 列举几条你特意保留的注释及其原因,这样评审者可以判断清理的合理性,而不是面对一堆删除记录。
完成标准:基线检查全绿、压缩输出一致、工具指令数量核对无误。