制定例外處理政策

  • 2887
  • 0

制定例外處理政策

在前一篇文章-例外處理(Exception Handling) 中曾提及例外狀況可分為可預期、不可預期與可矯正、不可矯正,本文將進一步說明例外處理的常用手法,並針對前述兩種面象所交織出的四種情境加以探討,最後再引用 Microsoft Enterprise Library Exception Handling Application Block 的概念,提出幾項例外處理政策。

常見的例外處理手法

  1. 記錄(Logging)
  2. 包裝(Wrapping)
  3. 替換(Replacing)
  4. 擲出(Throwing)
  5. 通知(Notifying)

記錄(Logging)

記錄的目的為了是方便日後的追蹤、除錯與統計等用途。記錄的地方可能有 Windows 事件記錄、檔案或資料庫等。記錄時例外狀況時需注意留下足夠必要的訊息,如例外狀況的型別、易記訊息、發生時間、發生地點(StackTrace) 等,否則可能喪失意義。

包裝(Wrapping)

變更例外狀況,並保留原始的例外狀況以便追蹤記錄。包裝的目的是為了讓例外狀況更易於呼叫端瞭解,因為呼叫端可能屬於另一個問題領域,它比較重視被呼叫端明確定義後的例外狀況。在 .NET Framework 中標準的作法是將原始的例外狀況放在 InnerException 成員中。

替換(Replacing)

變更例外狀況,但不保留原始的例外狀況。替換和包裝的共同目的都是讓例外狀況更易於瞭解,不同的是替換為了隱藏資訊,所以不會保留原始的例外狀況,通常在例外狀況越接近使用者越應該使用替換手法。

擲出(Throwing)

將例外狀況擲出,讓呼叫端來處理。擲出經常搭配包裝或替換手法一起使用,因為在這一層函式中無法矯正例外,所以期望將例外狀況更明確後,再擲出給呼叫端來矯正。需注意無法更明確化例外狀況不需要特意地先捕捉後擲出,因為這樣的動作一點意義也沒有,甚至還會影響除錯,原因是在 .NET Framework 設計下當例外狀況擲出時會重新記錄 StackTrace。

通知(Notifying)

通知使用者例外狀況的發生。對使用者或系統通知例外狀況的發生,最好還能依例外狀況的嚴重性分層級。如果通知的對象是使用者務必使用替換手法讓訊息更明確易懂。通知的方法則有 Alert、E-Mail 等。

以上手法運用時機各有不同也各有巧妙,所有手法都運用上不表示系統就是嚴謹的,較嚴謹的系統應該會有比較多的防呆檢查與例外矯正。而且這些手法真正的受益對象是開發團隊而不是使用者,事實上使用者比較想看到的只有成功訊息而已。如果可能的話,系統能自動矯正所有例外狀況是再好不過的事,但實際上對於不可預期或不可矯正例外狀況,我們只能期待使用者自行矯正或通知叫修。

許 多系統可能只用到記錄和通知這兩個手法,相信也有很多經驗告訴我們這樣是不夠的。大部份的專案因為時程和成本兩項因素導致無法在例外處理多加著墨,不過對於一個力求穩定的產品來說這應當是非常重要的議題,它在短期內很難看到成效,但會隨著時間的增長而逐漸慶幸有好的例外處理機制真好!

大型系統中有數十萬甚至數百萬的程式碼其實一點也不稀奇,而在這麼大量的程式碼中要變更例外處理手法才是極大的挑戰。在前一篇文章提過了,例外狀況是經過發現才知道的,可想而知一旦有新增的例外狀況,可能就要隨之有新的矯正措施或處理手法。那是不是有什麼方法可能簡化未來開發團隊在這方面的負擔?是接下來要討論的議題。

再回想一下例外狀況分為可預期、不可預期與可矯正、不可矯正來交織出四種情境,這應當可含括所有的例外狀況,所以我們可以利用這四種情境來簡化例外處理手法。如表一所示,不可預期卻可矯正的例外狀況是不存在的,因此還可以簡化到只剩下三種情境。
 

 

可預期

不可預期

可矯正

情境一

不存在

不可矯正

情境二

情境三

表一、例外狀況情境

既然這些情境可含括所有的例外狀況,那如果能擬定一些策略來處理這些情境下發生的例外狀況,將會強加例外處理工作的一致性,並簡化例外處理工作,未來也較容易改變策略。而這裡是引用了 Microsoft Enterprise Library Exception Handling Application Block 中例外政策(Exception Policy) 的概念。

一般對於政策的定義是指為實現某種目標所訂定的計劃,而例外政策是為了例外處理所訂定的計劃。計劃是有組織性的,包含了多項活動,每個活動都會使用一種例外處理手法,活動間有先後次序的問題需考量。我們可以為一般狀況訂定一般政策(Common Policy),目的是為了涵蓋所有可能發生的例外狀況,讓所有例外狀況的處理原則都有依據;對於部份特定狀況訂定特殊政策,是為了可以用更精確的方式處理問題,我稱它為領域政策(Domain Policy)

我們可以為前述三種情境訂定一般政策,因為它們涵蓋了所有的例外狀況,下圖說明這三種情境通常發生在系統的哪些層次中。

clip_image002

圖一、系統層次與例外情境對應關係

基本上系統都可粗略地劃分成三種層次,Interface layer 是外界認識系統的層次;Domain layer 是系統解決問題領域的核心層次;Infrastructure layer 是系統認識外界的層次。

情境一是可預期可矯正的,它可能發生於系統任何層次,而系統沒有必要將矯正的例外告訴外界,因此它只要負責記錄即可。

情境二是可預期不可矯正的,也可能發生於任何層次,但重點是將問題重包裝成系統定義的例外狀況,並往外擲出,期待由呼叫端來矯正。

情境三是不可預期不可矯正的,正因為它不可預期,因此只會發生 Interface layer,需要的是記錄原始例外狀況,然後取代成外界可理解的例外狀況,然後是通知外界。
 

政策

處理手法

ExpectedCorrectableExceptionPolicy

Logging

ExpectedIncorrectableExceptionPolicy

Wrapping, Throwing

UnexpectedIncorrectableExceptionPolicy

Logging, Replacing, Notifying

表二、一般政策

至於領域政策是為了明確處理特定問題領域所訂定之政策,如資料庫存取可訂定 DBAccessExceptionPolicy;網路通訊可訂定 NetworkExceptionPolicy;安全性可訂定 SecurityExceptionPolicy 等等,這些領域政策是可以視實際狀況彈性規劃,本文就不加以探討。

在下一篇文章將配合範例程式呈現本文的例外處理政策。

更多參考: