debugging-by-evidence

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Debugging by Evidence

基于证据的调试

Core principle. The loop is the skill. Everything after it is mechanical.
  • Without a loop the cause stays hidden. No amount of reading the code will find it.
  • The weight sits in the loop and in the five states. Every rule below either sharpens the loop or spends it.
  • You opened this in the middle of something. This is how to do that work, not a replacement for it. Name what you were doing before you start, and return to it when this is done.
核心原则。循环是核心技巧,其余步骤都是机械化操作。
  • 没有循环,原因就会隐藏。仅靠阅读代码无法找到问题根源。
  • 重点在于循环和五种状态。以下每条规则要么优化循环,要么基于循环展开操作。
  • 你是在中途打开这份文档。这是完成当前工作的方法,而非替代原有工作。开始前先明确你之前在做什么,完成后回到原有工作。

No hypothesis before a command that reproduces it

在能复现问题的命令执行前,不要提出假设

  • The command MUST already have been run. A command you wrote down and never ran is not a loop.
  • Its output MUST show the symptom the user reported. A different red line is a different bug.
  • Reading code produces theories nothing can falsify. A theory that cannot fail will survive every test you put it through.
  • The loop is that command plus the state it needs. Record both.
  • 命令必须已执行过。写下来但从未运行的命令不算循环。
  • 命令输出必须能复现用户报告的症状。不同的错误提示对应不同的bug。
  • 阅读代码产生的理论无法被证伪。无法被推翻的理论会在所有测试中“存活”。
  • 循环由命令及其所需状态组成。请同时记录两者。

What you may write, and when

何时可以进行哪些编写操作

  • Until
    EXPLAINED
    the only write you MAY make is instrumentation.
    Every inserted line carries a unique tag, so removal is one search. A fix written earlier destroys the red signal that was going to explain it.
  • Reverting your own change to re-observe the original failure is allowed here. It is often the point. This skill runs experiments.
  • The licence stops at the workspace boundary. No commit. No branch move. No remote or deployment action. Every tag comes out before you close.
  • 在达到
    EXPLAINED
    状态前,仅允许编写埋点代码
    。每一行插入的代码都要有唯一标记,以便通过搜索快速移除。过早编写修复代码会破坏原本能解释问题的错误信号。
  • 允许撤销自己的变更以重新观察原始故障。这往往是关键步骤,本技巧就是要开展实验。
  • 权限仅限于工作区内部。禁止提交、移动分支、远程操作或部署操作。关闭前必须移除所有标记。

Establish before the first run

首次运行前需确认的内容

  • Never ask what the environment answers. Three things settle the setup, and the environment already holds two of them.
    • The symptom in the user's own words, quoted.
    • The command the project already declares for running that surface.
    • Whether the failure is reported as constant or occasional, with a rate where it is occasional.
  • A symptom you restated in your own words is already a hypothesis. Keep the original beside it.
  • 不要询问环境信息。有三件事决定了初始设置,其中两件环境已经提供:
    • 用户原话描述的症状,需引用原文。
    • 项目已定义的、用于运行对应功能的命令。
    • 故障是持续出现还是偶发,若为偶发需记录出现频率。
  • 用自己的话重述症状本身就是一种假设。请将用户原文放在旁边对照。

Which rules to read

应阅读哪些规则

One rule per row. Match the left column against the symptom or the state you are in.
  • The match sets where to start. The loop state sets what you are allowed to do next. Enter at the matched row, then follow the loop states in order.
  • A rule belonging to a state you have not reached is read when you reach it. Not now. Stopping applies from any state and outranks continuing.
  • Where two rows both look like the symptom, read both. Under-reading costs a whole loop. Over-reading costs one file.
If you see...Read
nothing you have run yet shows the symptom, or the loop is slow, noisy, or fails only some of the time
rules/runnable-signal.md
a red loop that drags in far more than the bug: many files, a long sequence, a whole suite
rules/minimising.md
one explanation already feels obvious, or you are about to test the first thing that came to mind
rules/rival-hypotheses.md
you are about to add a log line, a breakpoint, or a temporary edit to see what happens
rules/probing.md
the failure surfaces far from where it starts: a bad value arriving from layers away, already wrong when it lands
rules/fix-at-the-source.md
the cause is explained and a test must now hold it down
rules/regression-seam.md
a third fix attempt just exposed a fourth problem, or the next step needs an observation you cannot make
rules/stopping-and-escalating.md
Discriminators.
  • Signal against minimising. Signal owns a loop that does not reproduce or cannot be trusted. Minimising owns a loop that reproduces but proves too much.
  • Hypotheses against probing. Ranking comes before any run. A probe tests exactly one ranked prediction.
  • Source against seam. Source decides where the fix belongs. Seam decides where its test belongs. Both wait for
    EXPLAINED
    .
Default stance.
  • Get a command to reproduce it before explaining anything.
  • Name the state you are in, and take only what that state licenses.
  • Never assert a cause no run has supported. An untested explanation is labelled as one.
一行对应一条规则。用左列内容匹配你遇到的症状或当前所处状态。
  • 匹配结果决定起始点。循环状态决定了你下一步可执行的操作。从匹配的行开始,然后按循环状态顺序推进。
  • 未到达对应状态时,无需阅读其规则。只有到达该状态时才阅读。无论处于何种状态,停止操作的优先级都高于继续操作。
  • 若两行都符合症状,需阅读两者。漏读会浪费整个循环,多读仅会多查看一个文件。
如果你遇到...阅读
尚未执行任何能复现症状的命令,或者循环过程缓慢、有噪音,或仅偶尔失败
rules/runnable-signal.md
能复现问题的循环涉及范围过大:包含大量文件、冗长流程或整个测试套件
rules/minimising.md
某个解释看起来显而易见,或者你打算测试第一个想到的思路
rules/rival-hypotheses.md
你打算添加日志、断点或临时修改来观察结果
rules/probing.md
故障表现位置与根源位置相差甚远:错误值来自多层之外,到达时已出错
rules/fix-at-the-source.md
原因已明确,需要添加测试防止问题复发
rules/regression-seam.md
第三次修复尝试又引出了第四个问题,或者下一步需要的观察无法实现
rules/stopping-and-escalating.md
判别标准
  • 信号规则 vs 最小化规则:信号规则适用于无法复现或不可信的循环;最小化规则适用于能复现但涉及范围过大的循环。
  • 假设规则 vs 探测规则:先排序假设,再执行探测。每次探测仅测试一个已排序的预测。
  • 根源规则 vs 测试点规则:根源规则决定修复位置,测试点规则决定测试放置位置。两者都需等待
    EXPLAINED
    状态。
默认准则
  • 在解释任何内容前,先找到能复现问题的命令
  • 明确你所处的状态,仅执行该状态允许的操作。
  • 绝不要断言未经运行验证的原因。未测试的解释需明确标记为假设。

Say which loop state you are in

明确你所处的循环状态

Report it every time. Each state licenses only what it names.
StateMeansLicenses
NO-SIGNAL
nothing run yet reproduces itmore attempts at a loop, nothing else
RED
a command reproduces the symptom, deterministically or at a stated ratehypotheses, probes
MINIMISED
removing any remaining element makes it passnaming a cause
EXPLAINED
one surviving hypothesis, each link observeda fix
RESOLVED
the original loop passes unmodified, and the nearest path the fix also touches was runclosing
  • Skipping a state is the failure this skill exists to prevent. You MAY spend as long as you need inside one state.
  • You SHOULD stop building a loop after five attempts and report
    NO-SIGNAL
    instead. Keep going only where you can name what the sixth attempt does differently.
  • NO-SIGNAL
    for long enough is itself the report.
    Say what you tried and what would produce a signal. Never proceed on theory.
  • Know what an empty result means before you trust it. A zero is evidence of absence only from a path that records this event. A path that records nothing, or records only failures, produces the same zero and proves nothing.
每次都要报告。每个状态仅允许执行其指定的操作。
状态含义允许操作
NO-SIGNAL
尚未执行任何能复现症状的命令尝试构建循环,无其他操作
RED
命令可复现症状,确定出现或有明确出现频率提出假设、进行探测
MINIMISED
移除任何剩余元素都会使测试通过确定问题原因
EXPLAINED
仅存一个假设,且每个环节都已验证进行修复
RESOLVED
原始循环未修改即可通过,且修复涉及的最近路径已运行结束调试
  • 跳过状态是本技巧要避免的错误。你可以在一个状态上花费任意时间。
  • 尝试构建循环五次后应停止,并报告
    NO-SIGNAL
    。只有当你能明确说明第六次尝试的不同之处时,才继续尝试。
  • 长时间处于
    NO-SIGNAL
    状态本身就是报告内容
    。说明你尝试过的方法,以及能产生信号的条件。绝不要仅凭理论推进。
  • 在信任空结果前,先明确其含义。只有在记录该事件的路径中,零结果才代表“未出现”;而无记录或仅记录失败的路径,产生的零结果无法证明任何事。

What makes a cause a cause

如何定义“原因”

All four hold, or it is a hypothesis and is labelled one.
  • A run at
    RED
    or better produced it.
    Not a reading of the code.
  • Each link from trigger to symptom cites an exact
    file:line
    .
  • One prediction it made was tested and could have failed.
  • It explains the whole symptom. That includes the part that seems incidental.
Three words carry their usual weight.
  • Confirmed. A probe result you observed.
  • Inference. A hypothesis nothing has tested yet.
  • Gap. An observation you could not reach. Name what would close it.
  • Say what the evidence does not establish. A cause that explains the failure and nothing about its timing has one link missing, not zero.
必须满足以下四点,否则只能被标记为假设
  • RED
    或更高状态下的运行结果得出
    。而非仅靠阅读代码。
  • 从触发点到症状的每个环节都能精确到
    file:line
  • 其做出的某个预测已被测试,且该测试可能失败
  • 能解释全部症状,包括看似无关的部分。
三个术语的含义
  • 已确认:你观察到的探测结果。
  • 推论:尚未被验证的假设。
  • 缺口:无法观察到的环节。说明能填补缺口的观察内容。
  • 明确说明证据未证实的内容:能解释故障但无法解释其出现时机的原因,仍存在一个未验证的环节。

When to stop instead of trying again

何时应停止尝试

  • Three attempted fixes that each reveal a new problem elsewhere are not a fourth attempt. They are the finding.
  • The shape is wrong. The report says so, and those three attempts are its evidence.
  • One thing you cannot observe stops the run the same way. Name it. Name the observation that would settle it. Then stop, because debugging around an unknown produces a fix nobody can defend.
  • 三次修复尝试每次都引发新问题时,不应进行第四次尝试。这本身就是发现的问题。
  • 问题形态异常。报告中需说明这一点,三次尝试的结果就是证据。
  • 某个无法观察的因素持续终止运行。说明该因素,以及能解决问题的观察内容。然后停止调试,因为围绕未知因素的调试会产生无人能维护的修复方案。

Output contract

输出规范

Symptom      as reported, in the user's words, and the loop that shows it
Loop state   one of the five, plus the reproduction rate where it is not 1
Ruled out    each rejected hypothesis with the observation that killed it
Cause        one line per causal link, each at file:line
Not shown    what this evidence leaves open
Fix          the change, and the seam the regression test sits in
Proof        the original loop re-run unmodified, the nearest adjacent path
             also run, and every probe tag removed
  • Report what you observed, not what you avoided.
  • Never open with "fixed". The reader needs the chain first. A fix stated before its cause reads as a guess that happened to work, and sometimes it is one.
Symptom      用户原话描述的症状,以及能复现它的循环
Loop state   五种状态之一,非100%复现时需注明出现频率
Ruled out    每个被排除的假设,以及证伪它的观察结果
Cause        每个因果环节各占一行,均标注file:line
Not shown    本证据未覆盖的内容
Fix          修复变更,以及回归测试的放置位置
Proof        原始循环未修改重新运行的结果、修复涉及的最近路径运行结果,以及所有探测标记已移除的证明
  • 报告你观察到的内容,而非你避开的内容
  • 不要以“已修复”开头。读者需要先看到因果链。先说明修复再讲原因,会让人觉得这只是碰巧有效的猜测,有时事实确实如此。

Do not skip this when

以下情况绝不能跳过本流程

  • The cause seems obvious. That is the anchor this skill exists to break.
  • Someone already told you what is broken. That is a hypothesis, not a signal.
  • The fix is one line. A one-line fix to the wrong line is still wrong.
  • You are in a hurry. Guessing is what produces the second and third attempt.
  • 原因看似显而易见。这正是本技巧要打破的思维定式。
  • 有人已经告诉你问题出在哪。这只是假设,不是信号。
  • 修复只需一行代码。修复错误位置的一行代码仍然是错误的。
  • 你很赶时间。猜测会导致第二次、第三次尝试。

Routing

流程指引

  • The table above selects the rule and its order. Read a selected rule in full, interpret it yourself, and say which one you opened in one line.
  • Rival explanations MAY be tested in parallel. Ranking them and judging what a result means is not delegated.
  • A direct instruction from the user outranks anything here.
  • Once a fix exists it stops being a symptom and becomes a change. Hand it to a review of the diff rather than judging it here.
  • 上述表格决定规则及顺序。完整阅读选中的规则,自行解读,并在一行内说明你打开了哪条规则。
  • 可并行测试多种对立解释。但排序和判断结果含义的工作不能委托他人。
  • 用户的直接指令优先级高于本技巧的所有规则
  • 修复完成后,它不再是症状而是变更。应提交diff审核,而非在此评估。