ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

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

agent-skills code-simplification 技能实战:AI 编程代理如何在行为零改动下降低代码复杂度 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 这类指令文件就可以遵循同一套工作流。技能的元数据name、description位于 skills/code-simplification/SKILL.md 的 frontmatter 中description用多个 Use when… 句式声明触发条件代码能跑但难以阅读维护时、评审中发现复杂度问题时、接手时间压力下写出的遗留代码时等。在整个仓库的分工中这个技能与 code-review-and-quality 技能配合使用前者负责「发现问题后如何安全地改」而 commands/code-simplify.toml 命令在最后一步明确要求用code-review-and-quality来审查简化结果。何时使用何时不要使用文档把触发场景归纳为六类功能已实现、测试已通过但实现感觉比必要更「重」代码评审中被指出可读性或复杂度问题遇到深层嵌套逻辑、超长函数或命名不清的代码重构时间压力下写出的代码需要整合散落在多个文件中的相关逻辑合并变更引入了重复或不一致之后。同样重要的是不使用的场景技能明确列出了四种「不要简化的情况」代码已经干净可读——不要为了简化而简化你还不理解代码在做什么——先理解再简化代码是性能关键路径且「更简单」的版本会可测量地变慢你即将整体重写该模块——简化即将丢弃的代码是浪费。五大原则简化的行为约束原则 1精确保持行为不改变代码「做什么」只改变它「怎么表达」。所有输入、输出、副作用、错误行为和边界情况必须保持完全一致。如果对某项简化能否保持行为没有把握就不做。每次变更前回答四个问题ASK BEFORE EVERY CHANGE: → 对每一个输入这个改动是否产生相同的输出 → 是否维持了相同的错误行为 → 是否保持了相同的副作用和执行顺序 → 所有既有测试是否在不做任何修改的情况下仍然通过原则 2遵循项目约定简化的含义是让代码与代码库更一致而不是强加外部偏好。动手前执行阅读 CLAUDE.md / 项目约定文件本仓库同时提供 AGENTS.md 与 CLAUDE.md 作为约定载体研究邻近代码如何处理同类模式对齐项目的具体风格导入顺序与模块系统、函数声明风格、命名约定、错误处理模式、类型标注深度。文档对此有一句尖锐的总结破坏项目一致性的「简化」不是简化而是 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 Mapstring, number(); for (const item of items) { countById.set(item.id, (countById.get(item.id) ?? 0) 1); }原则 4保持平衡——警惕「过度简化」简化本身有失败模式过度简化。需要警惕四个陷阱内联过度——删掉一个为某概念命名的辅助函数反而让调用点更难读合并无关逻辑——两个简单函数合成一个复杂函数并不更简单删除「不必要」的抽象——有些抽象的存在是为了可扩展性或可测试性而不是复杂度的代价为行数优化——更少的行数不是目标更容易理解才是。原则 5范围限定在变更范围内默认只简化最近修改过的代码。除非明确要求扩大范围否则避免顺手重构无关代码。无范围限定的简化会在 diff 中制造噪音并带来非预期的回归风险。四步简化流程Step 1动手前先理解Chestertons Fence在改动或删除任何东西之前先理解它为什么存在。这就是「切斯特顿之篱」如果你在路中间看到一道篱笆却不理解它为什么在那里就先别拆。先理解原因再判断该原因是否仍然成立。动手前必须能回答BEFORE SIMPLIFYING, ANSWER: - 这段代码的职责是什么 - 谁调用它它调用谁 - 边界情况和错误路径有哪些 - 是否存在定义期望行为的测试 - 它为什么可能被写成这样性能平台约束历史原因 - 检查 git blame这段代码当初的上下文是什么如果答不上来说明还不具备简化条件先读更多上下文。Step 2识别简化机会文档把「坏味道」整理成了三张可操作的信号表每条都是具体信号而非模糊感觉结构性复杂度模式信号简化手段深层嵌套3 层以上控制流难以跟随把条件提取为守卫子句guard clause或辅助函数超长函数50 行以上承担多个职责按职责拆分为命名清晰的聚焦函数嵌套三元表达式解析需要心理栈替换为 if/else 链、switch 或查表对象布尔参数旗标doThing(true, false, true)替换为 options 对象或拆分为独立函数重复条件判断同一if检查出现在多处提取为命名清晰的谓词函数命名与可读性模式信号简化手段泛化命名data、result、temp、val、item重命名以描述内容userProfile、validationErrors缩写命名usr、cfg、btn、evt除非是通用缩写id、url、api用完整单词误导性命名名为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): PromiseUser { return await userService.findById(id); } // After function getUser(id: string): PromiseUser { 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 variantadminAdmin/Badge; } else { return Badge variantdefaultUser/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, dont 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),仅供参考
返回列表