agent-skills code-simplification 技能实战:AI 编程代理如何在行为零改动下降低代码复杂度
2026/9/7 23:12:48 网站建设 项目流程

agent-skills code-simplification 技能实战:AI 编程代理如何在行为零改动下降低代码复杂度

【免费下载链接】agent-skillsProduction-grade engineering skills for AI coding agents.项目地址: https://gitcode.com/GitHub_Trending/agentskill/agent-skills

本篇围绕 agent-skills 仓库中的 code-simplification 技能 展开,完整讲解其五条简化原则、四步简化流程与语言级简化模式,并结合仓库中配套的/code-simplify命令、行为评测用例和 simplify-ignore 保护钩子,说明该技能从「文档化流程」到「可验证工程资产」的完整落地方式。读完后,你将掌握一套可直接应用于 AI 编码代理(Claude Code、Cursor、Codex 等)的行为保持型重构方法。

技能定位:在 Review 阶段把「能跑但难读」的代码变简单

code-simplification 是 agent-skills 中 25 个技能之一,归属于开发生命周期的 Review(合并前质量门)阶段,核心定义是:在严格保持行为不变的前提下降低代码复杂度。它的目标不是减少行数,而是让代码「更容易被阅读、理解、修改和调试」。每一项简化都要通过一个朴素测试:

新加入团队的人能否比读原始代码更快地理解这份代码?

该技能源于 Claude Code 的 Simplifier 插件(见 README.md 中对技能来源的说明),在本仓库中被改写为模型无关、流程驱动的通用技能——只要代理能接受 SKILL.md 这类指令文件,就可以遵循同一套工作流。技能的元数据(namedescription)位于 skills/code-simplification/SKILL.md 的 frontmatter 中,description用多个 "Use when…" 句式声明触发条件:代码能跑但难以阅读维护时、评审中发现复杂度问题时、接手时间压力下写出的遗留代码时等。

在整个仓库的分工中,这个技能与 code-review-and-quality 技能配合使用:前者负责「发现问题后如何安全地改」,而 commands/code-simplify.toml 命令在最后一步明确要求用code-review-and-quality来审查简化结果。

何时使用,何时不要使用

文档把触发场景归纳为六类:

  • 功能已实现、测试已通过,但实现感觉比必要更「重」;
  • 代码评审中被指出可读性或复杂度问题;
  • 遇到深层嵌套逻辑、超长函数或命名不清的代码;
  • 重构时间压力下写出的代码;
  • 需要整合散落在多个文件中的相关逻辑;
  • 合并变更引入了重复或不一致之后。

同样重要的是不使用的场景,技能明确列出了四种「不要简化的情况」:

  1. 代码已经干净可读——不要为了简化而简化;
  2. 你还不理解代码在做什么——先理解再简化;
  3. 代码是性能关键路径,且「更简单」的版本会可测量地变慢;
  4. 你即将整体重写该模块——简化即将丢弃的代码是浪费。

五大原则:简化的行为约束

原则 1:精确保持行为

不改变代码「做什么」,只改变它「怎么表达」。所有输入、输出、副作用、错误行为和边界情况必须保持完全一致。如果对某项简化能否保持行为没有把握,就不做。每次变更前回答四个问题:

ASK BEFORE EVERY CHANGE: → 对每一个输入,这个改动是否产生相同的输出? → 是否维持了相同的错误行为? → 是否保持了相同的副作用和执行顺序? → 所有既有测试是否在不做任何修改的情况下仍然通过?

原则 2:遵循项目约定

简化的含义是让代码与代码库更一致,而不是强加外部偏好。动手前执行:

  1. 阅读 CLAUDE.md / 项目约定文件(本仓库同时提供 AGENTS.md 与 CLAUDE.md 作为约定载体);
  2. 研究邻近代码如何处理同类模式;
  3. 对齐项目的具体风格:导入顺序与模块系统、函数声明风格、命名约定、错误处理模式、类型标注深度。

文档对此有一句尖锐的总结:破坏项目一致性的「简化」不是简化,而是 churn(无效搅动)

原则 3:清晰优于聪明

当紧凑写法需要读者「停下来想一想」才能解析时,显式代码优于紧凑代码。文档给出两个典型对照:

// UNCLEAR: Dense ternary chain const label = isNew ? 'New' : isUpdated ? 'Updated' : isArchived ? 'Archived' : 'Active'; // CLEAR: Readable mapping function getStatusLabel(item: Item): string { if (item.isNew) return 'New'; if (item.isUpdated) return 'Updated'; if (item.isArchived) return 'Archived'; return 'Active'; }
// UNCLEAR: Chained reduces with inline logic const result = items.reduce((acc, item) => ({ ...acc, [item.id]: { ...acc[item.id], count: (acc[item.id]?.count ?? 0) + 1 } }), {}); // CLEAR: Named intermediate step const countById = new Map<string, number>(); for (const item of items) { countById.set(item.id, (countById.get(item.id) ?? 0) + 1); }

原则 4:保持平衡——警惕「过度简化」

简化本身有失败模式:过度简化。需要警惕四个陷阱:

  • 内联过度——删掉一个为某概念命名的辅助函数,反而让调用点更难读;
  • 合并无关逻辑——两个简单函数合成一个复杂函数并不更简单;
  • 删除「不必要」的抽象——有些抽象的存在是为了可扩展性或可测试性,而不是复杂度的代价;
  • 为行数优化——更少的行数不是目标,更容易理解才是。

原则 5:范围限定在变更范围内

默认只简化最近修改过的代码。除非明确要求扩大范围,否则避免顺手重构无关代码。无范围限定的简化会在 diff 中制造噪音,并带来非预期的回归风险。

四步简化流程

Step 1:动手前先理解(Chesterton's Fence)

在改动或删除任何东西之前,先理解它为什么存在。这就是「切斯特顿之篱」:如果你在路中间看到一道篱笆,却不理解它为什么在那里,就先别拆。先理解原因,再判断该原因是否仍然成立。

动手前必须能回答:

BEFORE SIMPLIFYING, ANSWER: - 这段代码的职责是什么? - 谁调用它?它调用谁? - 边界情况和错误路径有哪些? - 是否存在定义期望行为的测试? - 它为什么可能被写成这样?(性能?平台约束?历史原因?) - 检查 git blame:这段代码当初的上下文是什么?

如果答不上来,说明还不具备简化条件,先读更多上下文。

Step 2:识别简化机会

文档把「坏味道」整理成了三张可操作的信号表,每条都是具体信号而非模糊感觉:

结构性复杂度:

模式信号简化手段
深层嵌套(3 层以上)控制流难以跟随把条件提取为守卫子句(guard clause)或辅助函数
超长函数(50 行以上)承担多个职责按职责拆分为命名清晰的聚焦函数
嵌套三元表达式解析需要心理栈替换为 if/else 链、switch 或查表对象
布尔参数旗标doThing(true, false, true)替换为 options 对象或拆分为独立函数
重复条件判断同一if检查出现在多处提取为命名清晰的谓词函数

命名与可读性:

模式信号简化手段
泛化命名dataresulttempvalitem重命名以描述内容:userProfilevalidationErrors
缩写命名usrcfgbtnevt除非是通用缩写(idurlapi),用完整单词
误导性命名名为get的函数却会修改状态重命名以反映实际行为
解释「做什么」的注释// increment counter之上是count++删除注释——代码已经足够清晰
解释「为什么」的注释// Retry because the API is flaky under load保留——它们承载代码无法表达的意图

冗余:

模式信号简化手段
重复逻辑相同 5 行以上代码出现在多处提取为共享函数
死代码不可达分支、未使用变量、被注释掉的代码块移除(确认确属死代码之后)
无价值抽象不增加任何价值的包装层内联包装,直接调用底层函数
过度工程化模式factory-for-a-factory、只有一个 strategy 的 strategy替换为简单的直接实现
冗余类型断言向已可推断类型做断言移除断言

Step 3:增量应用改动

一次只做一处简化,每处改动后运行测试。重构变更必须与功能/缺陷修复变更分开提交——一个同时重构和加功能的 PR 应该拆成两个。

FOR EACH SIMPLIFICATION: 1. 做这一处改动 2. 运行测试套件 3. 测试通过 → 提交(或继续下一处简化) 4. 测试失败 → 回滚并重新考虑

不要把多处简化攒成一个未经测试的大改动:一旦出问题,你需要知道是哪一处简化导致的。

500 行法则(Rule of 500):如果一次重构预计要触及超过 500 行代码,应投入自动化手段(codemods、sed 脚本、AST 转换),而不是手工修改。这个规模的手工编辑容易出错,且审阅极其疲惫。

Step 4:验证结果

全部简化完成后,退一步整体评估:

COMPARE BEFORE AND AFTER: - 简化后的版本是否真的更容易理解? - 是否引入了与代码库不一致的新模式? - diff 是否干净、可审阅? - 队友会不会认可这个改动?

如果「简化后」的版本更难理解或更难审阅,就回滚。不是每一次简化尝试都会成功。

语言级简化模式

TypeScript / JavaScript

文档给出了四个高频模式的前后对照:

// SIMPLIFY: Unnecessary async wrapper // Before async function getUser(id: string): Promise<User> { return await userService.findById(id); } // After function getUser(id: string): Promise<User> { return userService.findById(id); } // SIMPLIFY: Verbose conditional assignment // Before let displayName: string; if (user.nickname) { displayName = user.nickname; } else { displayName = user.fullName; } // After const displayName = user.nickname || user.fullName; // SIMPLIFY: Manual array building // Before const activeUsers: User[] = []; for (const user of users) { if (user.isActive) { activeUsers.push(user); } } // After const activeUsers = users.filter((user) => user.isActive); // SIMPLIFY: Redundant boolean return // Before function isValid(input: string): boolean { if (input.length > 0 && input.length < 100) { return true; } return false; } // After function isValid(input: string): boolean { return input.length > 0 && input.length < 100; }

Python

# SIMPLIFY: Verbose dictionary building # Before result = {} for item in items: result[item.id] = item.name # After result = {item.id: item.name for item in items} # SIMPLIFY: Nested conditionals with early return # Before def process(data): if data is not None: if data.is_valid(): if data.has_permission(): return do_work(data) else: raise PermissionError("No permission") else: raise ValueError("Invalid data") else: raise TypeError("Data is None") # After def process(data): if data is None: raise TypeError("Data is None") if not data.is_valid(): raise ValueError("Invalid data") if not data.has_permission(): raise PermissionError("No permission") return do_work(data)

注意第二个例子正是 Step 2 表中「深层嵌套 → 守卫子句」规则的直接示范:把data is not None的深层嵌套倒转为三个扁平的前置检查,错误路径提前抛出,主路径保持零缩进。

React / JSX

// SIMPLIFY: Verbose conditional rendering // Before function UserBadge({ user }: Props) { if (user.isAdmin) { return <Badge variant="admin">Admin</Badge>; } else { return <Badge variant="default">User</Badge>; } } // After function UserBadge({ user }: Props) { const variant = user.isAdmin ? 'admin' : 'default'; const label = user.isAdmin ? 'Admin' : 'User'; return <Badge variant={variant}>{label}</Badge>; } // SIMPLIFY: Prop drilling through intermediate components // Before — consider whether context or composition solves this better. // This is a judgment call — flag it, don't auto-refactor.

最后一个模式值得注意:文档刻意标注 prop drilling 是「判断题」——只标记出来,交给开发者决定,而不是让代理自动重构。这与原则 4「保持平衡」一脉相承。

常见自我合理化与红旗信号

技能沿袭了 agent-skills 的「反合理化」设计(参见 docs/skill-anatomy.md 的 SKILL.md 结构规范):它预判了代理在简化过程中常用的借口,并逐条给出反驳:

合理化借口现实
「它能跑,没必要动」能跑但难读的代码,一旦出问题会很难修。现在简化会为未来每次改动省时间。
「行数少一定更简单」1 行嵌套三元并不比 5 行 if/else 更简单。简单是关于理解速度,不是行数。
「顺手把这个无关代码也简化了」无范围的简化制造噪音 diff,并让你没打算改的代码有回归风险。保持聚焦。
「有类型就够了,它是自文档化的」类型描述结构,不描述意图。命名良好的函数比类型签名更能解释why
「这个抽象以后可能有用」不要保留投机性抽象。现在没被使用就是无价值的复杂度,删掉,需要时再加回来。
「原作者肯定有理由」也许。查 git blame——应用切斯特顿之篱。但累积复杂度往往没有理由,只是高压迭代下的残留物。
「我加功能的同时顺手重构」把重构与功能工作分开。混合变更更难审阅、回滚,也更难在历史中理解。

配套的红旗信号(Red Flags)用于事中自检:

  • 简化之后需要修改测试才能通过(说明你大概率改变了行为);
  • 「简化后」的代码更长、更难跟随;
  • 按个人偏好而非项目约定重命名;
  • 以「让代码更干净」为由删除错误处理;
  • 简化你自己并不完全理解的代码;
  • 把大量简化攒进一个难以审阅的大提交;
  • 未经要求就重构当前任务范围之外的代码。

验证清单:简化的退出条件

与仓库中其他技能一样,code-simplification 以可验证的证据收尾,而非「感觉变好了」:

  • 所有既有测试不做修改即全部通过
  • 构建成功且无新警告
  • Linter/formatter 通过(无风格回退)
  • 每一处简化都是可审阅的增量变更
  • diff 干净——没有混入无关改动
  • 简化后的代码遵循项目约定(对照 CLAUDE.md 或等价文件)
  • 没有移除或弱化任何错误处理
  • 没有遗留死代码(未使用的导入、不可达分支)
  • 队友或评审代理会认可这是一次净改善

仓库配套资产:命令、评测与保护钩子

技能文档之外,仓库为 code-simplification 配套了三层可执行资产,可以让「行为保持」从口号变成可检验的机制。

/code-simplify斜杠命令

commands/code-simplify.toml 把 SKILL.md 的原则压缩为代理可直接执行的提示词,其步骤与技能文档一一对应:读取 AGENTS.md 并研究项目约定 → 确定目标代码(默认为最近的变更)→ 触碰前先理解用途、调用方、边界与测试覆盖 → 按模式扫描机会(深嵌套、长函数、嵌套三元、泛化命名、重复逻辑、死代码)→ 增量应用、每改一处跑一次测试 → 最终验证测试、构建与 diff。它甚至内建了回退指令:「如果某处简化后测试失败,回滚该处改动并重新考虑」,收尾时调用code-review-and-quality技能审查结果。这正是原则 1(精确保持行为)和 Step 3(增量应用)在命令层的落地。

行为评测:用一个真实的「坏」配置文件解析器做靶子

evals/cases/code-simplification.json 定义了该技能的行为评测:提示词要求「简化一个 80 行的配置文件解析函数,精确保持行为」,files字段指向评测夹具目录。评测的期望(expectations)恰好把技能文档的四条核心原则变成了可判定的断言:

  • 行为被保持(测试不改动且通过,或具体论证了等价性);
  • 复杂度被削减而不是转移(对应原则 4:合并无关逻辑不算简化);
  • 回答中说明删掉了什么、以及为什么安全;
  • 简化过程中没有加入任何新功能。

对应的夹具 config-parser.js 是一段刻意写「糙」的 INI 风格解析器:parseConfig 函数用一个for循环套了 6 层if(非空、非注释、区段头、键分隔符、键非空、值类型推断),最深嵌套处缩进达 5 层——这正是 Step 2 表中「深层嵌套 → 守卫子句/提取辅助函数」的标准靶子。而 config-parser.test.js 用一个node:test用例锁定了全部行为面:区段解析、字符串/数字/布尔类型推断、注释忽略、默认区段,四件事。简化者必须让这个测试原样通过,这就把「精确保持行为」从一个承诺变成了 CI 可验证的事实。触发侧,评测用例还声明了正例提示(如「这个函数能跑但太聪明了,简化它且别改行为」)和负例提示(如「给应用加一个 feature flag 系统」不应路由到本技能),配合仓库三层评测体系(见 evals/README.md)保证技能在正确场景被触发、且不与相邻技能混淆。

simplify-ignore 钩子:让「不能简化」的代码对模型不可见

原则 3 中有一类特殊情况:性能关键代码(如手工展开的热路径)看起来「笨重」,但简单化版本会可测量地变慢。仓库用 hooks/SIMPLIFY-IGNORE.md 描述的钩子机制解决它:用注释标记保护块,执行/code-simplify时模型根本看不到保护块内部。

/* simplify-ignore-start: perf-critical */ // manually unrolled XOR — 3x faster than a loop result[0] = buf[0] ^ key[0]; result[1] = buf[1] ^ key[1]; result[2] = buf[2] ^ key[2]; result[3] = buf[3] ^ key[3]; /* simplify-ignore-end */

实现位于 simplify-ignore.sh,一个脚本挂三个钩子事件(见 SIMPLIFY-IGNORE.md 的事件表):

事件动作
PreToolUse Read备份原文件,把保护块就地替换为BLOCK_<hash>占位符
PostToolUse Edit\|Write把占位符还原为真实代码,保存模型改动后重新过滤
Stop会话结束时从备份恢复所有文件

每个块用内容哈希(shasum/sha1sum取前 8 位十六进制)标识(哈希工具函数),即使模型复制或重排占位符,往返替换也无歧义。占位符保留原注释语法(Python 中是# BLOCK_xxx、HTML 中是<!-- BLOCK_xxx -->),且支持带原因的形式——simplify-ignore-start: reason中的 reason 会出现在占位符里,让模型知道「这里有一块被保护的东西,原因是 perf-critical」而不知道具体实现。文档同时给出了已知限制(单行块会隐藏整行、注释收尾符只识别*/-->、渐进式回退展开可能留下残留、文件重命名后需手动恢复)与崩溃恢复命令,属于「把失败模式写进文档」的透明做法。

这个钩子与技能本身形成了一个闭环:SKILL.md 从认知层约束代理(性能关键代码不要简化),simplify-ignore 从机制层兜底(就算代理想改,它也没有看到那些代码)。

小结

code-simplification 技能的价值不在于罗列了哪些重构手法,而在于它把「简化」从一个模糊的审美动作变成了一条有护栏的流水线:动手前有切斯特顿之篱式的理解门槛(Step 1)、机会识别用具体信号表而非感觉(Step 2)、每次改动以既有测试为仲裁(Step 3)、收尾以「队友会不会认可」为最终判据(Step 4);五条原则划定行为的边界,合理化对照表和红旗信号防止代理在执行中自我说服,验证清单给出可检查的退出条件。再叠加仓库中的/code-simplify命令、以真实测试锁定行为面的评测夹具、以及让保护块对模型不可见的 simplify-ignore 钩子,整套流程从「建议」变成了「可验证的工程约束」——这恰恰是 agent-skills 把资深工程师经验封装为代理可执行工作流的核心思路。

【免费下载链接】agent-skillsProduction-grade engineering skills for AI coding agents.项目地址: https://gitcode.com/GitHub_Trending/agentskill/agent-skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询