SuperAPI AI 工具集

codebase-refactoring

编程与开发

查看项目

更新于 10-15 12:31

技能介绍

用途

codebase-refactoring 是一个引导式工作流技能,用于对代码库进行整体健康度改善,而非修复某个具体 bug。它聚焦于代码库的三大维护成本:重复代码、死代码和复杂度,使用 jscpd 工具定位每一类问题,并给出对应的修复策略。当被要求“清理”“改进”“重构”或“偿还技术债”时使用本技能。

主要能力

  • 健康度测量:通过 npx jscpd --health --reporters ai <path> 得到健康分,该分数是重复、死代码、复杂度三个子分数的加权混合,每个子分数是代码行数的占比,分数越高越好,100 表示干净。三个子分数中最低的那个指示代码库真正最痛的地方,应优先处理该维度。若某维度显示 n/a(例如死代码 n/a),表示 jscpd 无法测量它——死代码检测需要 JavaScript、TypeScript 或 Python 在代码中占实际比例——应跳过该步骤,而不是当作干净。
  • 仪表盘视图:npx jscpd --dashboard 可在同一屏展示最大重复格式、最复杂文件、最大死代码发现等完整信息。其控制台输出(默认)是唯一带有逐文件细节的报告器;在 --dashboard 上使用 --reporters ai 只会打印上述单行摘要,不会给出细分。若需要可解析的细节,可在 --dashboard 上使用 --reporters json。
  • 三个独立阶段:重复代码 → 死代码 → 复杂度是默认顺序,因为先修复重复可避免第二步浪费精力追踪调用点,先清理死代码可确保第三步排名的文件确实值得简化。三个阶段本身相互独立,可按任意顺序安全运行。

使用方式

第一步 — 重复代码

运行 npx jscpd --reporters ai --summary <path>,找出并阅读每个克隆,判断是否为值得合并的真实副本,并应用匹配的重构策略(提取函数、参数化、提取共享模块或常量,或针对结构性重复使用基类/模板)。完整的引导工作流、重命名/近似克隆的分诊规则以及每种克隆类型的示例见 dry-refactoring。其 --summary 热点排名与健康分的重复维度读取的是同一份数据,因此被标记为重复热点的文件正是拖低分数的文件。

第二步 — 死代码

运行 npx jscpd --dead-code --reporters ai <path>。这是从项目入口点(package.json 的 main/bin/exports/scripts、pyproject.toml 的 scripts、框架约定,或 --entry <glob>)出发的图遍历,而非引用计数——一个只被自身死代码调用的辅助函数也会被报告,因此删除一个发现可能使另一个原本未报告的发现变为真实。覆盖 JavaScript、TypeScript、JSX、TSX、Vue、Svelte、Astro 和 Python。

四类发现及常规修复:

类别 含义 常规修复
unused-file 从未被任何地方导入,也不是入口点 删除文件
unused-export 被导出,但没有其他文件导入它 删除它,或若同文件内仍有使用则去掉 export 关键字
unused-symbol 模块私有声明,其自身文件内无任何引用 删除它
unused-import 被导入但文件内从未引用 删除导入行

工作流:

  1. 使用 --reporters ai 运行(可加 --dead-code-categories 聚焦某一类别,--include-tests 使仅测试使用不算“已使用”,--include-entry-exports 也标记入口文件自身未使用的导出,通常排除因为其整个表面就是公共 API)。
  2. 按置信度从高到低排序。所有发现为 0-100;低于 90 的发现会附带一个可能出错的理由——eval/getattr 调用、分析器不认识的装饰器、通配符重导出、名称仅出现在字符串字面量中,或别处有文件解析失败(见 JSON 报告中的 statistics.unparsedFiles)。删除前先阅读理由;--min-confidence(默认 60)只设置报告下限,并不使低置信度发现变得安全。
  3. 对每个高于你舒适阈值的发现,手工确认——在仓库中 grep 符号名(动态访问、基于字符串的路由器、jscpd 不解析的模板文件都可能隐藏真实使用)——然后应用上表中的修复。
  4. 每批删除后运行项目自身的测试套件和构建,而不仅是重跑 jscpd:死代码分析证明的是从入口点无法到达该代码,而非删除它不会破坏构建步骤。
  5. 一批之后重跑 --dead-code:一个仅有的导入刚被你删除的文件现在可能自身已死——这种级联是预期的,持续进行直到干净通过,而非只跑一次。
  6. 单独报告你跳过了什么及原因(低置信度、无法排除的理由,或有意保留的死代码如公共库导出),与实际删除的内容分开。

第三步 — 大而复杂的文件

运行 npx jscpd --complexity --reporters ai --summary-top 10 <path>,或与重复和大小一起排名:npx jscpd --reporters ai --summary --summary-by complexity <path>。

cx 是语言感知的圈复杂度估算——大致每个函数一条路径加上每个分支一条(if、循环、&&/||、match/switch 分支、三元和 Elvis 运算符,按语言实际写法计数)——应作为排名信号阅读,而非精确指标。散文和数据文件(Markdown、JSON、YAML、锁文件等)始终得 0 分;大 README 不是重构目标。jscpd 自身的健康分将复杂度 50 或以上的文件视为“复杂”(其死代码式半衰期曲线校准的阈值)——若摘要未明确给出明显截止点,这是“值得阅读”的合理默认值。

工作流:

  1. 取复杂度最高的前 N 个文件(以及从 --summary 形式取大小最大的——一个巨大但低复杂度的文件,如大数据表,与一个小而高复杂度的文件是不同的问题)。
  2. 阅读每个文件并指出实际驱动因素:深层嵌套、一个做多件不相关事情的长函数、针对类型或状态的大型 switch/if 链,或实际上是多个模块粘在一起的文件。
  3. 选择匹配策略:
    • 深层嵌套 → 守卫子句/提前返回,展平快乐路径
    • 长函数、多个职责 → 按职责提取函数,以其功能命名
    • 针对固定用例集(类型、枚举、状态)的分支 → 替换为查找表/映射,或若每个用例已有自己的类型则用多态
    • 文件做太多 → 沿实际接缝拆分(每个文件一个导出组),而非任意按行数切割
  4. 一次重构一个文件;保持行为不变——这是复杂度处理,不是重写。若阅读时发现重复克隆(第一步)或死分支(第二步),仍在其自己的步骤中处理,以便每次变更的原因可追溯。
  5. 对触及的文件重跑 --complexity 确认 cx 确实下降——只移动代码而未减少每函数分支的拆分没有修复任何东西,只是给问题改了名。

第四步 — 确认改进

运行 npx jscpd --health --reporters ai <path>,将分数和等级与第 0 步测量比较。某个维度变差(例如在提取共享复杂度修复时重复又悄悄回来)是重访该步骤的信号,而不仅是记录——重跑相关阶段(--summary、--dead-code、--complexity),而非只信任一个聚合数字。

适用场景

  • 被要求“清理”“改进”“重构”或“偿还技术债”的代码库
  • 需要系统性降低重复代码、死代码和复杂度的项目
  • 希望用可量化的健康分跟踪重构进展的团队

限制

  • 死代码检测需要 JavaScript、TypeScript 或 Python 在代码中占实际比例,否则该维度显示 n/a,应跳过。
  • 复杂度 cx 是估算值,应作为排名信号而非精确指标;散文和数据文件始终得 0 分。
  • 死代码发现低于 90 置信度时可能出错,删除前必须人工验证。
  • 两次运行的健康分只有在基于相同维度构建时才可比较;若某维度因文件构成变化从 n/a 变为已测量(或反之),应说明而非将原始分数差读作改进或回归。
  • 每批删除后需运行项目自身测试和构建,死代码分析不保证删除不会破坏构建步骤。
  • 建议每步单独提交(重复修复、死代码删除、复杂度简化),以便审查者验证“是否确实减少了 X”。
  • 不要在没有先阅读 --dashboard 的情况下对从未见过的代码库运行全部三个阶段——若只有一个维度确实糟糕,在三个维度上平均用力会浪费时间。
  • --health-input 文件(覆盖率、安全扫描结果)可叠加到同一分数,若项目已跟踪这些;它不改变本工作流,只是为第 0 步增加更多维度。