Community编程与开发github.com

armandkaufmann/refactor-pass

在Git仓库中找出需要重构的内容以及无需动工的部分,还原开发者手写代码时对代码库的自然直觉。它通过Git历史热力图定位变更密集区,识别代码坏味并给出命名重构方案的战术手册,预估下一次变更的成本,最终生成一个可逐项完成的重构清单。

refactor-pass 是什么?

本技能旨在为AI编码助手(如Claude Code)提供一种系统化的重构决策框架,弥补其缺乏编码直觉的缺陷。它通过三个核心维度重建开发者对代码库的感知:1)Git历史热力图——定位变更频繁的热点文件;2)代码坏味检测——基于经典目录识别具体问题(如过长函数、散弹式修改),并对应到有命名的重构手法;3)变更成本推演——模拟下一次变更会触及哪些文件,量化重构前后的代价差异。 技能支持任何Git仓库,通过Python脚本分析历史和代码度量,最终生成一份优先级排序的重构清单(R1、R2…),并附有“无需处理”的说明以克制过度重构倾向。它特别适用于开发者询问技术债务、代码健康度、最糟糕的模块或“我们改了很多东西”,以及当需要清理或提升代码可维护性、可扩展性时。输出的HTML清单可跨会话复用,并支持增量更新。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/armandkaufmann/refactor-pass/tree/HEAD

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

重构通行证

重构曾经始于一种感觉。代码难以处理:一个类你得滚动查找新内容该放哪儿,一个函数你得在脑中记住才能修改某个分支,一个功能意味着要访问八个文件。同样的感觉也告诉你哪些代码可以不管。从未触碰过的丑陋代码从未造成伤害,所以你就随它去。

一个写代码的智能体感受不到这些,主要阅读智能体所写代码的开发者同样感受不到。于是坏味在未察觉中堆积。智能体会无怨无悔地向一个函数添加第三十个分支。当被要求重构时,它会清理所有看起来不整洁的地方,包括无人触碰的代码。本技能将这种感觉的两个方面重新赋予你,作为三个可衡量的东西:

  1. 你会感受到的地方:热力图。 摩擦只在你持续修改的地方有意义。根据研究,文件大小以及文件变更的频率比任何单一坏味更能预测维护问题。
  2. 你会感受到的内容:坏味。 已建立的坏味目录,每种坏味都转化为需要统计的内容、何时不是坏味,以及数十年来实践为其建立的有命名重构方案的战术手册:references/smells.md。
  3. 你会感受到的程度:推演。 关注即将进行的一次变更(已计划或很可能发生),列出它会触及的所有内容。

然后结论将位置与内容结合:

有坏味无坏味
经常变更重构表明它没问题
很少变更留待处理;最多添加“以后”备注无需处理

“表明它没问题”这一格与“重构”同样重要。这是直觉中克制的一半,报告会显示它。

两种规模的问题。 一次通行覆盖整个仓库:步骤 1 到 7。针对某个区域的问题(“我们应该重构 X 吗?”)在该区域上运行相同步骤。除非有多个项目,否则它会跳过清单,并且答案可以是“不”。无论哪种情况,首先运行步骤 1 的脚本,只带 --checklists 参数:如果它列出了早期通行中的清单,请先阅读在早期通行之后。

1. 位置:热力图

python3 <此技能目录>/scripts/heatmap.py -C <仓库> <作用域...>

<此技能目录> 是包含此 SKILL.md 的文件夹。如果 python3 不是命令,常见于 Windows,请使用 python 或 py。

  • 作用域:源文件夹和测试文件夹,例如 src tests 或 app,不包括文档或资源。阅读项目的 README、目录列表和任何智能体指令(AGENTS.md、CLAUDE.md)来决定。测试文件(通过名称如 Board.spec.ts、test_x.py、XTest.php... 或者文件夹识别)不包含在表格和对中,当它们与多个文件一起变更时单独列出。为其他测试名称添加 --test GLOB,为看似测试文件但不是的文件添加 --not-test GLOB(热力图会列出它怀疑的任何文件),为生成文件添加 --ignore GLOB。
  • 窗口:默认是最后 200 次提交。当用户指定起点时使用 --since 设置(“自 v2.0 起”、“自我们添加计费以来”、“过去三个月”):一个标签、分支或提交,或者一个日期。机器人的提交、仓库在 .git-blame-ignore-revs 中列出的大规模格式化提交,以及早期清单上记录的提交会自动排除。--exclude-commits 排除其他会让它们触及的所有内容显得热门的提交,例如供应商导入。
  • 数据太少? 当窗口内少于约 30 次提交时,计数无法区分热文件和冷文件。扩大窗口,或者说明历史太短无法指向任何位置,仅凭坏味判断。浅克隆(热力图会说明)需要 git fetch --unshallow;询问用户。

--help 解释每个列和选项。

阅读热力图

  • 热点的提交次数多且文件也大,因此列表首先列出它们:按提交次数乘以大小排序。文件小而提交次数多通常是没问题的,比如每个功能都会编辑的配置文件。无人触碰的大文件保持原样成本很低。
  • 仍然热门? recent 统计其在窗口较新一半(一半的提交,不是一半的时间)中的提交次数,last 是其最新提交的日期。结合窗口的日期一起阅读:八个 recent 提交,全部在较新一半开始的那一天,是已经冷却的爆发。缩小的文件可能已经被处理过。
  • rel 是变更的行数相对于文件大小。相对变更率预测缺陷的能力远优于绝对变更率。远高于 1 意味着文件在窗口期内被重写或增长。结合增长阅读:一个只增长、提交次次都增长的文件是仅加法增长。在窗口期内创建的文件,其增长等于其大小。
  • 对是指在同一提交中经常一起变更的文件。一个分组是三个或更多彼此成对的文件,由同时变更它们所有文件的提交计数;重叠的分组会一起列为一个区域。
    • 来自不同层且强成对的,或者跨层的分组,通常意味着一个功能散布在其中(散弹式修改)。
    • 检查每对的连接方式。导入、调用或某个东西命名的约定(路由、模式、控制器和页面之间的类型文件)是可见的依赖:跨边界的一个功能。一起变化但没有此类连接的成对文件,比如规则的两个副本或手动保持同步的两个列表,具有隐藏的依赖关系,这是最强的耦合形式。
    • 与许多其他文件成对的文件是一个每次变更都会经过的中心枢纽。
    • 除了自己的测试文件外,还与多个文件一起列出的测试文件,与其内部实现紧密耦合,会阻碍重构,除非那些文件是测试仅跟随的分组。
    • 如果许多提交的文件过多无法成对(--max-files),例如在压缩合并的仓库中,请提高该值或将成对视为部分信息。
  • 变更原因。 阅读最上面的几个文件的提交消息(--show),并按功能分组。一个文件因多种不相关的原因变更,是发散式变更,这在此处比任何计数都更直接地体现。

2. 内容:坏味

  • 在代码库自身范围内度量热点文件,使用同一种语言。python3 <此技能目录>/scripts/measure.py -C <仓库> <作用域...> 根据该语言的第 70、80 和 90 百分位将每个文件放入一个频段,--show <文件> 显示其每个函数。大意味着在第 80 或 90 百分位频段(频段也应用了目录的底线);第 70 百分位值得仔细查看。当它说百分位偏向一个文件时,也请参考度量中的参考点,该参考点也说明了如何统计其余部分(分支、参数、内聚性),或使用项目的 linter。
  • 亲自阅读最顶部的两三个核心文件。 数字指引方向;阅读做出决定。
  • 审查其他热门区域。 如果您可以运行子智能体,给其中两到三个每个分配一个区域(一个层或一个目录,以便每个一次读取整个区域),然后并行运行它们。根据 references/review-brief.md 为每个智能体提供简要说明。如果没有子智能体,则根据相同的简要说明,一次一个区域地亲自审查这些区域。
  • 使用已建立的名称命名每个坏味(过长函数、散弹式修改、重复切换……),并在计数前对照目录中的“何时不是坏味”进行检查。该名称是其战术手册的索引。
  • 寻找缺失的概念。 坏味往往成群出现,一个集群通常指向代码一直使用但从未命名的一个东西:一个状态、一种类型的定义、设置的单一来源。请参阅坏味相伴而行。
  • 检查测试覆盖了哪些热点代码:请参阅未测试代码。
  • 你注意到的错误作为 F 项添加到列表中,但当前不修复。尚未复现的错误是一种怀疑:将其作为标题(“检查:编辑跳过周末规则”),并在注释中附上证据。其第一步是一个失败的测试;如果没有测试失败,则跳过它,并附上你的发现。

3. 程度:推演

这是最接近旧时感觉的部分。它也是让一个项目令人信服的关键。

  1. 找出接下来的变更。已计划的变更优于推断的变更,因此首先从用户说即将进行的变更(“在我们开始第 7 块之前”)中获取它们,然后从项目的计划或路线图中获取(如果有的话),最后从提交消息中获取:最常出现的变更类型(“添加新的报告类型”、“添加设置”、“添加屏幕”)。取最常见的两三种类型,而不仅仅是一种。
  2. 对于每种类型,取该类型的最新一次真实提交并列出它触及的内容(git show --stat)。如果它早于窗口期,仍然使用它并给出其日期;在今天代码上的推演将显示自那以来哪些内容发生了变化。如果项目的文档或智能体指令有该变更的方案,则计算其步骤。一个方案需要五步来添加一个东西,这本身就是一个承认。
  3. 推演下一个变更,无需实际编写。列出你必须阅读的每个文件、你将编辑的每个位置以及你需要保持同步的每个副本。
  4. 写下今天的计数以及你建议的重构后的计数:“今天,一个新的报告类型触及 7 个文件和 3 个开关;重构后,它将只触及 1 个文件。”

一个计划工作将落地的冷文件不再冷:将其放入表格的顶行,因为下一次变更新增的成本无论多少都需要支付。如果下一次变更今天成本很低,那么坏味的代价就很小,无论它看起来如何。

4. 检查每个发现

审查者的发现是线索,不是事实,你自己的第一印象也是如此。在任何项目进入清单之前,打开引用的行,重新运行计数,并删除或纠正不成立的内容。在报告中说明你检查了什么。一个错误的项目如果导致用户进行重构,其代价远远超过检查它所花的一分钟。

然后应用克制。被要求发现问题的审查者总会找到些东西,而修复每一个发现会留下为不可能发生的情况准备的额外层和测试。删除冷的、被“何时不是坏味”行所豁免的,以及推演说明成本低廉的内容。

5. 排序

为每个项目分配一个稳定的 ID,因为用户会用它来命名项目(“从 R4 开始”),可能是在后续会话中。方括号中的名称是项目在清单(步骤 6)中的字段;F、L 和 D 项目在 note 中说明它们的字段。

  • R1, R2… 重构,按建议顺序。每个包含:
    • 一个以缺失概念作为结果的标题(“命名结账的状态”,而不是“重构 CheckoutController”)(title);
    • 按名称排列的坏味,包含数字和 file:line(smells);
    • 它缓解的变更类型,来自步骤 3(eases),以及该变更的成本(cost:today 和 after);
    • 作为战术手册步骤的计划(plan);
    • 文件、大小(S、M 或 L)和风险(低、中或高)(files、size、risk);
    • 如何检查行为未改变(verify)。
  • F1… 沿途发现的小修复,每个单独提交。
  • L1… 以后:有坏味但冷门,或者当附近代码下次被触及时应完成。
  • D1… 由用户决定:关于工作方式的变更,例如使每次变更都代价高昂的文档约定。列出权衡,而不是决策。

按收益与风险排序。收益是变更减轻未来工作的程度:热力图和推演是证据。坏味的优先级说明了哪些类型往往更重要。长而复杂的代码以及散布在文件间的变更最重要。特性依恋和中间人这样的耦合坏味最不重要,并且可以在过程中顺便修复。

按如下方式排序列表:

  • 阻塞项优先:与内部实现紧密耦合的测试,这些测试会使稍后的每一步看起来像破坏了什么东西,以及没有测试覆盖的代码,其项目以固定测试开始或明确说明无法检查(步骤 7);
  • 接下来是消除复制粘贴路径的小项目;
  • 大规模移动在后,因为它们通常需要先建立一个接缝;
  • 任何你无法自行验证的内容(听起来、感觉或看起来如何)排在最后,因为用户必须检查。

6. 编写清单和报告

再次运行步骤 1 的命令,使用 --page .refactor-pass/<YYYY-MM-DD>.html,以今天的日期为准。它会从 assets/page.html 创建清单,并将热力图写入其 heatmap 块;再次运行,它只会刷新热力图,不改变其他内容。你在其下面的 pass 块中编写内容,其 project、started、base 和 updated 已预先填充:

  • summary:用两到三句话描述整体状态;
  • items:每个项目,包含步骤 5 的字段、一个 status(todo、doing、waiting 等待用户、done 或 skipped 并在 outcome 中说明原因)、以及 commits 和 outcome(新项目为空);结转的项目保留其 from。每个项目以一行中的 ID 和状态开头,{"id": "R1", "status": "todo",,其后是其他字段,如块上方注释中完整显示的;不要使用 JSON 美化工具的布局,因为步骤 7 的状态更新会编辑那一行;
  • left_alone:每个包含 what 和 why;
  • checks:项目的检查,来自其指令,如果没有则列出你将手动检查的内容;
  • earlier:早期通行之后,其 checklist 和 results,每个在此通行中完成的重构对应一个:其 id、title、eases 和 cost,实际后续的 change 以及它实际触及的内容(如果尚未发生则均为空),以及一个 note。否则为 null;
  • log:每个包含 date 和 text,最新的在前。

每次编辑后,运行 python3 <此技能目录>/scripts/check_page.py <页面>,它会捕捉括号不匹配、字段拼写错误、重复 ID 或未从一行开始的项目。如果你的环境可以发布或预览 HTML 页面,可以 p

…

[已截断以进行翻译]

相关技能