← ClaudeAtlas

systematic-debugginglisted

遇到 bug、测试失败、行为异常时使用。先定位根因,再改代码,禁止瞎试。
Wade-DevCode/awesome-coding-skills-cn · ★ 3 · Code & Development · score 78
Install: claude install-skill Wade-DevCode/awesome-coding-skills-cn
# 系统化调试 ## 何时用 - 运行测试时出现 `FAILED` / `ERROR`,或 CI 红了。 - 程序行为与预期不符:输出值错误、接口返回异常状态码、UI 渲染出错。 - 改了一处代码后原本正常的功能突然挂掉(回归)。 - 看到报错信息、异常堆栈、日志中的 `Exception` / `panic` / `Segfault`,不知道从哪里下手。 ## 核心规则 ### 1. 先复现 **规则:** 在动任何代码之前,先稳定复现问题,写下复现步骤与"期望行为 vs 实际行为"。 **为什么:** AI 拿到 bug 描述后会立刻联想到"可能是 X 原因"并直接改代码——但如果问题根本无法稳定复现,改动就是在打空拳。更常见的事故是:AI 改了某处,恰好该次运行没触发 bug,就宣称"已修复",下次复现时问题依然存在。 **怎么做:** - 明确记录触发条件:输入数据、环境变量、调用顺序、并发时序等。 - 写一个最小复现脚本或测试用例,能稳定触发问题再继续。 - 若问题无法稳定复现,先补充日志/断言,下一次触发时收集更多信息,而非盲猜。 --- ### 2. 读真实报错 **规则:** 逐字阅读错误信息与完整堆栈,定位第一处出错的文件行号,不跳过、不脑补。 **为什么:** AI 经常只看错误的最后一行(如 `NullPointerException`),然后凭直觉猜"是不是哪个对象没初始化"并随意修改。真正的根因往往藏在堆栈中部——例如某个中间件吞掉了原始异常、某个工厂方法返回了错误类型——只读最后一行会让修复方向完全偏离。 **怎么做:** - 从堆栈的**最顶层**(第一次抛出点)开始读,而不是从底层的框架代码开始。 - 遇到"Caused by"或"wrapped"链式异常,追到链条的根源。 - 把报错的关键词(函数名、行号、错误码)直接复制到搜索或代码跳转,不凭记忆定位。 --- ### 3. 二分缩小范围 **规则:** 用打印/断点/注释二分法,把问题缩小到最小代码段,再下结论。 **为什么:** AI 倾向于在读了几十行代码后就"觉得问题在这里",跳过验证直接改。这种直觉经常错:真实 bug 往往在你以为不可能出错的地方。不二分就不改,是避免"修了半天发现改错位置"的唯一可靠方法。 **怎么做:** - 把可疑范围一分为二:注释掉后半段,确认前半段输出正确,再检查后半段。 - 在关键中间点插入 `print` / `console.log` / `assert`,确认数据在此时的真实状态。 - 重复缩小,直到能用不超过 10 行代码稳定触发问题,再动手修复。 --- ### 4. 找根因,不贴补丁 **规则:** 能解释"为什么会错"之后再动手改代码。禁止用 `try/except` 吞异常、随机调参、加 `|| null` 等掩盖症状的做法。 **为什么:** AI 面对报错时最常见的逃生路线就是在外层套一个 `try/except`,让异常不再抛出,然后声称"问题解决了"。但根因没消除:数据仍然损坏、状态仍然不一致,只是沉默了。这类"修复"在生产环境会演变成更难排查的数据问题或静默错误。 **怎么做:** - 改代码前用一句话写下根因假设:「变量 `user` 在首次调用时为 `None`,因为 `db.find()` 在记录不存在时返回 `None` 而非抛出异常。」 - 修复根因(加校验、修初始化逻辑),而不是在调用处加 `try/except` 掩盖。 - 若确实需要捕获