关于 same-results-less-code
这是一项代码审查与重构技能,用于发现自动化检查工具难以识别的冗余复杂度。它按优先级提供精简代码的指导,同时要求保持可观察行为不变。
主要功能
- 01按优先级划分重构规则
- 02识别抽象与重复问题
- 03以最小改动保持行为
- 04提供审查与验证流程
适用场景
- 01审查 PR 中可简化的实现
- 02精简不断膨胀的模块
- 03检查陌生代码库中的冗余复杂度
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ pproenca/ dot-skills --skill same-results-less-code安装后在 Claude Code 中输入/same-results-less-code确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
AGENTS.mdmetadata.jsonREADME.mdassets/templates/_template.mdreferences/_sections.mddefense-guard-against-impossible.mddefense-let-it-throw.mddefense-null-pollution-from-bad-modelling.mddefense-validate-once-at-boundary.mdderive-boolean-from-data.mdderive-cache-as-getter-not-field.mdderive-dont-store-computed.mdderive-single-source-of-truth.mdderive-url-as-state.mddup-config-not-copies.mddup-cross-layer-shape.mddup-mirrored-branches.mddup-near-twin-functions.mddup-parallel-types-same-shape.mdframe-composition-over-inheritance-for-shared-fields.mdframe-data-over-procedure.mdframe-function-not-class.mdframe-manager-noun-is-a-verb.mdframe-monolith-by-cohesive-axis.mdproc-build-vs-declarative-template.mdproc-if-chain-as-lookup.mdproc-manual-recursion-of-walk.mdproc-mutation-builder-over-pipeline.mdproc-sequential-awaits-could-be-parallel.mdreinvent-builtin-data-structures.md详细介绍
社区重构最佳实践:结果不变,代码更少
这份代码审查与重构指南聚焦于那些源自判断与建模偏差的代码量:抽象选择不当、隐藏的语义重复、防御性习惯以及过早追求通用性。本指南刻意跳过 knip、eslint、ruff、tsc --noUnusedLocals 等代码检查工具或格式化工具已经能发现的问题。这是第二轮审查:机械式清理之后,还剩下什么?
核心原则
- 保持行为不变。 每次转换都必须产生完全相同的可观察行为——输出、错误、副作用和 API 表面均不变。
- 早期错误会层层放大。 框架选错,会导致结构不当,进而造成逻辑重复。应从生命周期的上游开始优化。
- 解释原因,而不只是做法。 每条规则都说明反模式的代价,让判断力能迁移到新场景。
- 尽可能量化。 相比“更简洁”,优先说明“减少 N 行代码/避免 X 类 Bug”。
- 不要过度重构。 遵循三次原则:重复实际出现三次后再提取抽象,而不是提前预想。
适用场景
在以下情况下使用此技能:
- 审查 PR 时思考“能否更简单?”(这是代码检查工具无法回答的问题)
- 重构代码量不断增加、能力却没有提升的代码
- 审查“感觉很臃肿”的模块——标志很多、层次很多、检查很多
- 熟悉不熟悉的代码库,尝试区分无意增加的代码量与必要的复杂性
- 设计新模块,希望避免常见的过度抽象陷阱
- 配合使用 knip / eslint / ruff,并希望补上这些工具无法提供的判断
以下情况不要使用此技能:
- 代码检查工具或格式化工具已能完成的机械式清理(未使用的导入、无效导出、代码风格)——请改用
knip、eslint、ruff或prettier/black。 - 算法复杂度/性能调优——请改用
complexity-optimizer。 - 不论是否存在思维模型偏差,都要对近期修改的代码进行常规清理——请改用
code-simplifier。
按优先级排列的规则类别
| # | 类别 | 前缀 | 影响 | 规则数 | 概述 |
|---|---|---|---|---|---|
| 1 | 重造已有功能 | reinvent- | 严重 | 5 | 重写平台/标准库已经提供的功能 |
| 2 | 框架选错 | frame- | 严重 | 5 | 抽象结构不当——明明函数就够,却用了类;采用管理器式命名;数据导向场景却使用面向对象 |
| 3 | 隐藏的重复 | dup- | 高 | 5 | 语法不同,语义相同的重复实现 |
| 4 | 存储派生状态 | derive- | 高 | 5 | 存储本应计算得出的内容 |
| 5 | 过程式重建 | proc- | 中高 | 5 | 用命令式代码重新实现声明式概念 |
| 6 | 投机性通用化 | spec- | 中 | 5 | 为从未出现的第二个使用者构建通用性 |
| 7 | 过度防御 | defense- | 中 | 4 | 检查类型或流程已排除的状态 |
| 8 | 未充分利用类型系统 | types- | 低至中 | 6 | 本应由类型表达的运行时防护 |
快速参考
1. 重造已有功能(严重)
reinvent-stdlib-collection-ops— 编写循环前,先考虑使用.map/.filter/.reducereinvent-date-and-time— 不要手动实现日期和时间运算reinvent-deep-equality— 使用真正的深度相等比较工具,而不是手动递归遍历对象reinvent-explicit-state-machine— 明确呈现状态机,而不是来回切换布尔标志reinvent-builtin-data-structures— 识别自定义容器是否只是 Map、Set 或 Queue
2. 错误的框架(CRITICAL)
frame-function-not-class— 如果类没有身份标识,就使用函数frame-manager-noun-is-a-verb— 重命名 Manager/Helper/Util 类,直到体现出真正的动词frame-composition-over-inheritance-for-shared-fields— 组合共享字段,而非通过继承复用frame-data-over-procedure— 先将问题建模为数据,再编写过程frame-monolith-by-cohesive-axis— 沿着内聚轴拆分巨型函数,而非按行数拆分
3. 隐藏的重复(HIGH)
dup-parallel-types-same-shape— 合并结构相同的并行类型dup-near-twin-functions— 将仅在字面量上不同的两个函数参数化dup-mirrored-branches— 将镜像 if/else 分支中的共享代码提取出来dup-config-not-copies— 用一个表替代多处硬编码副本dup-cross-layer-shape— 合并相同的 DTO、数据库行和领域对象
4. 存储派生状态(HIGH)
derive-dont-store-computed— 能计算的就计算;只存储无法计算的内容derive-single-source-of-truth— 选定一个事实来源;从中派生其余内容derive-boolean-from-data— 从数据派生布尔值,不要单独跟踪它们derive-cache-as-getter-not-field— 将缓存字段改为 getter,直到性能分析证明另有必要derive-url-as-state— 让 URL 或路由成为状态,而不是状态的镜像
5. 过程式重建(MEDIUM-HIGH)
proc-mutation-builder-over-pipeline— 当变更构建器掩盖了意图时,改用管道组合proc-if-chain-as-lookup— 用查找表替代返回常量的 if/elif 链proc-manual-recursion-of-walk— 使用公认的树/对象遍历方式,而非手写递归proc-build-vs-declarative-template— 框架提供声明式形式时,就使用它proc-sequential-awaits-could-be-parallel— 并行执行彼此独立的 await
6. 投机性通用设计(MEDIUM)
spec-interface-of-one— 避免为单一实现定义接口spec-options-bag-of-one— 所有调用方都传入相同值时,避免使用选项集合spec-flag-driven-paths— 将被布尔标志拆成两种路径的函数拆分开spec-no-extension-point-without-extender— 删除没有第二个使用方的扩展点spec-generic-over-one-type— 只有一种具体类型使用时,移除泛型参数
7. 防御过度(中)
defense-guard-against-impossible— 不要防范类型或流程已排除的状态defense-validate-once-at-boundary— 在边界处验证一次,内部直接信任defense-let-it-throw— 让异常继续传播;不要捕获自己无法处理的异常defense-null-pollution-from-bad-modelling— 修正导致必须进行空值检查的类型
8. 类型系统利用不足(低至中)
types-discriminated-union-over-flags— 使用可辨识联合,而不是可选字段加标签types-literal-union-over-string— 当取值集合固定时,将string收窄为字面量联合types-no-any-to-silence— 避免使用any/as来压制类型错误types-branding-over-runtime-checks— 为已验证的值添加品牌,避免重复验证types-exhaustive-switch-not-default— 使用穷尽性检查,而不是兜底的 defaulttypes-readonly-and-immutable-by-default— 在确实需要修改之前,将数据标记为readonly
如何应用(工作流)
使用此技能审查或重构代码时:
- 先进行机械检查。
knip/eslint/ruff/tsc --noUnusedLocals可以发现死代码、未使用的导入和风格问题。不要在这里重复这些工作。 - 阅读文件或 PR,理解其意图。 思考:这段代码试图做什么?判断的关键在于识别实现是否超出了意图。
- 按优先级依次检查各类别。
- 提出最小差异的改动。 每条规则都通过紧凑的差异展示错误做法 → 正确做法;建议也应保持这一特点。
- 验证行为。 输出、错误和副作用必须保持一致,测试也必须通过。
- 不要捆绑无关改动。 每项改动都应对应一个类别。混在一起会让审查变得困难。
不适用的情况
- 代码尚未达到“三次法则”(只有一处或两处重复)——此时提取还为时过早。
- 该模式确实属于已知例外(参见每条规则中的“何时不应使用此模式”部分)。
- 重构会变成大型、高风险的改写,且缺少明确可靠的测试保障——应提出建议,而不是直接执行。
- 对性能至关重要的热点路径中,“更简单”的形式会带来可测量的成本——先进行测量。
参考文件
| 文件 | 描述 |
|---|---|
| references/_sections.md | 类别定义和排序 |
| assets/templates/_template.md | 新规则的模板 |
| metadata.json | 版本和参考信息 |
相关技能
code-simplifier— 机械式简化(命名、无用代码、嵌套)。可作为互补的初步处理。complexity-optimizer— 算法与性能复杂度。关注维度不同。refactor— 通用重构工作流。clean-code— 更广泛的整洁代码原则。本技能是其中范围更窄、更注重判断的子集。
评论
支持 Markdown