本篇是故事三的「內化」篇。
本篇要回答:怎麼把「修掉一個逗號」升級成「這一類無聲變形,在靠近源頭的地方就被攔下」?
修掉逗號之後,第一版防再發措施幾乎要寫成「以後多行賦值要小心逗號」。這是典型的為單一事故立單一法條——法條會越積越多,而下一場事故永遠長得不一樣:也許是字串被當成 iterable 拆成單字元(Day 13 順手驗證過 total("abc") 一樣照跑),也許是 dict 少包一層。針對逗號立法,攔不住家族裡的其他成員。
過去我把型別註記與驗證當成「有空再補的文件」。這場事故改變了定價:它們不是文件,是把錯誤攔在滑行距離為零處的機制——Day 13 量過那條滑行距離,跨越整條呼叫鏈加一次格式轉換。
改善措施依「離源頭多近」排序,每條附驗證方式:
| 措施 | 攔截位置 | 驗證方式 |
|---|---|---|
| 關鍵路徑補型別註記 | 編輯器即時/CI 型別檢查 | 在最小案例重演事故,確認型別檢查標紅 |
| 重要邊界做結構驗證(schema 或顯式檢查) | 邊界入口 | 餵入 (42,) 之類變形資料,確認被拒收 |
| 測試驗證型別與結構,不只驗證「沒拋例外」 | 測試層 | 斷言 type 與結構,變形資料使測試轉紅 |
| 排查輸出一律 repr 加型別 | 事故當下 | 檢查 debug 慣例與 log helper |
| 易誤讀的多行賦值改明確寫法 | 源頭 | code review 檢查點 |
| 測試覆蓋「資料建立到邊界輸出」的完整路徑 | 整條鏈 | 覆蓋率對照事件軌跡逐節點檢查 |
驗證欄的共同邏輯:每一條措施都要能在最小重現上演示「有它就攔住、沒它就放行」——攔不住重演的措施,只是又一份文件。
區分證據等級。已確認事實:表中攔截機制的行為可驗證。合理推論:涵蓋邊界後,同族事故的滑行距離趨近於零。執行假設:團隊願意為「重要邊界」付出註記與驗證的維護成本——這是取捨,不是免費。
Python 認為這是一段合法程式,但下游從未答應接受這種資料。
修掉一個逗號只能救這次事故;替資料邊界寫清楚契約,才可能攔住下一個看起來完全不同的錯誤。
故事三到此收束。下一個故事(Day 16 起)從語言層走進工具層:lint 全綠之後,ORM 查詢反而永遠找不到資料。