Debug 卡關,常常不是技術問題,而是心態與認知問題:我們會看見「想看見的」、會為了「證明自己沒錯」而忽略線索、會被「打開 DevTools 後 bug 就不見了」搞瘋。認識這些陷阱,比多學一個工具更能提升 debug 效率。

Debug 是為了蒐集資訊,不是自證清白#

這個心態轉變很關鍵。當你抱著「我要證明我的程式碼沒問題」的心態,你會下意識地避開那些可能打臉自己的測試路徑;當你抱著「我想知道這裡實際發生什麼」的心態,每一個錯誤都變成有用的線索,而不是對你的指控。

一個推論:沒有任何測試能證明「程式不存在 bug」,只能證明「在這些情境下沒發現 bug」。所以 debug 的合理目標不是「證明完美」,而是「把不確定性降到可接受的程度」。

把 bug 當成「資訊」而非「羞辱」。報 bug 的人是在送你情報;收到 bug 報告時防衛性地說「我這邊不會啊」「應該是環境問題」,只會擋住資訊流入。

觀察者效應:一觀察就變樣#

物理有觀察者效應,前端 debug 也有。打開 DevTools、加上 log、下中斷點這些動作本身,可能改變程式的行為

  • 開 DevTools 會停用快取(若勾了 Disable cache),於是「快取造成的 bug」就消失了。
  • console.log 一個物件,可能讓某個惰性求值或非同步時序剛好錯開,bug 不再出現。
  • 中斷點暫停執行,改變了 race condition 的時序,競態 bug 就「好了」。

這類「一觀察就不見」的 bug 稱為 Heisenbug(對付它的策略見 間歇性 bug)。

因為觀察會改變現象,所以記錄 bug 發生時的「環境元資訊」往往比現場重現更可靠:瀏覽器與版本、是否開著 DevTools、網路狀況、快取狀態、裝置。這些脈絡常常才是真正的觸發條件。

認知偏誤:你只看見想看見的#

人在 debug 時有幾種頑固的偏誤:

偏誤表現對策
確認偏誤只找支持「我的假設」的證據,忽略反證主動嘗試「推翻」自己的假設
定錨第一眼認定某處有問題,之後死守不放寫下假設,被否證就果斷換
視而不見看一段熟悉的程式碼太多次,反而看不到那個明顯的錯字換人看、隔一段時間再看、大聲讀出來

小黃鴨除錯法#

把問題一行一行、原原本本地「講」給別人聽——哪怕對象只是桌上的橡皮鴨。很多時候話講到一半,自己就發現矛盾了:因為「向別人解釋」會強迫你檢視每個你原本「想當然爾」跳過的假設。

找不到人或鴨,就把 bug 寫成一段文字描述(要貼到 issue 那種)。寫的過程跟講的過程效果一樣——逼你把模糊的直覺說清楚。

何時該停下來#

前端的 bug 不是每一個都值得追到底。要在「繼續挖」和「先繞過/蒐集更多資料」之間做判斷:

  • 這個 bug 多常發生?影響多少使用者?
  • 已經投入多少時間?再投入的邊際報酬還高嗎?
  • 是否該先加上更多 logging/監控,等它「自己再現」時帶回更多資訊,而不是現在硬逼重現?

對於罕見又難重現的 bug,「先加強可觀測性、把它養大到看得清楚」常常比當下死磕更划算。這不是放棄,而是換一種更有效率的蒐證方式。

小結#

  • Debug 是蒐集資訊,不是證明自己沒錯;bug 是情報不是羞辱。
  • 觀察會改變現象(Heisenbug);記錄環境元資訊比硬重現更可靠。
  • 防範確認偏誤與定錨:主動推翻自己的假設;用小黃鴨除錯法。
  • 罕見難重現的 bug,先加強可觀測性再蒐證,未必要當下硬攻。