关于 fable-simplify
fable-simplify 是用于简化代码的 Skill,通过小步改动和验证来保持外部行为及公共契约不变,适合有明确边界的重构与清理。
主要功能
- 01定义行为保持契约
- 02记录基线测试与证据
- 03删除前验证代码可达性
- 04分步进行可审查的重构
- 05完成后重新验证并评审
适用场景
- 01在保持行为不变时减少重复逻辑
- 02逐步扁平化复杂控制流
- 03验证可达性后删除过时代码
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ immamdouhaboammar/ get-fable --skill fable-simplify安装后在 Claude Code 中输入/fable-simplify确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
skill.package.jsonagents/openai.yamlevals/scenarios.jsonexamples/flatten-nested-logic.mdreferences/behavior-preserving-refactor-strategy.mdrefactoring-patterns.mdtemplates/simplification-plan.template.md详细介绍
Fable Simplify
降低意外复杂性,同时证明外部相关行为和契约未发生变化。
使命
简化并不意味着可以大范围重写。应通过小规模、易审查的转换,让代码更易于推理,并以特征测试/不变量证据为依据。
“更整洁”是主观的。行为保持不变、重复/分支/间接层减少,以及所有权更清晰,都可以通过证据加以证明。
适用场景
- 重复逻辑带来分歧风险;
- 嵌套/控制流复杂性掩盖了不变量;
- 已证明死代码/过时的间接层未被使用;
- 明确要求重构,且不打算改变行为;
- 已完成的实现需要在审查前进行范围受限的清理。
不适用场景
- 计划改变用户可见行为/API/架构(使用
fable-tdd/fable-execute); - 对行为的描述不足以确保行为保持不变;
- 正在重新设计架构本身(使用
fable-plan); - 清理机会与当前卡片无关。
简化分类
| 异味 | 首选安全做法 |
|---|---|
| 重复行为 | 证明等价性,提取共享规则 |
| 嵌套分支 | 确定决策表/不变量,逐步扁平化 |
| 死代码 | 证明其不可从运行时/注册/反射路径到达 |
| 包装器/间接层 | 在折叠之前证明调用方/语义 |
| 数据转换链 | 描述代表性输入和边界输入的行为 |
| 公共/内部 API 杂乱 | 保留公共契约;在边界之后简化 |
| 生成代码噪声 | 修改生成器/源代码,而不是手动修改输出 |
流程
阶段 1 — 确立行为保持契约
说明哪些内容不得改变:
- 公共输入/输出/错误;
- 副作用/状态转换;
- 契约要求的序列化/顺序/时序;
- 包/API/CLI 兼容性;
- 如有实质影响,列明性能要求。
采集基线测试/固件/运行时证据。若覆盖不足,应在结构性修改之前添加特征测试。
阶段 2 — 确定要消除的复杂性
具体指出复杂性:重复条件、不必要的分支、死适配器、重复解析、所有权分散、过时的兼容路径。
避免将“现代化这个模块”作为没有边界的目标。
阶段 3 — 删除前证明可达性/死代码
搜索调用方,以及动态注册/插件/反射/生成路径。对于可能动态加载的代码,仅凭“grep 未找到导入”并不足够。
阶段 4 — 每次进行一个语义步骤的重构
示例:
- 提取共享的纯规则;
- 将嵌套分支替换为明确的守卫条件/决策表;
- 折叠契约相同的包装器;
- 证明不可达后移除死分支。
每个有实质意义的步骤之后,都运行范围最小的行为保持检查。
阶段 5 — 留意意外的契约变更
检查差异,留意以下变化:
- 调用方依赖的异常/错误类型或消息发生变化;
- 迭代/顺序发生变化;
- 真值/空值语义发生变化;
- 求值从惰性变为急切,或反之;
- 异步顺序发生变化;
- 事务/清理操作发生移动;
- 公共导出/签名/默认值发生变化;
- 如有要求,性能/资源行为发生变化。
阶段 6 — 如实衡量简化效果
有用的证据包括:
- 重复规则/分支减少;
- 公共接口范围缩小;
- 状态/间接层减少;
- 不变量归属更明确。
行数本身不是质量指标。
阶段 7 — 重新验证并审查
完成最后一次重构修改后,重新运行受影响部分的验证,并进行独立的差异审查。重构前通过的基线对于简化后的代码已不再有效。
决策规则
- 对行为丰富的旧代码,如果没有特征化测试/证明 → 先补上,再进行重构。
- 删除死代码前,必须确认其运行时不可达,包括动态注册表/插件。
- 如果简化过程中发现需要改变行为,应将其拆分为单独的 TDD/执行卡片。
- 优先采用少量可逆的转换,而不是从头重写。
- 即使会增加代码行数,也不要合并代表真实领域/所有权边界的抽象。
- 如果两段相似代码编码了不同的未来不变量,就不要为了 DRY 而合并;语法相同并不总意味着概念相同。
- 如果测试失败,应诊断是重构改变了行为,还是测试与内部实现耦合;不要盲目回退或更新断言。
不变量
- 已接受的外部行为保持不变。
- 公共契约不会意外偏移。
- 每项转换都可审查且有证据支持。
- 无关清理不纳入范围。
- 删除代码前会考虑动态/生成式可达性。
- 最终修改后会重新进行验证。
失败类型
行为偏移
重构改变了输出/错误/状态/顺序。恢复不变量,或将预期的行为变更拆分出来。
测试耦合
测试失败是因为断言了内部结构,而非契约。根据已接受的行为,而非个人偏好,判断应修改测试还是代码。
误判为死代码
动态注册/反射/插件路径仍能访问该代码。恢复代码,并改进可发现性的证据。
抽象坍塌
被移除的层编码了真实边界/不变量。应重新引入更清晰的边界,而非单纯减少代码行数。
范围蔓延
重构扩展到了架构/功能工作。停止并拆分/重新规划。
复杂度转移
局部代码变短了,但复杂度转移到了调用方/配置/通用抽象中。应评估整个受影响的决策范围。
反模式
- 为了“简化”而从头重写模块;
- 将代码行数作为主要成功指标;
- 因为没有静态导入就删除代码;
- 将语义不同的规则抽取为 DRY 代码;
- 在清理期间更改 API 签名;
- 未检查契约就更新测试以匹配重构;
- 在功能开发后捆绑无关清理;
- 用巧妙的通用抽象替代明确的领域逻辑。
简化方案包
Preservation contract:
Baseline evidence:
Complexity targeted:
Reachability/deadness evidence:
Transformations:
Risky semantic deltas checked:
Fresh verification:
Review result:
Measured simplification:
Deferred behavior changes:
完成标准
满足以下条件时,简化工作即告完成:
- 复杂度的降低具体且范围明确;
- 行为/公共契约已特征化并得到保留;
- 删除/重构的可达性假设有依据;
- 最终证据是最新的;
- 独立审查未发现隐蔽的行为偏移;
- 清理工作中未夹带无关的行为变更。
渐进式资源
- 深入指南:
references/behavior-preserving-refactor-strategy.md - 现有模式:
references/refactoring-patterns.md - 示例:
examples/flatten-nested-logic.md