mcpField
S
systematic-debugging

systematic-debugging

github.com/bhagyamudgal开发2103 次安装5 天前更新
代码仓库

关于 systematic-debugging

面向开发者的调试技能,将排查分为根因调查、模式对比、假设测试和实施。它要求先以证据定位问题再修复,并在多次修复失败时重新审视设计。

主要功能

  1. 01读取错误并稳定复现问题
  2. 02沿数据流追溯问题源头
  3. 03比较正常与异常的实现模式
  4. 04测试排序后的可证伪假设
  5. 05修复前编写回归测试
  6. 06多次修复失败后升级讨论

适用场景

  1. 01修改代码前调查故障原因
  2. 02查明错误数据进入系统的位置
  3. 03通过小规模测试验证不同解释
  4. 04修复屡次失败后重新评估方案

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bhagyamudgal/skills --skill systematic-debugging

安装后在 Claude Code 中输入/systematic-debugging确认已加载。

附带文件TECHNIQUES.md

详细介绍

系统化调试

这是调试过程中的中间阶段所需遵循的准则。找到根本原因,证明它,然后一次性修复。

铁律

NO FIXES WITHOUT ROOT-CAUSE INVESTIGATION FIRST

不理解的修复不算修复,只是在拖延。如果你无法解释修复为何有效,就说明还没找到原因。停下来,追踪实际的代码路径。

每个 PR 的权宜修补额度为零。如果你确实找不到根本原因,就坦言这一点并寻求帮助。

四个阶段

完成当前阶段后再进入下一阶段。

阶段 1:根本原因调查

尝试任何修复之前:

  1. 阅读错误消息。这是第零步。堆栈跟踪会告诉你出错的代码行,错误消息会告诉你哪个不变量遭到了破坏。阅读输出中的每条错误和警告。它们往往包含确切答案。
  2. 稳定地复现问题。构建复现循环的操作指南见 /diagnosing-bugs 阶段 2。
  3. 检查最近的更改。查看 git diff、最近的提交、新依赖项、配置更改和环境差异。
  4. 为边界添加检测。在多组件系统中,记录进入和离开每个边界的内容,并验证环境和配置是否正确传递。在任何内容写入日志之前,先对机密、令牌、凭据和个人数据进行脱敏。保留名称和大小等元数据,绝不记录值。例如,CI 到构建再到签名,以及 API 到服务再到数据库。运行一次并查看证据。它会显示链路在哪一环中断。例如,证据可能表明机密已传递到工作流,但没有传递到构建环节。接下来就调查该组件。完整技巧:TECHNIQUES.md。
  5. 反向追踪数据流。当错误出现在调用栈深处时,崩溃位置只是症状。错误值从何而来?继续向上追踪,直到找到源头,并在那里修复。

当你能指出产生错误值的代码行,以及导致它出错的输入时,阶段 1 才算完成。如果你只能指出崩溃的位置,就还没完成。

出现以下任何一种情况,都意味着阶段 1 尚未完成:

  • 添加空值检查。问问自己为什么这里会是空值,以及它是否应该为空。
  • 用 try-catch 包装一个来历不明的错误。只捕获你理解且能够处理的错误。
  • 使用 as any、as unknown 或 @ts-ignore。修复类型,不要掩盖问题。
  • 延长超时时间或添加重试。问问究竟是什么变慢了,或者发生了竞争。如果罪魁祸首是时序不稳定的测试,请参阅 TECHNIQUES.md。
  • 修改失败的测试,让它通过。测试通常是正确的,所以修改之前先弄清楚它为何失败。如果它昨天还正确,而你的更改让它失败了,那就应该怀疑你的更改。
阶段 2:模式分析

修复之前先找出模式:

  1. 查找可正常运行的示例。在同一代码库中找到类似的可用代码。
  2. 对照参考实现。实现一种模式时,要逐行完整阅读参考实现,不要粗略浏览。理解不完整必然会导致错误。
  3. 列出正常代码和故障代码之间的所有差异,无论多么细微。在排除之前,将每个差异都视为可能原因。

当你能说出用来对照的正常示例,并且解释清单上的每项差异时,阶段 2 才算完成;每项差异都必须有证据排除,或作为假设带入阶段 3。如果没有找到可用示例,或仍有差异无法解释,就还没完成。

阶段 3:假设与测试

科学方法:

  1. 按优先级列出 3-5 个可证伪的假设,然后测试优先级最高的一个。每个假设都要说明其预测。例如:“如果 X 是原因,那么更改 Y 就会让 Bug 消失。”把它们写下来。预测可能失败,解释则不会。
  2. 尽量精简地测试。做出能验证假设的最小更改。每次运行只更改一个变量,以便结果能明确指向原因。
  3. 验证后再继续。假设得到证实后,进入阶段 4。否则,在测试下一个假设之前,先撤销失败的修复。
  4. 不知道时就直说。“我不理解 X”胜过假装明白。继续调研或寻求帮助。
阶段 4:实施

修复根本原因,而不是表面症状:

  1. 修复前先编写回归测试。将复现过程转化为失败测试,并先观察它失败。顺序至关重要。修复后编写的测试无法证明 Bug 的存在。具体操作由 /diagnosing-bugs 阶段 5 负责。
  2. 单一修复。处理已确定的根本原因。差异中只包含针对根本原因的修复。
  3. 验证。测试通过,没有其他测试失败,而且问题确实已解决。然后运行 /done。
  4. 每次尝试时都记录,格式为“尝试 N | 假设 | 结果”。第三次失败后,停止修复,并与用户讨论架构问题。
  5. 将 3 次失败的修复视为架构问题,而非假设不成立。迹象包括:每次修复都会在别处暴露新的共享状态或耦合,修复需要“大规模重构”,或者每次修复都会在其他地方引发新症状。询问这种模式是否从根本上合理,还是你只是惯性地沿用它。

从源头修复后,逐层添加验证。相关技术见 TECHNIQUES.md。

警示信号:停止并返回阶段 1

如果你发现自己在想以下任何一条:

  • “先快速修复,之后再调查”
  • “先试着改改 X,看能不能解决”
  • 同时更改多项内容,然后再运行测试
  • “可能是 X,我来修一下”,但没有证据
  • “我并不完全理解,但也许能行”
  • 尚未追踪数据流就开始列出修复方案
  • 为测试失败“其实不重要”找理由
  • 已经失败 2 次或更多,却还在想“再试一次修复”
  • 每次修复都会在不同位置暴露出一个新问题

用户表示你在猜测,例如“这不是没有发生吗?”、“这会让我们看到……吗?”、“别猜了”,都意味着同一件事。返回阶段 1。

调查发现“没有根本原因”时

如果系统性调查表明,问题确实由环境引起、依赖时序或来自外部,那么你已经完成了调查流程。记录你调查过的内容,然后实施重试、超时或明确错误等处理措施,并说明:

  1. 该处理措施应对的故障模式
  2. 为什么无法在上游避免该问题
  3. 处理措施本身失败时会发生什么

添加监控,以便跟踪下次发生情况。大多数“没有根本原因”的情况其实是调查不充分。在得出这个结论之前,请检查阶段 1 的标准。

评论

支持 Markdown