錯誤處理
定義失敗、其擁有者,以及失敗後仍保持安全的項目。此為指導方針,非檢查清單。
型別化、結構化的失敗
預期的失敗需要宣告的型別、穩定的判別式,以及與處理相關的細節。重複使用專案的錯誤慣例,保留原因鏈,並將機器識別資訊與顯示文字分開。絕不要透過解析訊息來進行處理路由。非預期的缺陷(例如窮舉檢查失敗)可以保持為單純的錯誤;但封裝絕對不能將其轉變為成功。
捕獲、復原或停止
對於每個失敗,定義處理與報告的擁有者、封裝方式,以及在擁有 API 文件中的保證:哪些不變量仍然有效,副作用是缺席、部分、已提交或未知,以及誰負責清理。背景工作也需承擔這些義務。
捕獲限制了異常的傳播,而非副作用。只有受影響狀態的擁有者才能建立安全的繼續執行。否則,應停止依賴的任務、丟棄無效的狀態或實例,或升級問題。僅記錄日誌並非復原。重試需要安全的重複執行、取消機制以及明確的擁有者;有限次數的操作需要預算,而持續的監督則需要生命週期的擁有權與可觀察的降級。
在地化、可操作、可見的報告
每份最終報告都需要可讀的摘要、受影響的操作,以及安全的下一步行動。若接收的應用程式存在在地化機制,則透過該機制進行在地化;其他診斷則使用其既有的輸出語言。將敏感的內部細節排除在使用者可見的文字之外。
不可信的狀態或未知的結果,必須透過 UI 或預設啟用、可存取的日誌顯示:報告影響、不確定性、系統做了什麼,以及安全的下一步。持續存在的無效狀態需要持續的可見性。如果在背後沒有相應的保證,絕不能聲稱成功、回滾或安全重試。報告失敗本身需要獨立的備援機制。
驗證最終的狀態與可見的結果,而不僅僅是異常是否被捕獲。
基礎
Meyer,《物件導向軟體建構》(1997):契約與不變量。Sutter,《Exceptional C++》(1999):異常安全保證。Armstrong,〈在軟體錯誤存在的情況下建立可靠的分散式系統〉(https://www.erlang.org/download/armstrong_thesis_2003.pdf)(2003):隔離與監督。