跳至主要內容
科技 科技評論

刪掉一行 console.log,生產環境直接崩了:這次事故算的是軟體維護那一欄的成本帳

刪掉一行console.log讓生產環境商品價格顯示undefined,本文從軟體維護成本與上線變更風險角度,拆解惰性初始化getter背後的工程帳。

刊登 閱讀約 4 分鐘

2026年10月28日,開發者ErpanOmer在掘金發布一篇事故復盤文章,標題直白:「刪了一個沒用的console.log,生產環境直接崩了」。事件本身不複雜:一次例行發版清理了專案裡散落的除錯日誌,上線20分鐘後告警羣響起,一個核心商品詳情頁中,帶階梯定價規則的商品價格顯示為undefined。回滾後比對git diff,這次發版改動47個檔案,其中38個是刪console.log,最終定位到一行程式碼:console.log('price config:', product.priceConfig)。

「純讀操作」的前提,在這個案子裡不成立

多數工程團隊對console.log的心智模型是:讀取值、印出、不影響程式行為,屬於可隨時清除的衛生項目。這個模型建立在「讀取屬性沒有副作用」的假設上,而在JavaScript裡,這個假設可以被getter打破。

來源文章給出了簡化後的程式碼結構:product物件包了一層帶惰性初始化的getter,階梯定價配置priceConfig在第一次被存取時才從原始資料解析,包含規則校驗、排序、區間合併,之後快取結果。被刪掉的那行console.log位於元件setup函式、渲染邏輯之前,它實際上扮演的角色是第一次觸發getter、完成惰性初始化的入口。

刪掉之後,getter的首次觸發被推遲到渲染階段,而渲染邏輯依賴的時序假設已經被破壞,於是價格變成undefined。CI跑過、測試環境驗過都沒有攔下這個問題,因為測試環境沒有覆蓋「帶階梯定價規則的商品」這個分支,出問題的也只有這一類商品。

把這件事放進成本結構裡看

單一事故的帳可以這樣記:上線20分鐘即觸發告警、回滾、拉git diff排查、定位到一行日誌刪除。這些是顯性成本。隱性成本在於,這類「看似安全」的批量清理動作,把驗證負擔從開發階段轉移到了生產環境,而測試覆蓋率沒有為它買單。

值得對照的是變更管理的基本原則:一次發版混合了47個檔案的改動,其中真正的功能變更與日誌清理混在一起,一旦出事,排查範圍被迫擴大到全部47個檔案。如果日誌清理獨立成一個發版批次,定位成本會大幅下降。這與我們先前討論過的線上文件Block架構的前端工程成本帳是同一類問題:架構決策把複雜度藏在哪一層,決定了之後每一次維護動作要付多少錢。

影響傳導:誰承擔,誰該重新計價

受影響的第一層是依賴惰性初始化的模組設計者。惰性getter本身是正當的效能手段,把重的解析推遲到首次存取,換取不必要的場景零成本。但它的代價是初始化時序變成隱式契約,任何「看似純讀」的存取都可能被依賴。第二層是制定清理規範的團隊負責人,「全局搜尋、逐條刪除、半小時搞定」的流程,在這個案例中被證明缺少一個環節:對存取對象是否為純資料的確認。

從工具面看,這類問題在靜態分析上有解空間:linter可以標記getter內含賦值操作的屬性存取,或者團隊直接禁止對非plain object使用console.log。但工具的採用本身就是一筆成本,多數團隊在出事之前不會為它編預算。

收束判斷

來源是一篇個人復盤文章,樣本為單一專案,細節經過簡化處理,不宜直接推廣為產業普遍現象。但它點出的結構性問題是可驗證的:在支援getter的語言特性下,屬性存取帶副作用時,除錯日誌從「可移除的旁觀者」變成「參與執行時序的行為」,這一欄在多數團隊的維護成本表上沒有被計價。下次發版清單裡躺著幾十個檔案的日誌刪除時,這筆帳值得先算一遍。