Update(2009/9/22): 看到另一篇說明 bug report 該有什麼內容。
debugging 最大問題在於,它是一個未知的時間箱子,不知道要花多久才能 debug 完。這章談的是幾個除錯上的技巧。
說到除錯,我也推薦閱讀如何有效地報告錯誤這一篇文章,談的是如何正確回報錯誤,好的錯誤回報可以節省很多時間,而不僅僅只是一句 “程式不會動” 而已。
Keep a Solutions Log (紀錄下解決問題的辦法)
解決問題一直是軟體開發者的工作項目(這裡指的問題比較像是軟體安裝、版本、函式庫使用等等問題,例如 windows 上如何把 MySQL Ruby gem 裝起來等等),不過有時候會碰到似曾相似的問題,疑?我以前是怎麼解決的?拜網路發達之賜,Google 搜尋一下通常會有不少幫助,但是還是得花不少時間找尋解答。
自己維護一份簡單的 solutions log 吧,紀錄下日期、問題描述、解法、參考網址等等資訊,之後碰到類似的問題就可以搜尋的到。將這份 log 用 wiki 維護也是不錯的主意。或是寫在 Blog 上,這樣 google 搞不好還會搜尋到自己以前寫的解法…XD
Warnings Are Really Errors (把警告當真)
編譯器(這裡泛指 complier 或 interpreter) 的警告常常有人是忽略不看的,反正可以編譯執行不會 error 就好了?書上舉了 C++ 的例子,編譯器的警告還是蠻有用的(我想特別是 static 語言)可以幫助你找到跟避免潛在的 Bugs,請不要忽略。請將編譯器的警告也當作程式錯誤或無法通過測試的程式一樣認真處理。
我自己寫 Ruby/Rails 的經驗,最常見的警告像是有:
link_to ( 'login', login_path ) # warning: don't put space before argument parentheses
因為中間多了一個沒用的空白。或是
p Array.new 3, 1 # warning: parenthesize argument(s) for future version
因為 interpreter 覺得 ambiguities 不清楚,這時要請你括號括清楚。另外就是 DEPRECATION WARNING 警告了,告訴你這函式將來的版本將會移除,請不要再用了 :p
Attack Problems in Isolation (隔離除錯)
要在一個大系統找特定問題,不要整個系統一起測,而是將分開隔離找出病因。如果有做 unit tests,我們知道可以將 dependence 的東西用 mock object 隔離出來,這樣測試的時候就不會被外部因素干擾。同理在抓整個系統中的特定 Bugs 的時候,必要的話可以做一些假的 prototype 元件用以隔離抓出問題所在,同時也比較好除錯測試。
我自己土法煉鋼除錯 CSS 也是如此,先移除 CSS 檔案的一半,看看問題是不是出在這裡,然後再砍一半直到找到有問題的那一行。(Binary search?)
Report All Exceptions (回報所有的例外)
如果呼叫一個可能會丟例外的函式,當碰到例外時,盡量可以處理就處理,不然請讓他自然傳播(Propagate)上去給上一層 Caller 處理,不要攔下來又什麼都不做。如果在整個 call stack 中有個傢伙寫了個空個 catch 所有例外,然後 return null 什麼都不做,到時候要找 Bugs 你就會很想殺人了,因為非得 trace 進去 call stack 才能找到原因。
不要覺得自己不會這樣寫,其實常常我們會想”暫時”不想處理這個例外,於是就留下這樣空的例外處理程式碼(然後繼續留到 Production code)。決定要在哪一層處理例外是個設計上的考量,但是如果呼叫一個函式卻要考慮處理二三十種以上的例外可能就有設計上的問題了。
Provide Useful Error Messages (提供使用者有用的錯誤訊息)
一般性的錯誤訊息如 “Something went wrong” 對使用者來說,可說是一點幫助也沒有,既沒有告訴用戶可以怎麼解決,就算使用者想要求助也不知道發生什麼事情。所以盡量提供詳細的訊息告訴使用者發生什麼事情。
當然,如果是比較嚴重的程式例外錯誤,對開發者來說,因為有 logging 的關係,所以看 log 應該可以知道大概的情況並排除,這類的錯誤對使用者來說也沒辦法自行排除,也只能告訴用戶說這不是因為他們操作錯誤的原因。
關於這個議題這一節講的不是很清楚,我個人推薦有本 37 signals 的小書可以翻翻:Defensive Design for the Web 圖文並茂共有40條 Guideline 告訴你如何改進網站的錯誤提示訊息、表單填寫等等,例如:
- 錯誤訊息要明顯,使用顏色、Icons 等效果
- 錯誤訊息包含這是什麼錯誤以及如何修復
- 整個網站用一致的錯誤提示方式
- 在錯誤提示後,不需要再回上一頁才能修正問題
- 用易懂、禮貌的字句