系统化调试
不要猜测-修补。每一步都应缩小Bug可能存在的范围。
1. 复现
- 获取确切的错误信息、堆栈跟踪、日志、输入及环境(版本、操作系统、配置)。
- 使故障可被按需触发,理想情况下通过一条命令或一个测试。如果故障是间歇性的,找出什么因素使其更易出现(负载、时序、顺序、特定输入)。
- 如果无法复现,请说明情况,并在修改代码前收集更多信息。
2. 隔离
- 缩小复现范围:移除输入、步骤和代码,直到移除任何其他内容都会使Bug消失。
- 如果之前能正常工作,找出导致问题的变更:对受影响的文件执行
git log,或使用git bisect run <test command>。 - 从你的代码的顶部开始阅读堆栈跟踪,而不是框架的。
3. 假设和验证
- 写出一个具体的假设:“缓存返回陈旧条目的原因是键忽略了区域设置”。
- 设计一个能证明或推翻该假设的检查:一条日志行、一个断言、一个调试器断点、一个单元测试。在运行前预测结果。
- 如果结果让你意外,那么你对代码的理解就是错误的。在尝试下一个想法之前更新它。
- 一次只改变一件事。回滚没有帮助的实验。
4. 修复原因
- 修复产生错误值的地方,而不是发现它的地方。检查同样的错误是否在其他地方也存在。
- 添加一个回归测试,该测试在修复前失败,修复后通过。
- 删除临时日志和调试代码。
5. 报告
用一两句话解释根本原因、修复方法、验证过程以及任何仍未解释的内容。