Systematic debugging
当遇到任何 bug、测试失败或意外行为时,在提出修复之前必须使用From its SKILL.md
npx -y skills add jnlk-cn/superpowers-cn --skill systematic-debuggingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
9.6 KB, as published. Nobody here has run it
系统性调试(Systematic Debugging)
概述
随机修复只会浪费时间并引入新 bug。临时补丁会掩盖根本问题。
核心原则: 必须先找到根本原因,再尝试修复。只修症状就是失败。
违背流程的字面要求,就是违背调试的精神。
铁律
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
如果尚未完成第一阶段,就不能提出修复方案。
何时使用
适用于任何技术问题:
- 测试失败
- 线上 bug
- 意外行为
- 性能问题
- 构建失败
- 集成问题
尤其在以下情况下使用:
- 时间紧迫时(紧急情况下更容易产生猜测的冲动)
- "先快速修一下"看似显而易见
- 你已经尝试过多种修复
- 上一次修复没有奏效
- 你尚未完全理解问题
不要跳过此流程的情况:
- 问题看起来很简单(简单 bug 也有根本原因)
- 你很着急(赶工必然导致返工)
- 经理要求立刻修复(系统化处理比反复试错更快)
四个阶段
必须按顺序完成每个阶段,然后才能进入下一阶段。
第一阶段:根本原因调查
在尝试任何修复之前:
-
仔细阅读错误信息
- 不要跳过错误或警告
- 它们往往已经给出了解决方案
- 完整阅读堆栈跟踪
- 记录行号、文件路径、错误码
-
稳定复现问题
- 能否可靠地触发它?
- 复现的精确步骤是什么?
- 每次都发生吗?
- 如果无法复现 → 收集更多数据,不要猜测
-
检查近期变更
- 哪些变更可能导致这个问题?
- Git diff、最近的提交
- 新依赖、配置变更
- 环境差异
-
在 multi-component 系统中收集证据
当系统包含多个组件时(CI → build → signing、API → service → database):
在提出修复方案之前,先添加诊断埋点:
对于每个组件边界: - 记录进入组件的数据 - 记录离开组件的数据 - 验证环境/配置传递 - 检查每一层的状态 运行一次以收集证据,定位故障位置 然后分析证据,确定具体失效的组件 再针对该组件深入调查示例(多层系统):
# Layer 1: Workflow echo "=== Secrets available in workflow: ===" echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}" # Layer 2: Build script echo "=== Env vars in build script: ===" env | grep IDENTITY || echo "IDENTITY not in environment" # Layer 3: Signing script echo "=== Keychain state: ===" security list-keychains security find-identity -v # Layer 4: Actual signing codesign --sign "$IDENTITY" --verbose=4 "$APP"这会揭示: 哪一层出错(secrets → workflow ✓,workflow → build ✗)
-
追踪数据流
当错误出现在调用栈深处时:
请参阅本目录中的
root-cause-tracing.md,了解完整的反向追踪技术。快速版本:
- 错误值最初从哪里产生?
- 是谁用错误值调用了这里?
- 不断向上追踪,直到找到源头
- 在源头修复,而不是在症状处修复
第二阶段:模式分析
在修复之前先找到模式:
-
寻找可运行的示例
- 在同一代码库中找到类似的可运行代码
- 哪些正常工作的内容与出问题的内容相似?
-
与参考实现对比
- 如果是在实现某种模式,请完整阅读参考实现
- 不要略读,逐行阅读
- 在应用之前充分理解该模式
-
识别差异
- 正常代码与故障代码之间有什么不同?
- 列出每一个差异,无论多小
- 不要假设"那个应该没关系"
-
理解依赖关系
- 这个组件依赖哪些其他组件?
- 需要哪些设置、配置、环境?
- 它做出了哪些假设?
第三阶段:假设与验证
使用科学方法:
-
形成单一假设
- 清楚表述:"我认为 X 是根本原因,因为 Y"
- 把它写下来
- 要具体,不要含糊
-
最小化验证
- 只做最小的改动来验证假设
- 一次只改变一个变量
- 不要同时修复多个问题
-
验证后再继续
- 有效吗?有效 → 进入第四阶段
- 无效吗?提出新假设
- 不要在此基础上叠加更多修复
-
当你不确定时
- 说"我不理解 X"
- 不要假装知道
- 寻求帮助
- 进一步研究
第四阶段:实施
修复根本原因,而不是症状:
-
创建失败的测试用例
- 最简单的可复现形式
- 如果可能,使用自动化测试
- 如果没有测试框架,编写一次性测试脚本
- 修复前必须有
- 编写规范的失败测试时,使用
superpowers:test-driven-developmentskill
-
实施单一修复
- 针对已识别的根本原因
- 一次只改一处
- 不要"顺便"做改进
- 不要打包重构
-
验证修复
- 测试现在通过了吗?
- 其他测试没有损坏吗?
- 问题确实解决了吗?
-
如果修复无效
- 停下来
- 统计:你已经尝试过多少次修复?
- 如果少于 3 次:回到第一阶段,用新信息重新分析
- 如果达到或超过 3 次:停下来,审视架构(见下文第 5 步)
- 在没有进行架构讨论前,不要尝试第 4 次修复
-
如果 3 次以上修复失败:质疑架构
表明存在架构问题的迹象:
- 每次修复都会在不同位置暴露出新的共享状态/耦合/问题
- 修复需要"大规模重构"才能实现
- 每次修复都会在其他地方引发新症状
停下来并质疑根本问题:
- 这种模式从根本上是否合理?
- 我们是否只是"出于惯性在坚持"?
- 我们应该重构架构,还是继续修症状?
在尝试更多修复之前,先与人类伙伴讨论
这不是假设失败,而是架构错误。
危险信号 —— 停下来并遵循流程
如果你发现自己这样想:
- "先临时修一下,以后再调查"
- "试试改 X 看看有没有用"
- "一次性改多个地方,然后跑测试"
- "跳过测试,我手动验证一下"
- "很可能是 X,我来修它"
- "我不太理解,但这样可能有用"
- "模式要求 X,但我会以不同方式适配"
- "主要问题是这些:[列出修复方案但没有调查]"
- 在追踪数据流之前就提出解决方案
- "再试一次修复"(已经失败 2 次以上时)
- 每次修复都在不同位置暴露出新问题
以上任何一条都意味着:停下来,回到第一阶段。
如果 3 次以上修复失败: 质疑架构(见第四阶段第 5 步)
人类伙伴提示你做错事的信号
注意这些引导语:
- "Is that not happening?" - 你没有验证就做了假设
- "Will it show us...?" - 你本应该添加证据收集
- "Stop guessing" - 你在没有理解的情况下就提出修复
- "Ultra-think this" - 要质疑根本问题,而不只是症状
- "We're stuck?"(不耐烦地)- 你的方法行不通
当你看到这些信号时: 停下来,回到第一阶段。
常见借口
| 借口 | 事实 |
|---|---|
| "问题很简单,不需要流程" | 简单问题也有根本原因。流程对简单 bug 同样快速。 |
| "情况紧急,没时间按流程" | 系统性调试比猜测式试错更快。 |
| "先试一下这个,不行再调查" | 第一次修复就会定下调子。从一开始就要做对。 |
| "等确认修复有效后再写测试" | 未经测试的修复无法保持。先写测试才能证明问题。 |
| "一次性改多处更省时间" | 无法隔离真正起作用的改动,还会引入新 bug。 |
| "参考太长,我按理解适配一下" | 一知半解必然导致 bug。必须完整阅读。 |
| "我看到问题了,我来修" | 看到症状 ≠ 理解根本原因。 |
| "再试一次修复"(已失败 2 次以上) | 3 次以上失败 = 架构问题。要质疑模式,而不是继续修。 |
快速参考
| 阶段 | 关键活动 | 成功标准 |
|---|---|---|
| 1. 根本原因 | 阅读错误、复现、检查变更、收集证据 | 理解 WHAT 和 WHY |
| 2. 模式分析 | 寻找可运行示例、对比 | 识别差异 |
| 3. 假设验证 | 形成理论、最小化验证 | 假设被证实或提出新假设 |
| 4. 实施 | 创建测试、修复、验证 | bug 解决、测试通过 |
当流程显示"没有根本原因"
如果系统调查显示问题确实是环境相关、时序相关或外部因素:
- 你已经完成了流程
- 记录你调查过的内容
- 实施适当的处理(重试、超时、错误信息)
- 添加监控/日志,便于未来调查
但是: 95% 的"没有根本原因"都是调查不完整。
支持技术
这些技术是系统性调试的一部分,本目录下均有相关文件:
root-cause-tracing.md- 从调用栈反向追踪 bug,找到原始触发点defense-in-depth.md- 找到根本原因后,在多层添加校验condition-based-waiting.md- 用条件轮询替代任意超时
相关 skill:
- superpowers:test-driven-development - 用于创建失败测试用例(第四阶段第 1 步)
- superpowers:verification-before-completion - 在声称成功前验证修复有效
实际影响
来自真实调试会话的数据:
- 系统化处理:15-30 分钟修复
- 随机修复方式:2-3 小时折腾
- 首次修复成功率:95% 对比 40%
- 引入的新 bug:几乎为零 对比 常见