mcpField
S
systematic-debugging

systematic-debugging

github.com/tmdgusya开发12547 次安装17 周前更新
代码仓库

关于 systematic-debugging

systematic-debugging 是用于处理缺陷、测试失败和异常行为的调试流程技能。它要求先复现问题、建立测试或等效验证手段并提出根因假设,再进行针对性修复。

主要功能

  1. 01定义并复现故障
  2. 02在系统边界收集证据
  3. 03一次验证一个根因假设
  4. 04修复前锁定故障
  5. 05修复后沿相同路径验证

适用场景

  1. 01调查失败的测试
  2. 02复现生产或本地缺陷
  3. 03追查间歇性故障或性能下降

安装

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

$npx skills add https://github.com/tmdgusya/engineering-discipline --skill systematic-debugging

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

condition-based-waiting-example.ts
condition-based-waiting.md
defense-in-depth.md
find-polluter.sh
root-cause-tracing.md

详细介绍

系统化调试

严格的调试工作流。遇到 Bug、测试失败或意外行为时使用。

三个核心目的:

  1. 修复根因,而非表象。
  2. 避免基于猜测进行修复。
  3. 修复前先用测试锁定故障。

硬性门槛

这些规则没有例外。

  1. 在获得可复现或可观察的状态之前,不要修复。
  2. 在陈述根因假设之前,不要修复。
  3. 在获得失败测试或等效复现机制之前,不要修复。
  4. 一次只验证一个假设。
  5. 修复时不得顺手重构。
  6. 如果三次修复尝试都失败,应先怀疑结构性问题,再应用其他补丁。

违反此流程即视为调试失败。

何时使用

在以下情况下使用此技能:

  • 测试失败时
  • 线上或本地出现 Bug 时
  • 响应、状态、渲染或查询结果与预期不符时
  • 调查性能下降、超时、竞态条件或间歇性故障时
  • 某个问题至少修复过一次后再次出现时

以下借口不可接受:

  • “看起来很简单,我直接修一下”
  • “没时间了,先打个补丁再说”
  • “可能是这个原因,我先改改看”

必需的输出约定

使用此技能时,必须在内部明确以下事项:

  1. 问题陈述:用一句话说明出了什么问题
  2. 复现路径:如何复现或观察故障
  3. 证据:实际观察到的结果
  4. 根因假设:你认为问题发生的原因
  5. 失败防护:以下其中一项:失败的测试、复现脚本或日志验证
  6. 修复:针对根因进行的一项修复
  7. 验证:修复后的复现路径和相关测试结果

缺少以上七项中的任何一项,都说明工作尚未完成。

工作流

按顺序执行以下步骤。

阶段 1. 定义问题

首先,简要概括问题。

  • 预期行为是什么
  • 观察到的行为是什么
  • 影响范围是什么
  • 问题总能复现,还是间歇性出现

输出格式:

Problem: <expected> but got <actual> under <condition>

不要把症状与猜测混在一起。

Good: Product detail API returns 500 when brand is null.
Bad: Serializer is broken because brand mapping seems wrong.
阶段 2. 复现或添加检测

修复前,你必须能够再次看到故障。

优先级:

  1. 使用现有测试复现
  2. 使用最小集成测试复现
  3. 使用单元测试复现
  4. 通过复现脚本或命令观察
  5. 添加日志或检测后观察

规则:

  • 尽可能简化复现路径。
  • 即使 Bug 只在 UI 中可见,也应尽可能优先在更低层复现。
  • 对于间歇性故障,通过添加日志、捕获输入、时间戳和并发条件来提高可观察性。
  • 如果无法复现,不要继续修复,而应提高可观察性。

无法复现时的处理方法:

  1. 记录输入值
  2. 检查环境差异
  3. 检查近期变更
  4. 在边界点添加日志
  5. 查找能产生相同症状的更小条件
阶段 3. 收集证据

只收集可观察的事实。

务必检查:

  • 完整的错误消息和堆栈跟踪
  • 失败时的输入值
  • 最近修改过的文件或提交
  • 环境/配置差异
  • 调用路径和数据流

对于多组件问题,应检查每个边界。

示例:

  • 控制器 -> 应用程序 -> 服务 -> 存储库
  • 客户端 -> API -> 外部服务
  • 调度器 -> 批处理服务 -> 数据库

在每个边界,检查:

  • 输入了什么
  • 输出了什么
  • 哪些值发生了转换
  • 在什么条件下会出错

在确定问题所在位置之前,不要修复。

阶段 4:隔离根因

只提出一个原因假设。

格式:

Hypothesis: <root cause> because <evidence>

好的假设具备以下特点:

  • 指向单一原因
  • 与观察到的证据相关联
  • 可以通过小型实验证伪

不好的假设示例:

  • “某处似乎存在一些异步问题”
  • “整个序列化层似乎不稳定”

将原因追溯到源头。如果错误出现在调用栈深处,应追溯输入的来源,而不是症状。

阶段 5:锁定故障

修复前先锁定故障。

优先顺序:

  1. 自动化失败测试
  2. 在现有测试中添加回归用例
  3. 最小复现脚本
  4. 通过日志或断言进行临时验证

规则:

  • 尽可能创建自动化测试。
  • 修复前,测试必须失败。
  • 修复后,同一路径上的测试必须通过。
  • 测试名称必须揭示问题所在。

如果可以编写自动化测试,请同时使用 test-driven-development 技能。

阶段 6:实施单一修复

修复只针对一个假设。

允许:

  • 直接解决原因的最小代码改动
  • 验证所需的最小辅助改动

禁止:

  • 捆绑多个看似相关的修复
  • 将重构与修复合并
  • 顺带进行格式调整、清理或重命名
  • 在没有证据的情况下添加空值保护
  • 吞掉异常

如果修复失败,请立即返回阶段 1 或阶段 3。此前的假设是错误的。

阶段 7:验证并收尾

收尾前必须满足以下所有条件:

  1. 原始复现路径不再失败。
  2. 新增的失败保护测试通过。
  3. 相关测试未被破坏。
  4. 你能解释该修复阻止的是原因,而非症状。

对于间歇性 Bug,仅通过一次还不够。必须在重复运行或不同条件下进行验证。

停止条件

出现以下情况时,请停止并重新审视问题。

1. 复现失败

如果多次尝试后仍无法复现:

  • 检查可观测性是否不足。
  • 检查环境是否存在差异。
  • 检查问题定义是否有误。

禁止在无法复现的情况下修改代码。

2. 三次修复失败

如果连续三次修复都未能解决问题,则应得出结论:

  • 当前理解有误,或
  • 问题可能具有结构性,例如共享状态、边界设计、职责划分

从这时起,“第四次补丁”并不能解决问题,需要进行结构性讨论。

3. 没有失败保护

如果无法创建失败测试或等效的复现机制,就不要宣称任务已完成。至少应留下复现命令和观察结果。

危险信号

如果出现以下任何想法,请立即停止并返回前一阶段。

  • “我只要改这一行,应该就能解决”
  • “我稍后再看日志,先修复再说”
  • “我之后再添加测试”
  • “我把这两个问题一起修复吧”
  • “错误消失了,所以不需要弄清原因”

最简检查清单

执行过程中使用此清单进行自我检查。

  • 用一句话定义问题
  • 复现问题或让故障变得可观测
  • 收集证据
  • 创建单一根因假设
  • 修复前创建失败保护
  • 只实施单一修复
  • 修复后通过相同路径进行验证

完成标准

此技能的完成标准不是“代码已更改”。

完成标准:

  • 问题定义清晰
  • 修复前已锁定故障
  • 修复与根因相关联
  • 保留验证结果

若未满足这四项,调试就尚未完成。

评论

支持 Markdown