核心原則

第 1 次失敗是運氣、第 2 次失敗是訊號。 同一個問題、同一個方向、同一類錯誤出現第 2 次時、停下來把處理層級升一階 — 不要繼續用同層方法第 3 次嘗試。第 1 次失敗的資訊不足以判斷「這條路是否值得繼續」、第 2 次提供「在同類條件下重複失敗」的證據、值得付出升級成本。


為什麼是 2 次、不是 1 次或 3 次

1 次失敗的資訊量不足

第 1 次失敗時可能的原因:

原因應對
實作細節錯了(typo、API 用錯)修細節再試一次
假設在邊界 case 不成立微調假設
路徑本身錯了換路徑
環境因素(cache、暫時性問題)重試

第 1 次失敗無法區分這四種 — 證據量不夠做決策。預設用最便宜的應對(修細節重試)是合理的。

2 次失敗的證據量足夠

同方向第 2 次失敗、四種原因中三種被排除:

原因還可能嗎
實作細節錯了否 — 第 2 次已經修過
邊界 case否 — 第 2 次的 case 不一樣、仍然失敗
環境因素否 — 兩次環境不同仍失敗
路徑本身錯了 — 唯一沒排除的選項

第 2 次失敗 ≈ 「路徑本身有問題」的證據。繼續用同層方法第 3 次嘗試 = 忽略這個證據。

3 次以上是浪費

到第 3 次嘗試還沒升級、表示已經錯過訊號。每次失敗的學習回報遞減、執行者的耐心遞減、心智負擔累積。事後檢視常常會發現:「第 2 次就該停了、第 4 次才停浪費了兩輪」。

為什麼不是 1 次就升級

預防式升級成本太高 — 大部分問題第 1 次嘗試就解決。如果每次失敗都立刻升級、會在「修個 typo 就好」的場景過度反應。門檻定在 2 = 不過度反應、又不錯過真訊號


三個應用面向

「2 次門檻」不是單一規則、是一條跨層級套用的元規則。三個典型升級方向:

應用 1:推理 → 量測(#11 在開發循環裡早一點用 playwright

情境:CSS 行為跟預期不符、靜態推理該怎麼改。

嘗試次數成本曲線
第 1 次推理低 — 假設對時一次到位
第 2 次推理高 — 假設錯了得重來、多輪試錯

升級:停止靜態推理、用 playwright browser_evaluate 直接讀 live DOM。把「四個變數(CSS / DOM / 繼承 / framework)」中假設的部分變成已知。

應用 2:手動驗證 → 自動化測試(#15 用前端測試把排版問題自動化

情境:版型 bug 已經 debug 過、未來是否會回歸。

出現次數處理方式
第 1 次修完即可、不寫測試
第 2 次表示這地方容易壞、寫測試固化契約

升級:把手動「改 CSS → 開頁面看」的驗證迴圈、換成 playwright 測試。下次有人改 CSS 立刻紅、不用人記得回歸驗證。

應用 3:同方向嘗試 → 換思路(#20 同方向反覆失敗的轉折點

情境:用 grid 解某個 layout 問題、第一次沒解決。

嘗試次數處理方式
第 1 次 grid 失敗微調 grid 參數重試
第 2 次 grid 失敗停下來假設「grid 本身可能不對」、改用 absolute / flex

升級:從「同層 retry」升到「換思路」。第 2 次失敗的訊號是「底層假設可能錯」、不是「再調一次參數就行」。


識別「同方向」:避免誤判 2 次門檻

「2 次失敗」必須是同方向才算門檻。誤判同方向會錯誤觸發升級、誤判不同方向會錯過真訊號。

同方向的判準

維度同方向不同方向
假設基礎共用同一假設換了核心假設
工具層同一抽象層換到不同抽象層
失敗模式同類錯誤訊息 / 症狀完全不同的失敗

判讀問題:「兩次嘗試的差異、有沒有挑戰底層假設?」

  • 沒有 → 同方向、第 2 次失敗 = 升級訊號
  • 有 → 不同方向、相當於兩次第 1 次嘗試、繼續嘗試合理

反例:誤判為同方向

第 1 次:用 grid-row: 1 把 drawer 放到第一列、失敗 第 2 次:用 grid-row: 1 / span 2 跨兩列、失敗

兩次都基於「drawer 是 grid item」的假設 — 是同方向。第 2 次該停下來檢查這個假設(drawer 實際是 form 子節點、不是 grid item)。

反例:誤判為不同方向

第 1 次:寫 CSS 試 第 2 次:寫 JS 試(覺得「這算換工具」)

但兩次都基於「drawer 在 grid 第一列」的目標 — 假設沒變、只換了實作工具。仍是同方向。


不該套用 2 次門檻的情境

這條原則有適用範圍、不是所有失敗都套用:

情境為什麼不套用
探索性學習新技術學習過程的失敗本身有價值、不是訊號
已知 flaky 的測試 / 環境失敗來自環境、不是路徑問題
嘗試次數很便宜(< 1 秒)預設成本太低、3-5 次嘗試比升級便宜
真正的不同方向(換假設換工具)計數歸零、重新從第 1 次開始

核心判準:升級成本 vs 繼續嘗試成本的比較。當每次嘗試都很貴(人類幾分鐘 / 來回溝通 / 上下文切換)、2 次就該升級;當嘗試很便宜、可以放寬到 3-5 次。


內在屬性比較:四種失敗回應

策略效率風險
第 1 次失敗就升級低 — 過度反應、簡單問題複雜化低 — 但放棄太多便宜路徑
第 2 次失敗升級高 — 平衡不過度反應與不錯失訊號
第 4-5 次才升級低 — 浪費前 3 次的時間中 — 累積心智負擔
不升級、無限試最低 — 在錯方向裡打轉高 — 可能永遠到不了正解

推薦:第 2 次失敗升級。例外情境(探索 / flaky)顯式判斷再放寬。


跨情境辨識訊號表

下次工作中看到這些訊號、回想「2 次門檻」:

訊號在做什麼升級到
「我覺得改這個應該就好了」第 2 次靜態推理量測(#11)
「上次也是這個 bug」手動驗證自動化測試(#15)
「再調一次 grid 參數」第 2 次同方向嘗試換思路(#20)
「再加一條 CSS 應該就蓋過了」第 2 次specificity 戰換維度(#24 CSS Layers
「再多寫一個 if 處理這 case」第 2 次patch 補丁看是否該重新設計

通用形式:「再做一次同方向的 X」第 2 次出現 = 該升級的訊號。


對應的實作篇

每篇示範這個原則的不同面向、各自展開具體場景:

升級方向場景特徵
#11 早一點用 playwright推理 → 量測CSS 行為跟預期不符
#15 用前端測試把排版自動化手動驗證 → 自動化同版型 bug 第 2 次
#20 同方向反覆失敗的轉折點同層 retry → 換思路同方向第 2 次失敗
#23 驗證方法的選擇時機被動等指令 → 主動提工具反覆試錯時的溝通

讀的時候從本篇出發、依場景挑實作篇 — 不需要逐篇讀完。


判讀徵兆

訊號自問回應
「再試一次同方向應該就好」這是第幾次同方向嘗試?第 2 次 → 停下來升級
對話中「上次也是這樣」這個 bug 已經修過?是 → 寫測試固化
同個假設用第 3 種寫法假設本身可能錯?是 → 改假設、不換寫法
累積心智負擔但還沒進展是不是錯過 2 次門檻?是 → 立刻升級、不再試

核心原則:失敗的價值在於提供資訊。第 1 次失敗資訊不足以決策、第 2 次失敗資訊足以決策 — 兩者要用不同方式回應。混為一談會讓人在錯方向裡無限重試、或對小錯過度反應。

第 5 個面向:驗收訊號 — 「畫面對一次」是低資訊量訊號、跟「程式跑通一次」「測試過一次」是同類錯誤。詳見 #56 視覺完成 ≠ 功能完成 把驗收訊號的時間軸跟 2 次門檻接起來、#68 驗收的時間軸:四個 checkpoint 把驗收分散到多個時點。

第 6 個面向:測試訊號 — 「測試 PASS 一次」是低資訊量訊號(測試本身可能有 bug、可能太寬)。要 RED → GREEN 兩個訊號 — 一次 fail 一次 pass — 才能相信測試真的會 catch。詳見 #69 Test-First:先看到 RED 才相信 GREEN

第 7 個面向:跨檔 emergence 訊號 — 在批量寫作 / 批量產出情境下、「第 2 次」要區分 同檔 vs 跨檔 兩種強度。同檔同 pattern 第 2 次出現 = 直接訊號、立即升級;跨檔同 cadence 第 2 次出現 = 弱訊號、樣本數通常要到 5-10 才強到 catch。對應 #122 Cadence 同質化是模板的隱形維度#124 Emergence-class 違規規則化不了 — 跨檔 emergence 的 2 次門檻不在「寫第 2 篇就 catch」、而在「寫到 batch 進度 10-20% 時抽樣 catch」、過了這位置修正成本就會 N 倍上升。