系统化调试

作者:鹿Sir开发工具v1

在遇到任何Bug、测试失败或异常行为时,先定位根因再修复,避免盲目尝试。当用户需要调试代码、排查测试失败、定位Bug根因时触发。触发词:调试、Bug排查、根因分析、测试失败。

下载量
267
点赞
67
价格
免费

技能文档

---
name: boisenoise-superpowers-systematic-debugging
title: 系统化调试
category: 开发工具
description: 在遇到任何Bug、测试失败或异常行为时,先定位根因再修复,避免盲目尝试。当用户需要调试代码、排查测试失败、定位Bug根因时触发。触发词:调试、Bug排查、根因分析、测试失败。
---

# 系统化调试

## 概述

随机修复浪费时间并引入新 Bug。快速补丁掩盖底层问题。

**核心原则:** 在尝试修复之前,务必先找到根因。修复表象即是失败。

**违背此流程的字面意义就是违背调试的精神。**

## 铁律

```
未经根因调查,不得进行任何修复
```

如果你没有完成第一阶段,就不能提出修复方案。

## 何时使用

适用于任何技术问题:
- 测试失败
- 生产环境 Bug
- 异常行为
- 性能问题
- 构建失败
- 集成问题

**尤其在以下情况下使用:**
- 时间紧迫(紧急情况使猜测变得诱人)
- "只是一个快速修复"看起来很明显
- 你已经尝试了多次修复
- 之前的修复没有生效
- 你没有完全理解问题

**不要在以下情况跳过:**
- 问题看起来很简单(简单 Bug 也有根因)
- 你很着急(赶时间只会导致返工)
- 负责人要求立刻修复(系统化方法比反复试错更快)

## 四个阶段

你必须完成每个阶段后才能进入下一阶段。

### 第一阶段:根因调查

**在尝试任何修复之前:**

1. **仔细阅读错误信息**
   - 不要跳过错误或警告
   - 它们通常包含确切的解决方案
   - 完整阅读堆栈跟踪
   - 记录行号、文件路径、错误代码

2. **稳定复现**
   - 你能可靠地触发它吗?
   - 具体步骤是什么?
   - 每次都会发生吗?
   - 如果无法复现 → 收集更多数据,不要猜测

3. **检查近期变更**
   - 什么变更可能导致了这个问题?
   - Git diff、最近的提交
   - 新依赖项、配置变更
   - 环境差异

4. **在多组件系统中收集证据**

   **当系统有多个组件(CI → 构建 → 签名,API → 服务 → 数据库)时:**

   **在提出修复方案之前,添加诊断插桩:**
   ```
   对于每个组件边界:
     - 记录进入组件的数据
     - 记录离开组件的数据
     - 验证环境/配置的传播
     - 检查每一层的状态

   运行一次以收集证据,显示在哪里断裂
   然后分析证据以识别故障组件
   然后调查该特定组件
   ```

   **示例(多层系统):**
   ```bash
   # 第 1 层:工作流
   echo "=== 工作流中可用的密钥:==="
   echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}"

   # 第 2 层:构建脚本
   echo "=== 构建脚本中的环境变量:==="
   env | grep IDENTITY || echo "IDENTITY not in environment"

   # 第 3 层:签名脚本
   echo "=== 钥匙串状态:==="
   security list-keychains
   security find-identity -v

   # 第 4 层:实际签名
   codesign --sign "$IDENTITY" --verbose=4 "$APP"
   ```

   **这揭示了:** 哪一层失败(密钥 → 工作流 ✓,工作流 → 构建 ✗)

5. **追踪数据流**

   **当错误深在调用栈中时:**

   参见本目录 `references/root-cause-tracing.md` 获取完整的反向追踪技术。

   **简要版本:**
   - 错误值源自哪里?
   - 是什么用错误值调用了这里?
   - 持续向上追踪直到找到源头
   - 在源头修复,而非在表象处

### 第二阶段:模式分析

**在修复之前找到模式:**

1. **找到可工作的示例**
   - 在同一代码库中找到类似的可工作代码
   - 什么与损坏的部分类似但能正常工作?

2. **与参考对比**
   - 如果在实现某个模式,完整阅读参考实现
   - 不要略读——阅读每一行
   - 在应用之前完全理解该模式

3. **识别差异**
   - 可工作的与损坏的之间有什么不同?
   - 列出每一个差异,无论多小
   - 不要假设"那不重要"

4. **理解依赖关系**
   - 这需要哪些其他组件?
   - 什么设置、配置、环境?
   - 它做了什么假设?

### 第三阶段:假设与测试

**科学方法:**

1. **形成单一假设**
   - 清楚陈述:"我认为 X 是根因,因为 Y"
   - 写下来
   - 要具体,不要模糊

2. **最小化测试**
   - 做最小的可能变更来测试假设
   - 一次一个变量
   - 不要同时修复多个问题

3. **验证后继续**
   - 成功了吗?是 → 第四阶段
   - 没成功?形成新假设
   - 不要在上面叠加更多修复

4. **当你不确定时**
   - 说"我不理解 X"
   - 不要假装知道
   - 寻求帮助
   - 做更多研究

### 第四阶段:实施

**修复根因,而非表象:**

1. **创建失败测试用例**
   - 最简单的可能复现
   - 尽可能使用自动化测试
   - 没有框架时用一次性测试脚本
   - 修复前必须有测试

2. **实施单一修复**
   - 解决已识别的根因
   - 一次一个变更
   - 不要"顺便"做改进
   - 不要捆绑重构

3. **验证修复**
   - 测试现在通过了吗?
   - 没有其他测试被破坏吧?
   - 问题真的解决了吗?

4. **如果修复不起作用**
   - 停下来
   - 计数:你已经尝试了多少次修复?
   - 如果 < 3 次:返回第一阶段,用新信息重新分析
   - **如果 ≥ 3 次:停下来,质疑架构(见下方第 5 步)**
   - 在没有讨论架构之前,不要尝试第 4 次修复

5. **如果 3 次以上修复失败:质疑架构**

   **表明架构问题的模式:**
   - 每次修复都揭示新的共享状态/耦合/不同位置的问题
   - 修复需要"大规模重构"才能实施
   - 每次修复都在其他地方产生新症状

   **停下来质疑基本假设:**
   - 这个模式从根本上是否合理?
   - 我们是否"只是因为惯性而坚持"?
   - 应该重构架构还是继续修复表象?

   **在尝试更多修复之前与你的搭档讨论**

   这不是假设失败——这是架构错误。

## 危险信号——停下来遵循流程

如果你发现自己在想:
- "先快速修复,以后再调查"
- "试试改 X 看看是否有效"
- "加多个变更,跑测试"
- "跳过测试,我手动验证"
- "可能是 X,让我修复它"
- "我不完全理解但这可能有效"
- "模式说是 X 但我用不同方式适配"
- "这是主要问题:[在未调查的情况下列出修复]"
- 在追踪数据流之前就提出解决方案
- **"再试一次修复"(已经尝试了 2 次以上)**
- **每次修复都在不同地方揭示新问题**

**以上所有情况意味着:停下来。返回第一阶段。**

**如果 3 次以上修复失败:** 质疑架构(见第四阶段第 5 步)

## 搭档发出的"你做错了"信号

**注意这些引导:**
- "那不是没发生吗?"——你在没有验证的情况下做了假设
- "它会显示给我们……吗?"——你应该添加证据收集
- "别猜了"——你在没有理解的情况下提出修复
- "深入想想"——质疑根本问题,而非仅仅是表象
- "我们卡住了?"(沮丧)——你的方法不起作用

**当你看到这些时:停下来。返回第一阶段。**

## 常见借口

| 借口 | 现实 |
|--------|---------|
| "问题很简单,不需要流程" | 简单问题也有根因。流程对简单 Bug 很快。 |
| "紧急情况,没时间走流程" | 系统化调试比猜测式反复试错更快。 |
| "先试这个,然后再调查" | 第一次修复设定了模式。从一开始就做对。 |
| "我先确认修复有效再写测试" | 未经测试的修复不可靠。先写测试来证明。 |
| "同时修复多个问题节省时间" | 无法隔离什么起了作用。会引入新 Bug。 |
| "参考太长了,我来适配这个模式" | 部分理解保证会出 Bug。完整阅读。 |
| "我看到问题了,让我修复它" | 看到表象 ≠ 理解根因。 |
| "再试一次修复"(2 次以上失败后) | 3 次以上失败 = 架构问题。质疑模式,不要再修。 |

## 快速参考

| 阶段 | 关键活动 | 成功标准 |
|-------|---------------|------------------|
| **1. 根因** | 阅读错误、复现、检查变更、收集证据 | 理解是什么以及为什么 |
| **2. 模式** | 找到可工作的示例、对比 | 识别差异 |
| **3. 假设** | 形成理论、最小化测试 | 确认或形成新假设 |
| **4. 实施** | 创建测试、修复、验证 | Bug 解决,测试通过 |

## 当流程揭示"没有根因"时

如果系统化调查揭示问题确实是环境相关的、时序依赖的或外部的:

1. 你已经完成了流程
2. 记录你调查了什么
3. 实施适当的处理(重试、超时、错误消息)
4. 添加监控/日志以供未来调查

**但是:** 95% 的"没有根因"案例是调查不彻底。

## 辅助技术

这些技术是系统化调试的组成部分,可在本目录中找到:

- **`references/root-cause-tracing.md`** — 通过调用栈反向追踪 Bug 以找到原始触发点
- **`references/defense-in-depth.md`** — 在找到根因后在多个层添加验证
- **`references/condition-based-waiting.md`** — 用条件轮询替代任意超时

## 实际效果

来自调试实践:
- 系统化方法:15-30 分钟修复
- 随机修复方法:2-3 小时反复试错
- 首次修复成功率:95% vs 40%
- 引入新 Bug:几乎为零 vs 经常发生

使用说明

# 系统化调试

在遇到任何 Bug、测试失败或异常行为时,先定位根因再修复,避免盲目尝试和随机修复。

## 使用

在调试代码或排查问题时,遵循四阶段系统化流程:

```
用户:这个测试一直失败,我试了三次修复都不行
助手:已尝试 3 次修复 → 触发系统化调试流程

1. 根因调查:阅读错误信息、复现问题、检查近期变更
2. 模式分析:找到可工作的示例并对比差异
3. 假设测试:形成单一假设,最小化验证
4. 实施修复:创建失败测试 → 修复根因 → 验证通过
```

## 工作原理

核心铁律:未经根因调查,不得进行任何修复。四个阶段必须顺序完成,每阶段有明确的成功标准。当 3 次以上修复失败时,强制质疑架构而非继续修补。辅助技术包括反向追踪、纵深防御和条件等待。

如何安装此技能?

访问技能市场,点击「安装」按钮,按提示将技能包放入 AI 编程助手的 skills 目录即可。

浏览技能市场

支持平台:Qoder · QoderWork · Claude · Codex 等 AI 编程助手