Skip to content
返回构建教程

调试策略

采用可复现方法(二分、隔离、假设)而非试错式微调。

为什么

随机微调——注释行、换值、重启服务——感觉高效但极少找到根因。它们靠巧合掩盖 bug(重试消失)或把它移到别处(症状变但原因在)。可复现方法把调试从迷信变工程:你提假设、设计可证伪实验、留日志避免重复死胡同。最大省时是 git bisect——log(N) 步找到引入 bug 的精确提交而非读 diff。无方法的团队在硬 bug 上多花 3 倍时间,且常以两周后回归的方式'修'它。

何时使用

第一个硬 bug 之前。学方法 30 分钟,每 bug 省数小时。永不跳过。

如何做

1. 可靠复现——不能复现的 bug 不能修
   - 写触发它的失败测试;不能则缩步骤直到能
   - 记精确环境(node 版本、env、DB 状态)非"我机器上能跑"

2. 提假设并写下再行动
   - "空引用因用户在 profile 迁移前创建"
   - 写下的假设可证伪;模糊直觉不可

3. 隔离变量——一次改一个
   - 禁一半中间件;bug 在则因在另一半
   - git bisect 找引入提交:git bisect start && git bisect bad HEAD && git bisect good v1.0

4. 检视非假设——读实际值
   - console.log / debugger 在边界非深处
   - 查 DB 行、网络响应、env——bug 通常在数据跨边界处

5. 修因非症——验证测试过且持续绿
   - 加回归测试让此 bug 永不回
   - 若修是"加 null 检查",问为何值是 null 并修那

示例

# 复现:触发 bug 的失败测试
test("迁移前创建的用户不崩", () => {
  const user = factory.user({ createdAt: "2024-01-01", profileId: null });
  expect(() => renderProfile(user)).not.toThrow();
});

# bisect 找引入提交
git bisect start
git bisect bad HEAD              # 当前坏
git bisect good v1.4.0           # v1.4.0 好
# git 检出提交;你标好/坏;100 提交约 7 步缩范围

# 假设日志(调查时留 DEBUG.md)
# 2024-03-15 14:30  H1: 空 profileId——证伪,v1.2 起有守卫
# 2024-03-15 14:45  H2: user.create 与 profile.create 竞态——证实

常见问题

  • ⚠一次改 3 处,bug 消失,不知哪个修的——后回归。
  • ⚠dev 热重载调试,模块状态过时 bug 不复现——浪费 1 小时追幻影。
  • ⚠读代码非运行时值——bug 几乎总在代码实际做而非看似说。
  • ⚠跳回归测试,3 月后重构重引入同 bug。

最佳实践

  • ✓每调查留 DEBUG.md:时间戳、假设、实验、结果——把 4 小时追变 bug 回时 30 分钟读。
  • ✓早用 git bisect;免费且对数时间找精确提交,无需读 diff。
  • ✓修在 PR 同加回归测试,链接永久可审。
  • ✓修是守卫(null 检查、try/catch)时,再花 10 分钟找坏值为何到守卫——守卫藏真 bug。