Systematic Debugging 是一套面向调试工作的技能,用于在遇到任何 bug、测试失败或异常行为时,先完成根因调查再提出修复方案。
适用场景
该技能适用于任何技术问题,包括测试失败、生产环境 bug、意外行为、性能问题、构建失败和集成问题。以下情况尤其需要使用:时间压力下(紧急情况容易让人倾向于猜测)、看似只需“快速修一下”、已经尝试过多次修复、前一次修复没有生效、尚未完全理解问题。也不应因为问题看起来简单、自己很急或上级要求立刻修复而跳过流程,因为简单问题同样有根因,系统性调试比反复试错更快。
核心原则
核心原则是:必须先找到根本原因再尝试修复,只修复症状属于失败。技能提出一条“铁律”:没有先做根因调查,就不允许提出修复方案。如果尚未完成第一阶段,就不能提出修复。
四个阶段
必须完成前一阶段后才能进入下一阶段。
第一阶段:根因调查。在尝试任何修复之前,要仔细阅读错误信息,不跳过错误或警告,完整阅读堆栈跟踪,记录行号、文件路径和错误码;稳定复现问题,确认是否每次都能触发、具体步骤是什么,如果无法复现,就继续收集数据而不要猜测;检查近期变更,包括 git diff、最近提交、新依赖、配置改动和环境差异;在多组件系统(如 CI → 构建 → 签名、API → 服务 → 数据库)中,先在每个组件边界添加诊断插桩,记录进入和离开组件的数据、验证环境与配置传递、检查各层状态,运行一次以收集证据显示问题出在哪一层,再分析证据定位失败组件,最后调查该组件;当错误位于调用栈深处时,可参考本目录中的 root-cause-tracing.md 进行完整的反向追溯,快速方法是追问坏值从何而来、谁用坏值调用了它,一直向上追溯到源头,并在源头修复而非在症状处修复。
第二阶段:模式分析。修复前先找模式,包括在同一代码库中寻找类似的可工作代码、如果实现某种模式则完整阅读参考实现(不要略读)、列出工作代码与出错代码之间的每一处差异(无论多小,不要假设“那不可能有影响”)、理解依赖关系(需要哪些其他组件、哪些设置、配置和环境、做了哪些假设)。
第三阶段:假设与测试。采用科学方法:提出单一假设,明确写下“我认为 X 是根本原因,因为 Y”,要具体而非模糊;做最小化测试,用尽可能小的改动验证假设,一次只改一个变量,不要同时修复多个问题;继续之前先验证,如果成功则进入第四阶段,如果不成功则形成新假设,不要在原有修复上叠加更多修复;当自己不知道时,要明说“我不理解 X”,不要假装知道,可以寻求帮助或做更多研究。
第四阶段:实施。针对根因而非症状进行修复:先创建失败测试用例,使用最简单的复现方式,可能的话写成自动化测试,没有框架时可用一次性测试脚本,修复前必须先有它;如需编写正确的失败测试,可使用 superpowers:test-driven-development 技能;然后实施单一修复,针对已识别的根因,一次只做一处改动,不做“顺便改一下”的改进,也不捆绑重构;最后验证修复,确认测试现在通过、其他测试没有被破坏、问题确实得到解决,在声称成功之前可使用 superpowers:verification-before-completion 技能。
如果修复无效
应立即停止并计数已尝试的修复次数。若少于 3 次,返回第一阶段,结合新信息重新分析;若达到或超过 3 次,停止并质疑架构,不要在没有架构讨论的情况下尝试第 4 次修复。三次以上修复失败通常意味着架构问题,其模式包括:每次修复都在不同位置暴露新的共享状态、耦合或问题;修复需要“大规模重构”才能实施;每次修复都在别处制造新症状。此时应停止并质疑根本问题:这种模式是否根本合理、是否只是出于惯性在坚持、应该重构架构还是继续修复症状,并在尝试更多修复之前与人类搭档讨论。这不是假设失败,而是架构错误。
危险信号
如果发现自己出现以下想法,应立即停止并回到流程:先快速修复、稍后再调查;先改一下 X 看看是否有效;同时添加多个改动再运行测试;跳过测试、手动验证;大概是 X 的问题,直接修它;虽然不太理解但这样可能有用;模式说是 X 但我换个方式改;先列出主要问题(未经调查就列出修复方案);在追溯数据流之前就提出解决方案;已经试过两次以上还要“再修一次”;每次修复都在不同位置暴露新问题。
人类搭档的纠正信号
如果人类搭档说“那不是没发生吗”(说明你未经验证就做了假设)、“它会显示给我们看吗”(说明你应该增加证据收集)、“别猜了”(说明你在未理解的情况下提出修复)、“超深度思考一下”(说明应质疑根本问题而不只是症状)、“我们卡住了吗”(表示你的方法无效),都应停止并返回第一阶段。
常见借口与现实
“问题很简单,不需要流程”——简单问题也有根因,流程对简单 bug 很快。“紧急,没时间走流程”——系统性调试比反复猜测试错更快。“先试这个,再调查”——第一次修复会设定模式,应从开始就做对。“先确认修复有效再写测试”——未经测试的修复不会稳固,测试先行才能证明。“同时做多个修复省时间”——无法隔离哪个生效,还会引入新 bug。“参考太长,我按自己理解改”——部分理解必然导致 bug,要完整阅读。“我看到问题了,直接修”——看到症状不等于理解根因。“再修一次”(在两次以上失败后)——三次以上失败是架构问题,应质疑模式而不是继续修复。
快速参考
第一阶段根因:阅读错误、复现、检查变更、收集证据,成功标准是理解 WHAT 和 WHY。第二阶段模式:寻找可工作示例并比较,成功标准是找出差异。第三阶段假设:形成理论并最小化测试,成功标准是确认或形成新假设。第四阶段实施:创建测试、修复、验证,成功标准是 bug 解决且测试通过。
流程揭示“没有根因”时
如果系统性调查发现问题确实是环境性、时序相关或外部因素导致的,则说明流程已完成:记录调查内容,实施适当的处理方式(重试、超时、错误信息),并添加监控或日志以便未来调查。但需注意,95% 的“没有根因”情况其实是调查不完整。
配套技术
本目录还提供配套技术文档:root-cause-tracing.md 用于通过调用栈反向追溯 bug 以找到最初的触发点;defense-in-depth.md 用于在找到根因后于多个层级添加校验;condition-based-waiting.md 用于用条件轮询替代任意超时。