l

2010年3月14日 星期日

敏捷式例外處理設計 (2):我到底哪裡做錯之 dummy handler

 03/14 20:43~21:50


以下的內容需要先閱讀『敏捷式例外處理設計的第一步:決定例外處理等級』比較容易理解。

今天 Teddy 要談一個導致程式無法達到 G1 (error-reporting) 例外處理等級的 exception handling bad smell (例外處理壞味道): dummy handler 。先看一個 Java 程式片段的例子:

public void doIt(){

  try {
     // Do IO operations
  }
  catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
  }
}

寫過 Java 程式的鄉民們,應該對上面這個 catch clause 裡面的程式碼不陌生,這就是一個 dummy handler。所謂的 dummy handler,就跟政客的競選政見一樣,聽(看)起來頭頭是道,實際上卻是空無一物,看不到牛肉。e.printStackTrace(); 這一行程式,事實上並沒有實質地 handle (處理) 例外,只是單純把例外印到 console 中。這樣的訊息通常只有 programmers 在程式開發的時候才看得到,對於這個 method 的呼叫者 (caller) 而言當例外發生之後並不會得到任何通知,因此會以為該 method 的執行沒有問題而繼續執行下去,但實際上系統的狀態可能已經發生了錯誤了。

Dummy handler 還會讓 programmers 產生一種『我已經把裡外處理好』的錯覺,實際上這樣的例外處理卻連 G1 等級都沒有達到。

*******

Replace Dummy Handler with Rethrow

要移除 dummy handler 這個 bad smell 很簡單,只要套用 Replace Dummy Handler with Rethrow 這個 refactoring 就可以達到 G1 例外處理等級,請看:


public void doIt(){

  try {
     // Do IO operations
  }
  catch (IOException e) {
     throw new UnhandledException(“message”, e);
  }
}

附註說明一下,其中 UnhandledException 是一個在其他地方事先定義好的 RuntimeException。另外,在 main program 中需要有一個超大的 try block 用來捕捉所有的例外並回報個使用者知道,如此便可達到 G1。

如果上面的程式要達到 G2 或是 G3 還有其他相對應的方法,改天有空再談。

*******

以下為 QA 時間。

鄉民甲:為什麼不直接把 IOException 丟出去,還要轉成另一個 RuntimeException?

Teddy 回答:G1 的目的只是為了讓例外可以被回報,也就是保證沒有例外會被隱藏或忽略。由於 IOException 是一個 checked exception,所以如果只是為了『回報例外』這個目的,而直接把它往外丟,那麼就需要修改 doIt() 的介面如下:

public void doIt() throws IOException;

而呼叫 doIt() 的人也需要修改,造成所謂的漣波效應。為了避免這個問題,才使用一個 RuntimeException 來回報錯誤。


鄉民乙:這個 dummy handler 是不是只有在 Java 才會出現?

Teddy 回答:應該說在 Java 程式中很容易出現,而其他語言也『不排除』會有這個 smell (鄉民乙:講得很心虛喔...)。由於絕大多數的程式語言只有 unchecked exceptions (也就是 runtime exceptions) ,因此 programmers 沒有必要為了符合類似 Java 所規定的 catch or declare rule 而需要去捕捉這些 unchecked exceptions,因此預設情況下所有未被捕捉的 unchecked exceptions 直接就往上層傳遞 (propagate) ,而自動達到 G1(記得在程式最外層加上一個大的 try block)。

友藏內心獨白:看得懂 Teddy 在講什麼東東的人請到前面來領糖果...

沒有留言:

張貼留言