antfu-simplify
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSimplify Changes
简化变更
Review the current changes (PR branch or working tree) and cut them down to the smallest correct diff, the way a skilled developer would. The method is an ablation study: remove each piece, check whether anything that matters breaks, and keep only what earns its place.
Goal: clean, minimal code with the just-right abstraction, that is also robust (handles real edge cases) and universal (solves the general case, not only the one that triggered the change).
审查 当前变更(PR 分支或 working tree),并像资深开发者那样,将其缩减为最小且正确的 diff。所采用的方法是 ablation study:移除每个部分,检查任何重要行为是否会因此失效,只保留真正有存在价值的部分。
目标是编写简洁、最小化的代码,同时具备 恰到好处的抽象,并确保代码 健壮(能够处理真实的边缘情况)和 通用(解决一般问题,而非只解决触发本次变更的特定场景)。
Hard Rules
硬性规则
- Behavior stays the same. Simplify only. Do not add features, change public APIs, or fix unrelated issues. Report unrelated findings instead.
- Scope is the diff. Only touch code the change introduced or modified, plus code that must change to remove it. Do not refactor the surrounding codebase.
- Every removal is verified. Run the repo's tests, typecheck, and lint after each batch. If a check has no coverage for the removed piece, reason about it explicitly or keep it.
- Match the surrounding code's style, naming, and comment density.
- 行为保持不变。 只做简化。不要添加功能、修改公共 API 或修复无关问题;应单独报告无关发现。
- 范围限定于 diff。 只修改本次变更引入或修改的代码,以及为移除这些代码而必须修改的代码。不要重构周围的代码库。
- 每次删除都必须验证。 每批修改后运行代码库的 tests、typecheck 和 lint。如果某项检查未覆盖被删除的部分,应明确说明推理依据,否则保留该部分。
- 与周围代码的风格、命名和注释密度保持一致。
Workflow
工作流
- Get the diff. Pick the base: PR target branch merge base (), else
git merge-base HEAD origin/<default>for uncommitted work. Read the full diff and the files around it. Note the goal of the change in one sentence; it is the yardstick for everything below.git diff HEAD - Inventory the pieces. List each unit the diff adds: function, parameter, option, branch, type, file, dependency, abstraction layer, comment, test. See Ablation Study.
- Ablate. For each piece, try removing, inlining, or merging it. Decide keep or cut using Keep vs Cut.
- Apply the cuts in small steps. After each batch run focused checks (tests, typecheck, lint). Revert a cut that breaks behavior; that piece is now proven needed.
- Check the result. Re-read the final diff as a reviewer. Is each remaining line explained by the one-sentence goal? Is it still robust and general?
- Report. Show a short table of what was cut or kept and why, plus the diff size before and after (). Do not commit unless asked.
git diff --stat
- 获取 diff。 确定基准:优先使用 PR 目标分支的 merge base(),否则对于未提交的工作使用
git merge-base HEAD origin/<default>。阅读完整 diff 及其周边文件。用一句话概括本次变更的目标;将其作为后续所有判断的准绳。git diff HEAD - 盘点各个部分。 列出 diff 新增的每个单元:function、parameter、option、branch、type、file、dependency、abstraction layer、comment、test。参见 Ablation Study。
- 执行 ablation。 对每个部分,尝试移除、内联或合并。根据 保留还是删除 决定保留或删除。
- 小批量实施删减。 每批修改后运行针对性检查(tests、typecheck、lint)。如果某项删减破坏了行为,则撤销该删减;这表明该部分已被证明是必要的。
- 检查结果。 以 reviewer 的视角重新阅读最终 diff。剩余的每一行是否都能由前述一句话目标解释?代码是否仍然健壮且通用?
- 报告。 用简短表格说明删除了什么、保留了什么及其原因,同时展示修改前后的 diff 大小()。除非用户明确要求,否则不要提交。
git diff --stat
Ablation Study
Ablation Study
For every piece in the diff, ask: if I delete this, what concretely breaks?
| Piece | Ablation | Keep if |
|---|---|---|
| New function / helper | Inline it at the call site | Called from 2+ places, or the name explains a non-obvious step |
| Wrapper / abstraction layer | Call the underlying thing directly | It hides real complexity or a likely-to-change boundary |
| Parameter / option / config | Hardcode the only used value | A real caller needs a different value now |
| Type / interface / generic | Use the inferred or existing type | It is exported, or inference gives a worse or wrong type |
| Branch / guard / try-catch | Delete it and run tests | It guards a reachable case (real input, real failure), not an impossible one |
| New file / module | Merge it into its only consumer | It has multiple consumers or a distinct responsibility |
| Dependency | Replace with a few lines or an existing dep | It handles hard edge cases you would otherwise get wrong |
| Duplicate logic | Reuse an existing util in the repo | No equivalent exists (search first) |
| Comment | Delete it | It explains why (constraint, workaround, surprising choice), not what |
| Test | Remove it and see what is unprotected | It covers behavior or a regression nothing else covers |
| Changed lines unrelated to the goal | Revert them | Never keep drive-by edits |
对于 diff 中的每个部分,都应提出这个问题:如果我删除它,具体会出什么問題?
| 部分 | Ablation 方式 | 保留条件 |
|---|---|---|
| 新增 function / helper | 在调用处内联 | 有 2 个及以上调用方,或者名称解释了一个不明显的步骤 |
| Wrapper / abstraction layer | 直接调用底层实现 | 它隐藏了真实的复杂性,或隔离了一个可能变化的边界 |
| Parameter / option / config | 硬编码唯一使用的值 | 当前确有调用方需要传入不同的值 |
| Type / interface / generic | 使用推导出的类型或现有类型 | 它已导出,或者类型推导得到的类型更差或不正确 |
| Branch / guard / try-catch | 删除它并运行 tests | 它防护的是可触达的情况(真实输入、真实故障),而非不可能发生的情况 |
| New file / module | 合并到唯一使用方 | 它有多个使用方,或者承担独立职责 |
| Dependency | 用少量代码或现有依赖替代 | 它能处理否则容易处理错误的复杂边缘情况 |
| Duplicate logic | 复用仓库中的现有 util | 仓库中不存在等价实现(先搜索) |
| Comment | 删除 | 它解释的是 为什么(约束、变通方案、令人意外的选择),而不是 做什么 |
| Test | 删除它并查看哪些行为失去保护 | 它覆盖了其他测试无法覆盖的行为或回归问题 |
| 与目标无关的修改行 | 撤销 | 绝不保留顺带修改(drive-by edits) |
Keep vs Cut
保留还是删除
Cut when the piece is:
- Speculative: built for a future need nobody has (extra options, hooks, plugin points, "just in case" generics).
- Redundant: repeats what the language, framework, types, or an existing util already provides.
- Defensive against the impossible: null checks on values the types or callers guarantee, fallbacks that never run, catch blocks that swallow errors.
- Indirection without payoff: one-use helpers, pass-through wrappers, classes where a function works, factories that build one thing.
- Noise: commented-out code, narrating comments, unused imports and exports, formatting-only churn.
Keep (or even add) when the piece is:
- Robustness: handles real edge cases (empty input, concurrency, cleanup, cross-platform paths, error propagation with context).
- Universality: solves the general problem instead of special-casing the reported one. If the fix hardcodes a name, path, or value from the bug report, generalize it.
- Right-sized abstraction: the third repetition of something gets extracted; the first and second usually do not. A good abstraction removes more code than it adds.
If an abstraction is too small, merge; if a function does several unrelated things, split. The target is neither fewest lines nor most layers, it is the fewest concepts a reader must hold.
当某个部分具有以下特征时,应删除:
- 推测性:为无人需要的未来需求而构建(额外的 options、hooks、plugin points、“以防万一”的 generics)。
- 冗余:重复 language、framework、types 或现有 util 已经提供的能力。
- 防范不可能情况:对 types 或调用方保证不会出现的值进行 null checks、永不执行的 fallback,以及吞掉错误的 catch 块。
- 无收益的间接层:只使用一次的 helper、透传 wrapper、在 function 足够时仍使用 class,以及只构造一种对象的 factory。
- 噪声:注释掉的代码、叙述过程的 comments、未使用的 imports 和 exports,以及只涉及格式的改动。
当某个部分具有以下特征时,应保留(甚至可以添加):
- 健壮性: 处理真实的边缘情况(空输入、并发、资源清理、跨平台路径、带上下文的错误传播)。
- 通用性: 解决通用问题,而不是对报告中的问题进行特殊处理。如果修复方案硬编码了 bug report 中的 name、path 或 value,应将其泛化。
- 适中规模的抽象: 同一逻辑出现第三次时才提取;通常前两次不应提取。好的抽象所减少的代码应多于其新增的代码。
如果某个 abstraction 太小,则合并;如果某个 function 做了几件互不相关的事,则拆分。目标既不是行数最少,也不是层次最多,而是让读者需要记住的概念最少。
Smells to Look For
需要排查的坏味道
- A fix that patches the symptom at the call site instead of the cause.
- Special cases () where a general rule would cover them.
if (name === 'foo') - Two code paths that do the same thing with small differences; unify them.
- State, flags, or caches that can be derived from existing data.
- Long parameter lists or option bags where most values are never varied.
- Types duplicated by hand when they can be derived (,
typeof,ReturnType, utility types).Parameters - Hand-rolled utilities that the repo, runtime, or an existing dependency already has.
- Tests that assert implementation details or mirror the code line by line.
- 在调用处修补表象而非根因的修复。
- 特例(),而一条通用规则本可覆盖这些情况。
if (name === 'foo') - 两条只有细微差异却执行相同任务的 code paths;应将其统一。
- 可以从现有数据推导出的 state、flags 或 caches。
- 冗长的 parameter 列表或 option bags,其中大多数 values 从未被改变。
- 手工重复定义本可推导出的 types(、
typeof、ReturnType、utility types)。Parameters - 手写的 utils,而 repository、runtime 或现有 dependency 已经提供了同类能力。
- 断言实现细节或逐行镜像代码的 tests。
Report Format
报告格式
md
| # | Piece | Action | Why |
|---|-------|--------|-----|
| 1 | `parseOptions()` in src/cli.ts | inlined | one caller, 3 lines |
| 2 | `retry` option | removed | no caller passes it; default is enough |
| 3 | `try/catch` in fetchData | kept | network errors reach users; test covers it |
Diff: +142 -8 -> +61 -8. Tests, typecheck, lint pass.List anything noticed but out of scope (unrelated bugs, wider refactors) separately, and leave it alone.
md
| # | Piece | Action | Why |
|---|-------|--------|-----|
| 1 | `parseOptions()` in src/cli.ts | inlined | one caller, 3 lines |
| 2 | `retry` option | removed | no caller passes it; default is enough |
| 3 | `try/catch` in fetchData | kept | network errors reach users; test covers it |
Diff: +142 -8 -> +61 -8. Tests, typecheck, lint pass.另行列出发现但不在范围内的问题(无关 bugs、范围更大的 refactors),不要对这些内容进行修改。