教程 / 技巧与窍门 / 精简改动代码
📝 文字 ● 中级 更新于 2026-05-19

使用 /simplify 精简改动代码

能编译、能通过测试、符合需求的 diff,仍然可能比它应有的长度多出一倍——遗漏了复用机会、过度抽象、为不可能出现的情况添加防御性代码。/simplify 是一个专注的代码审查环节,能准确指出这些具体的代码异味并重写它们。在代码审查之前运行它,而不是之后。

"完成"与"精简"是两个不同的标准

0

当 Agent 完成一个功能时,自然的停止条件是"测试通过,功能正常"。这是功能性标准。而质量标准——精简、符合惯用写法、没有冗余——通常不会被检查。

这种情况在足够多的项目中反复出现,已成为一种规律:

  • 新建了一个辅助函数,但三个目录之外已经存在相同的工具函数。
  • 为只有一个调用方的问题建立了四层抽象。
  • 对调用方的类型系统已经排除的输入添加了 guard 子句。
  • 没人要求的配置开关。
  • 注释逐行解释下一行代码的内容——用英语,比读代码还慢。

/simplify 是一个独立的代码审查环节,专门针对这些常见问题提供检查清单。它读取 diff,按类别指出问题所在,然后直接重写或提出重写方案供你审批。把它当作工作流中的一个步骤,而不是可选的润色。

何时运行

1

最佳时机是"测试通过"之后、"提交 PR"之前。太早运行,你在精简的是还在变动中的代码;太晚运行,代码异味已经进入审查,让审查者来发现它们。

  • LingCode 完成功能之后——在提交前对工作区运行它。
  • 手写改动之后——你自己的 diff 也在检查范围内。这个技能不在意是谁写的代码。
  • 请求代码审查之前——在根源处消除"这段代码太长了"的评论。
不要对你不负责的代码运行 /simplify。在别人的分支上精简他们的 PR,是制造 200 行合并冲突的好方法。只对你自己的改动运行它。

它实际检查什么

2

/simplify 按优先级顺序审查的五个类别:

  • 复用。这次 diff 是否添加了代码库其他地方已存在的函数?LingCode 在接受新的辅助函数之前会搜索相似的结构。
  • 过度抽象。是否存在只有一个实现的协议/接口、只有一个产品的工厂、只有一个具体类型的泛型?内联它。
  • 对不可能输入的防御性代码。对非可选类型的 null 检查。对无符号整数的 if (count < 0)。什么都没加的 catch-and-rethrow。删掉。
  • 死分支和未使用的参数。"以后可能会用到"但没有调用方传递的参数。永远无法到达的错误情况。
  • 叙述代码的注释。// increment counter 写在 counter += 1 上方是噪音;// rate-limited to 5/s by upstream 才是有价值的信息。保留第二种,删掉第一种。

如何运行

3

在 LingCode 对话框中输入:

/simplify

不带参数时,它的范围是当前未提交的改动(git diff HEAD)。LingCode 读取 diff,运行检查清单,并生成一份结构化报告。

明确指定范围:

# Just one file.
/simplify Sources/Auth/LoginViewModel.swift

# A range of commits — useful before a force-push.
/simplify since main

# A specific PR-shaped scope.
/simplify HEAD~3..HEAD

报告以按类别分组的问题列表形式返回,每条问题都附有文件/行号引用和建议的重写方案。没有把握的重写会被标记为"考虑"而非"修复"。

典型报告示例

4

经过格式整理,内容贴近实际:

### Reuse (1)
- LoginViewModel.swift:42 — added formatPhoneNumber(). The same
  function exists at Utilities/PhoneFormatter.swift:18 and is
  already imported in this file. Replace the local helper with a
  call to PhoneFormatter.format(_:).

### Over-abstraction (2)
- AuthService.swift:8 — protocol AuthProviding has one conformer
  (RealAuthService) and is only injected in one place. Inline:
  delete the protocol, depend on RealAuthService directly. Re-add
  the protocol if and when a second conformer arrives.
- LoginCoordinator.swift:30 — generic NavigationDestination<T>
  is instantiated only as NavigationDestination<LoginRoute>.
  Specialize to NavigationDestinationLogin.

### Defensive code (1)
- LoginViewModel.swift:67 — guard let email = email else { ... }
  where `email` is typed `String` (non-optional). The branch is
  unreachable. Delete.

### Consider (1)
- AuthService.swift:55 — three-argument `login(email:password:
  remember:)` defaults `remember = false` and no caller passes
  `true`. Consider dropping the parameter, re-adding when needed.

Apply fixes? [y/N]

分类区分了"显然应该删除"的问题和"需要判断"的问题。"考虑"部分是你可以提出异议的地方;其余部分通常可以安全应用。

应用修复

5

回答 y,LingCode 将重写相关文件。标准的"验证后再声明完成"流程随即启动:它在改动后重新运行测试套件,并在结果中报告测试状态。

如果某个修复导致测试失败,LingCode 会还原该修复并告知你哪条问题是不安全的。其余修复保持应用。最终你得到的是干净精简的 diff。

提交前先审查重写结果。/simplify 是基于判断的机械模式匹配——通常是对的,有时会过于激进。快速浏览一下最终的 diff;你不必接受每一处重写。

它不做什么

6

值得了解的边界:

  • 不改变行为。问题都是关于代码结构的,而非代码是否做了正确的事。这方面请使用代码审查
  • 不优化性能。技能描述中的"效率"是指"没有明显的无用功"——重复调用、死分支——而非微优化。热点路径仍然需要性能分析。
  • 不重写只是按你口味显得冗长的正常代码。如果一个 30 行的函数读起来很清晰,没有复用/抽象/防御性问题,/simplify 会忽略它。风格偏好不是代码异味。
  • 不处理测试代码。测试代码遵循不同的规则——重复往往是可取的,防御性的初始化往往是必要的。那是另一个审查环节。

与验证配合使用

7

推荐的工作流:

  1. LingCode 实现功能。
  2. 测试通过。
  3. /simplify——去除多余的构建。
  4. 测试仍然通过(验证,不要假设)。
  5. 提交并请求代码审查。

第 4 步是很多"精简"工作流出现漏洞的地方——修复已应用,却没有人重新运行测试套件,回归问题就这样发布了。/simplify 会自行运行测试套件;如果你通过手动编辑跳过了它,请手动运行测试套件。参阅验证后再声明完成了解这一纪律。

在 LingCode 中使用

8

将工作流打包为一个技能,这样每次你让 LingCode 精简代码时,它都会应用正确的检查清单:

---
name: simplify
description: Review changed code for reuse, quality, and efficiency, then fix any issues found. Triggers: 'simplify this', 'clean up the code', 'reduce', 'too verbose', 'review my diff', 'is there a simpler way', 'shorter version', 'refactor for clarity'. Actions: scan diff for five categories — missed reuse opportunities, over-abstraction, defensive code for impossible cases, dead branches, narrating comments. Output: structured report + edits. Explicitly NOT: behavior changes, performance optimization, taste rewrites, test changes.
---

Review the current diff (default: git diff HEAD; or the scope the
user names) against five categories, in priority order:

1. Reuse — does this diff add code that already exists elsewhere
   in the codebase? Grep for similar shapes before accepting new
   helpers. Prefer call-site updates over duplicate utilities.

2. Over-abstraction — protocols with one conformer, factories
   with one product, generics with one concrete type. Inline.
   Re-add the abstraction when a second use case appears.

3. Defensive code for impossible inputs — guard clauses on
   non-nullable types, range checks the type system already
   enforces, catch-and-rethrow that adds nothing. Delete.

4. Dead branches and unused parameters — error cases that can't
   reach, params no caller passes, "for future use" knobs.
   Delete.

5. Comments that narrate code — "// increment counter" above
   "counter += 1" is noise. Keep comments that explain *why* (a
   constraint, a non-obvious invariant), drop comments that
   describe *what*.

Group findings by category. For each, give file:line, the smell,
and a concrete rewrite. Use a "Consider" bucket for judgment
calls.

After applying fixes, re-run the test suite. Revert any fix that
breaks a test; keep the rest.

Do not change behavior. Do not optimize for performance. Do not
rewrite working code that's just verbose by taste. Do not touch
test files.

保存为 ~/.lingcode/skills/simplify/SKILL.md——参阅安装技能了解确切的存放位置以及技能的发现机制。

获取 LingCode →

下一步