关于 code-refiner
code-refiner 是面向开发者的多轮代码整理技能,强调在保持可观察行为不变的前提下提升可读性与可维护性。它涵盖范围分析、结构改进、语言习惯指导和验证。
主要功能
- 01五阶段整理流程
- 02复杂度与结构分析
- 03语言习惯指导
- 04保持行为不变的约束
- 05测试与代码检查验证
适用场景
- 01在不改变行为时简化复杂函数
- 02整理近期 Git 修改
- 03对整个模块进行深入整理
- 04重构后核对行为与测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mathews-tom/ armory --skill code-refiner安装后在 Claude Code 中输入/code-refiner确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.mdevals/cases.yamlreferences/go.mdpython.mdrust.mdtypescript.mdscripts/complexity_report.py详细介绍
代码优化
一项结构化、多轮次的代码优化技能,可将复杂、冗长或错综混乱的代码转换为简洁、符合惯用风格且易于维护的实现,同时不改变代码的行为。
理念
目标不是减少代码行数,而是让一位凌晨 2 点疲惫不堪的工程师也能读懂、理解并安全地修改代码。每项更改都必须通过以下三项检验:
- 行为等价——相同的输入会产生相同的输出、副作用和错误
- 降低认知负担——不熟悉代码的读者在更改后能更快理解代码
- 提升维护效率——更改让未来的修改更容易,而非更困难
当清晰与简洁发生冲突时,优先选择清晰。当惯用风格与显式表达发生冲突时,应考虑团队的经验水平。当 DRY 与局部性发生冲突时,对于阅读多于修改的代码,优先选择局部性。
前置条件
- git——当用户未指定目标文件时,在阶段 1 中用于检测范围(
git diff) - Python 3.10+——运行
scripts/complexity_report.py以获取定量复杂度指标
工作流
按以下顺序执行。每个阶段都基于前一阶段推进。不要跳过阶段,但要根据请求范围调整深度(单个函数只需轻量处理,完整模块则需要更全面的处理)。
阶段 1:初步调查
在进行任何修改之前,先建立整体认识:
- 确定范围——涉及哪些文件或函数?如果用户没有指定,请检查最近的 git 修改:
git diff --name-only HEAD~5或git diff --staged --name-only - 识别语言和生态系统——查看文件扩展名、导入项和配置文件(package.json、pyproject.toml、go.mod、Cargo.toml)。如需针对惯用风格的指导,可从
references/加载相应的语言参考资料 - 了解项目约定——检查 CLAUDE.md、.editorconfig 和 linter 配置(eslint、ruff、golangci-lint、clippy)。这些约定优先于通用的惯用风格偏好
- 了解测试覆盖情况——查找测试文件。如果存在测试,请记下测试运行器,以便在更改后验证行为等价性
- 记录复杂度基线——针对每个目标函数或方法,先在心中记录:
- 嵌套深度(最大缩进层数)
- 分支数量(if/else/match/switch 分支)
- 提前返回与单一出口的数量
- 参数数量
- 代码行数
- 职责数量(是否承担多个职责?)
阶段 2:结构分析
在着手寻找解决方案之前,先找出实际问题。按严重程度对问题分类:
严重(始终修复):
- 死代码(无法到达的分支、未使用的变量或导入项)
- 冗余操作(重复检查同一条件、重新计算已缓存的值)
- 可由标准库或语言内置功能替代的逻辑
- 本可避免的共享状态修改
高(除非有明确理由,否则修复):
- 嵌套层级超过 3 层的函数
- 参数超过 5 个的函数
- 臃肿函数(超过 40 行或承担超过 3 项职责)
- 重复代码块(3 处或更多处相似逻辑)
- 反转或令人困惑的布尔逻辑
- 使用字符串表示的枚举
中(在不增加风险且能提升清晰度时修复):
- 不清晰的变量或函数名称
- 缺失或容易误导的类型注解
- 不必要的中间变量
- 过度抽象(没有增益的包装器)
- 只是复述代码、而非解释 原因 的注释
低(仅在专门的清理过程中修复):
- 格式不一致(交由 linter 处理)
- 导入项排序
- 行尾空白、行长度
阶段 3:执行重构
使用以下策略应用更改,并按影响与风险的比值从高到低排序:
3a. 消除冗余
重构前先删除。代码越少,需要考虑的内容就越少。
- 删除未使用的导入、变量和函数
- 移除不可达的分支(但要确认它们确实不可达)
- 删除重复说明显而易见内容的注释(保留解释 原因 的注释)
- 删除仅转发调用的空操作包装函数
3b. 扁平化结构
减少嵌套和认知负担:
- 守卫子句:将深层的
if嵌套改为提前返回 - 提取条件:为复杂的布尔表达式命名(
is_valid_order = ...) - 分解循环:如果一个循环同时执行筛选、转换和累积,就将这些操作拆开 (或使用适合该语言的结构:列表推导式、迭代器、流)
- 反转条件:当
else分支是“正常路径”时,调换条件顺序
3c. 合并并命名
让代码意图一目了然:
- 提取函数,封装重复逻辑或不同职责
- 按 要完成的任务 命名,而不是按 实现方式 命名
- 函数应在同一抽象层级上只做一件事
- 用具名常量替换魔法值
- 按意图重命名:
data→user_records,process→validate_and_enqueue - 当参数数量超过 3 个时,将相关参数组合到配置/选项结构体中
3d. 运用语言惯用法
应用特定于语言的模式(详情请参阅 references/<language>.md):
- Python:推导式、上下文管理器、数据类、结构化模式匹配
- Go:表驱动测试、错误包装、函数式选项、接口实现
- TypeScript:判别联合、品牌类型、const 断言、satisfies
- Rust:迭代器链、
?运算符、From/Into、新类型模式
3e. 收紧类型
类型是由编译器检查的文档:
- 为公共函数添加返回类型注解
- 将字符串类型参数替换为枚举/联合类型
- 尽可能将
any/interface{}缩窄为具体类型 - 对不应混淆的标识符使用品牌类型/新类型模式
第 4 阶段:验证
绝不要跳过此阶段。 会破坏行为的简化不是真正的简化。
- 运行现有测试 —— 如果存在测试套件,就运行它,并报告通过/失败情况。
- 运行代码检查工具/类型检查器 —— 如果已配置,就运行它,并修复由本次修改引入的新问题。
- 手动追踪 —— 对每个重构后的函数,在脑中分别追踪一个正常路径输入和一个错误路径输入在旧代码与新代码中的执行过程,确认行为一致。
- 副作用审查 —— 如果原始代码存在副作用(I/O、变更、日志记录),请确认新代码以相同的顺序和条件保留了这些副作用。
如果测试失败或行为不一致:撤销具体的修改,不要试图修复测试。
第 5 阶段:报告
以结构化摘要的形式呈现修改内容。这一点很重要——开发者需要在提交前了解并信任所做的修改。
对于每个已修改的文件,提供:
## <filename>
### Changes
- [Critical] Removed unreachable error branch in `parse_config` (dead code after L42 guard)
- [High] Extracted `validate_credentials()` from 60-line `handle_login()` (was 3 responsibilities)
- [Medium] Renamed `d` → `document`, `proc` → `process_batch`
### Complexity Delta
- `handle_login`: 4 levels nesting → 2, 8 branches → 5
- `parse_config`: removed 12 lines of dead code
### Risk Assessment
- Low risk: all changes are structural, no logic modifications
- Tests: 47/47 passing
根据工作范围调整详略程度。单个函数的清理用一句话说明即可;涉及多个文件的重构则提供完整报告。
行为约束
这些是硬性规则。无论代码看起来可以变得多简洁,都不得违反:
- 绝不改变可观察到的行为——包括错误消息、日志输出、返回值、副作用顺序和异常类型
- 绝不移除错误处理——即使看起来多余也不行。防御性代码往往有其原因,而仅凭代码本身你可能看不出来
- 绝不引入新依赖——简化不会给依赖树带来任何收益
- 绝不重构指定范围以外的代码——除非用户明确要求扩大处理范围。克制“再顺手修一处”的冲动
- 保留公共 API 表面——对使用者可见的函数签名、导出名称和类型定义,未经用户明确批准不得更改
- 尊重现有测试——如果测试断言了特定行为,该行为就是要求,即使看起来不合理。应在报告中指出,不要更改
配置范围和力度
用户可能会指定不同模式。如果没有指定,默认使用 standard。
| 模式 | 范围 | 严重性阈值 | 测试要求 |
|---|---|---|---|
quick | 单个文件或函数 | 仅 Critical 和 High | 建议运行测试 |
standard | 最近的 git 更改 | Critical、High 和 Medium | 如果存在测试,则必须运行 |
deep | 整个模块/软件包 | 所有严重性 | 必须运行测试 |
surgical | 用户指定的行/函数 | 所有严重性 | 手动追踪即可 |
用户可以通过说“快速检查一下”或“深度清理这个模块”等方式指定模式。
不应进行优化的情况
遇到以下情况时应礼貌地提出异议:
- 代码没有测试,但用户想进行深度重构 → 建议先编写测试
- 代码是自动生成的(protobuf、OpenAPI、ORM 模型)→ 建议修改生成器
- 请求实际上是伪装成“清理”的功能变更 → 澄清意图
- 代码位于热点路径中,而“简化”会引入分配/复制 → 指出这一权衡
语言参考
有关特定语言的惯用写法指导,请阅读相应的参考文件:
references/python.md— Python 专属模式、反模式和标准库替代方案references/go.md— Go 惯用写法、错误处理模式和接口设计references/typescript.md— TypeScript/JavaScript 模式、类型收窄和模块设计references/rust.md— Rust 惯用写法、所有权模式和迭代器用法
只加载当前范围涉及的语言对应的参考文件。这些文件提供详细的模式目录,用于补充上述通用方法。
自我合理化
| 合理化说法 | 实际情况 |
|---|---|
| “代码已经够易读了” | “够”不是标准——如果下一位开发者需要把一个函数读 3 遍,它就不够易读 |
| “重构有回归风险” | 不重构会累积技术债——前后都运行测试套件,这就是测试的用途 |
| “代码库一直以来都是这样写的” | 延续糟糕模式依然是糟糕做法——逐步改进,不要保留反模式 |
| “性能可能会变差” | 前后进行基准测试——大多数可读性重构对性能毫无影响;过早优化是万恶之源 |
| “它没坏,就别改” | 优化不是修复——而是让可运行的代码更易维护、测试和理解,方便后来者 |
| “我以后会重构整个模块” | 渐进式优化行之有效;大爆炸式重写往往失败——现在就改进你正在处理的部分 |
危险信号
- 声称“只是重构”却改变行为——优化必须保留所有现有行为
- 未经说明就修改声明范围之外的代码
- 简化时移除错误处理或验证
- 为一次性操作引入新的抽象
- 重构前后都未运行测试套件
- 修改不属于原始任务的代码风格
验证
- 优化前后所有现有测试均通过
- 行为未发生变化——所有输入的输出和副作用均相同
- 修改仅限于声明范围——不顺手修改无关代码
- 圈复杂度降低或保持不变——绝不增加
- 未为单次使用的情况引入新抽象
- Linter 和类型检查器均通过:
ruff check+mypy --strict或tsc --noEmit+eslint