接手既有系統時,最大的困難往往不是技術,而是「不確定改這裡會影響哪裡」。比起憑感覺修改,用固定的流程除錯更穩定:重現、定位、歸因、修復、防範,每一步都留下可以驗證的證據。
一、重現:先讓問題穩定發生
無法穩定重現的問題,修好了也無法證明修好。先把條件寫清楚:
- 哪個頁面、什麼操作順序、什麼資料。
- 只發生在特定瀏覽器、螢幕尺寸或登入身分嗎?
- 能不能縮小到最小重現範例(Minimal Reproduction):拿掉不相關的程式碼,問題還在,代表範圍縮對了。
二、定位:用二分法縮小範圍
用 DevTools 把範圍切半,再切半:
- Console:先看有沒有錯誤或警告,它們常直接指出方向。
- Network:確認請求有沒有送出、狀態碼、回傳資料是否符合預期。
- Elements:看實際套用的 CSS,以及被劃掉的規則是被誰覆蓋。
- Sources:在可疑位置設中斷點,或用「Event Listener Breakpoints」在特定事件發生時暫停。
三、歸因:用假設驗證,不要憑猜測
介面行為問題常見的原因,可以對照著檢查:
| 現象 | 常見原因 | 驗證方式 |
|---|---|---|
| 彈窗點外面會立刻關閉,或關不掉 | 事件冒泡或捕獲順序,點擊被上層攔截 | 在 capture 階段記錄事件路徑 |
| 元件值沒有更新 | 響應性失效(解構、非響應式物件) | 在 DevTools 檢查該值是否仍是響應式 |
| 樣式改了沒效果 | 選擇器優先權較低,或被框架樣式覆蓋 | 在 Elements 面板看被劃掉的規則 |
| 浮層被遮住 | stacking context 讓 z-index 失效 | 檢查祖先元素是否有 transform、opacity 等 |
| 偶發錯誤 | 非同步時序或請求競態 | 加上時間戳記記錄,比對順序 |
例如要確認是哪一層攔截了點擊,可以在 capture 階段觀察事件路徑:
js
document.addEventListener('click', (e) => {
console.log('capture:', e.target, e.composedPath())
}, true)
四、修復:最小範圍,並評估影響面
修改前先回答三個問題:
- 這段程式碼還有哪些地方會用到?(全域搜尋、查看引用)
- 修改會改變哪些既有行為?
- 有沒有更小的改法?例如修元件本身,而不是在每個呼叫端各補一次。
既有系統通常沒有完整測試,修復後要手動走過「會受影響的流程」,而不只是驗證被回報的那一個情境。
五、防範:讓同樣的問題不再發生
- 補一個能重現原問題的測試;沒有測試環境時,至少把重現步驟寫進 PR 說明。
- 能用工具擋下的,就收斂成規則,例如 ESLint 規則或元件的 props 限制。
- 把根因記錄在程式碼註解或文件中,寫的是「為什麼這樣做」,而不是「做了什麼」。
小結
除錯的重點是把「感覺」換成「證據」:能穩定重現、能說明原因、能驗證修復、能防止再發。流程固定下來,面對不熟悉的舊程式碼時也能一步一步縮小範圍,而不是到處試改。