核心原則

第 2 次同方向失敗、停下來回報「假設可能錯了、要不要換思路」。 失敗 ≥ 2 次大多是底層假設有問題、不是執行細節有問題。繼續沿同一方向加碼(換更複雜的 selector、加 !important、再寫一層 polyfill)只會放大原本的問題。


為什麼第 2 次是轉折點

商業邏輯

第 1 次失敗常是執行細節(typo、特定 syntax、瀏覽器 cache)— 修正後可能就過。

第 2 次失敗、用同樣的方法但更小心、還是失敗 — 這個訊號的重量遠大於兩次失敗的相加。它說的是「我以為的問題不在這層、根本問題在別處」。

第 3 次以上的失敗、加上「再試一次更小心」的努力、產生的副作用會超過解決的問題:

嘗試次數心理狀態行動模式可能副作用
1信心足直接做
2信心動搖加碼(更複雜的 selector / important)可控
3焦慮全面反擊(layers + important + polyfill)大 — 改動範圍擴張
4+沉沒成本綁住不肯放棄已寫的嚴重 — 為前面的錯買單

第 2 次是還能優雅切換方向的最後機會。


這次任務的實際情境

觀察

要把 search scope UI 放在「搜尋框與結果之間」。我嘗試了:

嘗試方向結果
1Display: contents 串接 + grid-row 排序失敗 — scope 跑到頁尾
2!important 強化 grid-row失敗 — 沒改善
3Specificity 雙寫(.x.x失敗 — 沒改善
4加更多 display: contents 層失敗 — 同樣結果
5(被使用者制止)「思路錯了、換方向」改用 absolute 定位、一次成功

四次失敗都基於同一假設:「drawer 是 .pagefind-ui 的直接子節點」。實際 drawer 在 form 內。

判讀

第 2 次失敗時就應該停下來檢查假設、不該再往同方向加碼。

正確流程:第 1 次失敗修細節;第 2 次失敗用 playwright 量 DOM 確認假設;發現假設錯就立刻換方向、不要為前面的努力買單。

執行:失敗計數與行動

失敗次數行動
第 1 次修細節(typo、cache、syntax)
第 2 次停下來 — 用工具驗證底層假設(DOM tree、computed style、framework 行為)
第 2 次驗證後假設對 → 繼續修;假設錯 → 換方向、不為前面買單

關鍵是第 2 次的「停」 — 把行動從「執行更努力」切換到「驗證假設」。


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

應對適用次數風險
修細節再試1 次低 — 假設沒問題的話通常成功
停下來驗證假設2 次低 — 確認方向是否正確
加碼(important / 雙寫 / polyfill)不適用高 — 假設錯時放大問題
換方向(重新設計實作)2 次後驗證假設錯中 — 一次性成本、後續穩定

選擇規則:第 1 次修細節、第 2 次驗證、第 2 次後驗證假設決定繼續或換方向。不該有第 3 次同方向加碼。


假設驗證的具體方法

1. 用工具讀真實狀態

假設類型驗證工具
DOM 結構playwright browser_evaluate 讀 ancestor chain
Computed styleplaywright getComputedStyle
元素位置playwright getBoundingClientRect
Framework 行為讀框架 source、看 reconcile 條件

2. 反問「如果假設錯了會怎樣」

假設如果錯了
Drawer 是 form 的 sibling那 grid-row 完全無效(drawer 跟 form 共用 cell)
Specificity 30 是上限那 layers 才是解、不是雙寫

「如果錯了會怎樣」的答案是「跟我看到的失敗一致」 → 假設可能錯。

3. 對外回報

1我嘗試了兩次 [方向 X]、結果都 [現象 Y]。
2我的假設是 [假設 Z]、但驗證 [假設 Z] 似乎不成立。
3要不要換 [方向 W]、或是有什麼資訊我沒看到?

對外回報 = 把問題放到使用者視野、避免繼續單方面加碼。


設計取捨:失敗應對的策略

四種做法、各自機會成本不同。這個專案選 A(第 2 次失敗驗證假設)當預設、其他做法在特定情境合理。

本篇是 #42 2 次門檻 抽象原則在「同方向失敗」這個面向的應用。

A:第 2 次失敗停下驗證假設(這個專案的預設)

  • 機制:第 1 次修細節再試;第 2 次失敗 → 用工具驗證底層假設(DOM tree、computed style、framework 行為);驗證錯就換方向
  • 選 A 的理由:早一點切換、雙方時間都省;2 次失敗的證據量足以判斷「路徑問題」
  • 適合:所有除錯情境
  • 代價:第 2 次後的「停下」需要心理紀律(克服繼續加碼的衝動)

B:第 4-5 次才停(沉沒成本綁住)

  • 機制:繼續加碼直到使用者制止
  • 跟 A 的取捨:B 給更多嘗試空間、A 早決;B 在沉沒成本累積後更難切換
  • B 是反模式:沉沒成本是認知偏誤、不是合理應對 — 「再試一次更小心」的衝動是訊號、不是解法

C:第 1 次失敗就換方向(過度反應)

  • 機制:每次失敗都假設方向錯、立即換
  • 跟 A 的取捨:C 太敏感、A 適度;C 在「修細節就能過」的場景過度切換
  • C 才合理的情境:嘗試成本極高(每次失敗 = 半天工作)— 即使單次失敗、也值得停下重新評估

D:永不換方向

  • 機制:認定方向對、無限加碼
  • D 是反模式:方向錯時無法收斂、最後產生脆弱的 patchwork
  • 看起來吸引人的原因:心理上不想承認方向錯、繼續加碼比放棄好受
  • 實際發生的代價:失敗訊號被忽略、產生脆弱的 patchwork、修復成本指數放大

判讀徵兆

訊號該觸發的行動第一個該做的事
第 2 次同方向失敗停下來驗證假設用 playwright / DevTools 量真實狀態
!important 解 specificity停 — 切換到 layers 思路評估用 CSS Layers
加第 2 條 polyfill 補跨瀏覽器停 — 評估值不值得繼續報告成本、問使用者意願
用 imperative JS 補宣告式 layout停 — 切換到 CSS-first 思路評估能否用 grid / flex 解決
內心 OS:「再試一次更小心」停 — 這是沉沒成本綁住的訊號對外回報、邀請換方向

核心原則:第 2 次失敗的最佳行動是「驗證假設」、不是「再試一次」。早一點切換方向、節省的是雙方時間。

「再試一次」是當下便利的選項(不需要重新分析)、「驗證假設換方向」是對齊正確性的選項 — 這個反相關見 #67 寫作便利度跟意圖對齊反相關