principle-fix-root-causes

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Fix Root Causes

修复根因

When debugging, fix the fault, not the place where it surfaced. The symptom is where a wrong state became visible. The root cause is the first place the system did something it should not do, or failed to handle a state it should handle.
Why: A symptom fix hides the evidence and leaves the fault free to surface somewhere else. Each one makes the system harder to reason about, because the code now carries a workaround for a bug that nobody named.
Pattern:
  • Reproduce first.
  • Ask "why" at each step until the answer is a wrong decision in the code, not a consequence of an earlier one.
  • When stuck, instrument. Read the actual error and the actual state. Do not guess.
  • Ask whether the state that triggered the symptom is legitimate. If the system may be in that state, the code that broke on it is the root cause, and handling the state there is the fix. If the state should never exist, a check where it broke hides the bug. Find what produced the state. Guards, retries, swallowed errors, clamped values, and discarded state are the usual ways to hide a bug.
  • When something fails only after a restart, suspect persisted state first: config files, caches, lock files, serialized state.
  • Check for the pattern, not just the instance. Find every place with the same fault and fix them all.
  • If a workaround needs a paragraph-long comment to justify it, the code is wrong. Fix the code, not the comment.
  • If the deciding fact took a deep dig to find, propose the cheap, always-on signal that would have shown it at first look.
调试时,应修复故障本身,而不是症状显现之处。症状是错误状态开始变得可见的位置;根因则是系统首次执行了不应执行的操作,或未能处理本应能够处理的状态的位置。
原因: 修复症状会隐藏证据,并使故障得以在别处再次出现。每一次这样的修复都会让系统更难理解,因为代码中又多了一个用于掩盖未被发现缺陷的变通方案。
模式:
  • 首先复现问题。
  • 在每一步都追问“为什么”,直到答案指向代码中的错误决策,而不是更早决策所造成的后果。
  • 遇到困难时,添加观测埋点。读取实际错误和实际状态,不要猜测。
  • 判断触发症状的状态是否合法。如果系统可能处于该状态,那么在该状态下失效的代码就是根因,在这里处理该状态才是修复。如果该状态本就不应存在,那么在失效处添加检查只会掩盖缺陷;应找出产生该状态的原因。防御检查、重试、吞掉错误、限制数值范围和丢弃状态,通常都是掩盖缺陷的常见方式。
  • 如果某问题只在重启后出现,应首先怀疑持久化状态:配置文件、缓存、锁文件和序列化状态。
  • 检查问题模式,而不只是单个实例。找出所有存在相同缺陷的位置,并全部修复。
  • 如果一个变通方案需要用一整段注释来证明其合理性,那么代码本身就是错误的。应该修复代码,而不是注释。
  • 如果决定问题性质的事实需要深入挖掘才能找到,应提出一种低成本、始终开启的信号,使该事实在第一眼就能被看到。