l

2016年2月12日 星期五

用Introduce Assertion移除Comments怪味道

Feb. 04 23:00~23:50

螢幕截圖 2016-02-04 23.48.26

▲assert (Eiffel != Fat Cat)

 

程式中的註解除了用來解釋變數與函數用途、程式邏輯以外,還有一種常見的情況是用來說明某種條件必須成立,否則程式就是有bug。以下例子節錄自《Refactoring》,Employee類別有一個_primaryProject資料成員(data member),代表員工隸屬於某個專案。每位員工有一個_expenseLimi資料成員代表可以報銷費用的的上限。

Employee的getExpenseLimit()假設員工如果沒有隸屬於專案,他的_expenseLimit就必須要有值(不能為 NULL_EXPENSE)。若_expenseLimit為NULL_EXPENSE則員工必須隸屬於某個專案,然後回傳這個專案的getMemberExpenseLimit()。

螢幕截圖 2016-02-05 17.42.22

螢幕截圖 2016-02-05 17.42.33

***

電腦只會執行程式,不會執行註解。所以寫在Employee類別第13行的註解除了給人看以外,沒有強制性作用。萬一程式有問題,_expenseLimit為Null_EXPENSE而且_primaryProject為Null,執行Employee的getExpenseLimit()函數便會拋出NullPointerException。

怎麼改,可以套用Introduce Assertion來取代註解。Assertion中文翻譯為「斷言」,意義為「一個結果為真的敘述」,例如,assert (5 > 1) 結果為真,這個assertion就通過。下列程式範例直接使用JUnit的Assert.assertTrue(_expenseLimit != NULL_EXPENSE || _primaryProject != null) 取代原本註解的內容,鄉民們也可以用JDK 1.4 之後的assert關鍵字來取代。

螢幕截圖 2016-02-05 17.44.17

 

在執行期間如果assertion判斷失敗會丟出例外(exception)終止程式執行,這樣子開發人員就知道系統有bug,要趕快修改(fail fast的做法)。

***

看到這裡如果鄉民們有很認真看文章內容此時應該會有一個疑問:「assertion失敗丟出例外和NullPointerException丟出例外不都是例外,那幹嘛寫assertion?」答案很簡單:「因為兩者語意不同」。細節請參考〈敏捷式例外處理設計 (8):這是你的問題,不是我的問題〉與〈過勞死之軟工無用論〉,或是《Object-Oriented Software Construction, 2nd》這本書。

***

友藏內心獨白:懷念Design By Contract。

沒有留言:

張貼留言