systematic-debugging · git:20260905.64eb187 · 2026-09-05 · sha256 66dfe7b2220a0a92
systematic-debugging git:20260905.64eb187A
Immutable. This exact content never changes and is served at /api/v1/blob/66dfe7b2220a0a92.
--- name: systematic-debugging description: 在遇到缺陷、测试失败、构建失败、异常行为或排查卡住时使用。适用于不能靠猜修、需要先定位根因再改代码的场景。 --- # 系统化排查问题 ## 目标 先找到根因,再做修复。 避免“猜一个改一个”的随机试错。 ## 何时使用 - 测试失败 - 构建失败 - 功能行为异常 - 线上或本地缺陷 - 已经试过几次修复但没解决 ## 核心原则 - 先复现,再分析 - 先看证据,再下结论 - 先建立能区分对错的反馈环,再正式修复 - 一次只验证一个假设 - 排障早期可以并行收集互不依赖的证据,但结论必须按证据链收敛 - 修复症状不等于修复根因 - 在改代码前,必须能用一句话说出根因假设 ## 基本流程 1. 读清楚报错和上下文 2. 稳定复现问题 3. 建立能稳定复现失败的反馈环:能稳定失败、能复跑、能在修复后变绿;可以是测试、最小复现命令、脚本、页面操作或日志判定 4. 并行收集互不依赖的证据:日志、配置差异、近期变更、网络/环境状态、相关源码路径 5. 建立假设矩阵,按证据强弱排序 6. 用一句话写出当前最高置信假设:`我认为根因是 X,因为证据 Y` 7. 用最小改动或最小观测手段验证该假设 8. 每轮验证后更新假设矩阵;被证伪的方向不要继续加码 9. 只有在根因明确后才正式修复 ### 反馈环要求 - 没有反馈环时,只能做读取、复现、加观测或缩小范围;不要直接提交修复 - 反馈环必须足够小,能区分当前假设是否成立,不用一开始就跑全量测试 - 如果问题无法本地复现,要写清替代证据:日志模式、线上状态、CI 失败、用户提供的稳定步骤或最小可观察指标 - 修复后必须用同一个反馈环证明问题消失,再按风险补充更宽的验证 ## 常见检查点 - 报错信息、堆栈、日志 - 最近提交或配置变更 - 输入、输出、状态流转 - 环境差异 - 网络路径、端口、DNS、代理、证书、服务发现和防火墙规则 - 是否有现成正常案例可对比 - 是否有最近已知正常版本版本、截图、旧行为或旧产物可当作对照 ## 低层基线 系统、工具链、渲染、网络或生成物问题,先测更低一层的事实,再判断上层症状: - 界面异常先区分 DOM/CSS/渲染层、数据层和状态层 - 网络异常先确认 DNS、代理、证书、端口和服务端响应,再改客户端逻辑 - 编译/工具链异常先确认版本、路径、环境变量和最小命令,再改业务代码 - 生成物异常先确认源文件、生成命令、输出路径和时间戳,再改消费方 ## 假设矩阵 排障超过一个明显路径时,维护一个轻量矩阵: ```text 假设 | 证据 | 置信度 | 下一步检查 | 证伪条件 ``` - `假设`:具体根因,不写“环境问题”这类空泛词。 - `证据`:已有事实,例如日志、配置差异、命令输出、源码条件。 - `置信度`:高 / 中 / 低。 - `下一步检查`:下一步最小验证动作。 - `证伪条件`:什么结果出现时应放弃该方向。 连续两个假设被证伪后,必须回到矩阵重新排序;不要沿着最熟悉的方向继续猜。 ## 可用参考 遇到下面这些问题时,优先参考同目录下的补充文档: - `root-cause-tracing.md`:适用于错误出现在很深的调用链里,需要一路往上追源头。 - `condition-based-waiting.md`:适用于测试或异步逻辑依赖时序,不能靠 sleep 猜等待时间。 - `defense-in-depth.md`:适用于一个问题可能需要多层保护,避免只修一处留下同类缺口。 ## 强化模式 ### 重复回归 / 截图对照模式 适用于: - 用户说“还是不对”“修了但症状没消失” - 用户给了旧截图、旧版本、旧产物作为参考 - 视觉结果以前是对的,现在坏了 处理方式: 1. 列出所有症状,不只盯住第一条。 2. 明确参考基准:旧截图、旧版本、旧提交、预期状态。 3. 先定义通过或失败检查,再决定怎么修。 4. 同样症状在一次修复后仍存在时,立即停止叠补丁,回到证据重新建模。 ### 二分定位模式 适用于用户说“以前是好的”“之前是好的”“某个版本还能用”,或能提供最近已知正常版本。 1. 先保护当前工作区:`git status --short --branch -uall`;有改动时不要在当前检出目录直接二分定位。 2. 先读最近正常版本到当前的相关路径差异;如果范围不大,通常比完整二分定位更快。 3. 必须先定义非交互通过或失败命令;没有可复现检查时,二分定位只会制造噪音。 4. 二分定位得到嫌疑提交后,只读该提交差异,定位引入回归的具体条件。 ### 范围扩散检查 适用于修复一类模式问题后,需要确认仓库里是否还有同型缺陷。 1. 提炼缺陷模式:函数、正则、选择器、锁、校验缺口、输入边界。 2. 在仓库中搜索同类形状。 3. 对每个命中项明确写出:同类问题 / 安全例外 / 还需确认。 4. 不要只修用户指出的那一处就宣布结束。 ### 运行时证据阶梯 宣布修复前,尽量沿这条链路补齐证据: 1. 源码路径:具体到函数、条件、文件或状态转移 2. 稳定复现:最小复现命令、测试、页面路径或输入 3. 运行时证据:日志、状态、缓存、生成物、外部系统反馈 4. 针对性测试或构建 5. 真正的运行结果确认:尤其是界面、渲染、生成物问题 仅编译通过,不足以证明界面、渲染和产物类问题已修好。 ### 定向日志 加日志前先写清楚:这条日志要回答什么问题。 - 第一条日志优先打在执行路径中点,不要直接堆在症状点 - 只记能区分假设的事实:分支、旧值/新值、输入键、错误码、顺序 - 临时日志在结束前移除 - 当假设涉及回调顺序、对象生命周期、异步状态、窗口/导航事件时,日志应作为形成假设的一部分,而不是连续修错后才补 ### 配置修改安全线 排障中修改配置、版本、端口、权限或网络参数前: 1. 记录原值和文件路径。 2. 说明该修改要验证哪个假设。 3. 优先做最小临时变更,不混入无关优化。 4. 验证失败立即回滚,不把失败尝试留在最终状态。 ## 常见错误 - “先随便改一下试试” - 一次改很多地方 - 没复现稳定就开始修 - 只看表面症状 - 连续试了多次还不回头重新分析 - 同样症状没消失,还继续沿着旧假设补丁 - 修好一处就假设其他同类位置也没问题 ## 输出要求 - 问题现象是什么 - 如何复现 - 当前证据指向什么 - 根因假设是什么 - 假设矩阵如何排序,哪些方向已被证伪 - 验证结果是什么 - 最终修复是否已经验证 - 若做了范围扩散检查,要写清还有无同类命中项 ## 关键约束 - 根因没明确前,不要给大幅修复方案 - 连续几次假设都失败时,要停下来重新分析 - 不能把“猜中一次”当成排查方法 - 同样症状在一次修复后仍存在时,必须回到根因分析 - 连续 3 个假设被证据推翻后,先汇总证据和已排除方向,重新选择诊断方法;有可执行且已获授权的下一步时继续,不因失败次数自动结束任务或转为交接 - 同一数值、阈值、间距或超时被调了 3 次还不对时,停止调参,回到结构约束或不变量