Re: [請益] BUG少的程式 通常有什麼特色?
※ 引述《p52189 (皮爺)》之銘言:
: 每次都要花很多時間在完工之後的測試和bug修正
: 甚至會有花在測試的時間比動手寫的時間還多的狀況!!
: 我很想知道,bug少的程式究竟有些什麼樣的特質
: 而產出這些好程式的人,又是因為什麼樣的條件使他們手法漂亮?
: 請各位前輩指點,也請盡量講得淺顯一點
: 感謝!!!
我回想一些經驗,覺得程式bug可以分為幾類:
1. 函數的值域及例外部份,變數的值域及例外部份,物件的行為及例外行為.
2. 資料算錯.
3. 機制錯誤,包括暫存資料沒有更新到前端.
第1類即包含了資料型態轉換問題,陣列超限問題,或是物件參考為空值,以及
小到除以0這樣的問題. 因為這些是很基本,很黑手的部份,處理方法就是邊寫程式
邊注意. 開始除錯也是以這個部份為主. 這個部份若bug少,程式的特質就是
都有很固定的慣例方式來避錯誤:
1a. 雜七雜八的關鍵值,都放到變數中: 例如for迴圈的邊界值n,函數的傳回值result.
1b. 固定的函數名稱和變數名稱: 例如取值getSomething..., 放值setSome...,
做一件事情doSome..., 判斷isSome...
1c. 函數盡可能壓到只有輸入參數和輸出,沒有從函數中參考到什麼外部變數.
1d. 對函數內容,變數值,物件行為的思考,是同時思考界內值域和界外值:
界內值該如何處理,應該很容易定義. 不過界外值或例外行為呢?
就要思考程式多需要這些界外或例外的資訊: 有些要藏,有些要let it be,
有些要跳出訊息,這些需要第一時間直接的細心.
1e. 程式功能做有效的分類.
1f. 用一些看起來沒必要但是有效的程式碼來保證程式正確: 例如,複製檔案,
然後刪除原檔,本來做法可能是:
copy(fileName, anotherFileName);
delete(fileName);
看起來好像蠻完美了. 但是有些工作經驗告訴我必須寫成:
if (isExisting(fileName))
doCopy(fileName, anotherFileName);
if (isExisting(anotherFileName) && isExisting(fileName))
doDelete(fileName);
普通來看,前面的判斷式在絕大部分時候很沒有必要. 可是,所謂避免bug
所要避的就是在比較罕見的時候,你要複製一個檔案但是找不到來源檔案,
或者你複製了檔案之後目標檔案不存在,以及要刪檔案的時候找不到檔案
等等這些運作上的狀況.
(複製檔案之後目標會不存在嗎? 理論上不會,但實務上,會.)
第2類資料算錯的解決,因為是需要domain knowledge,以及需要參考需求定義,所以我
傾向於請使用者或測試人員幫忙提供夠多的資訊,使我能核對資料是否正確.
這個部份,我的感想是,如果需求沒辦法抓清楚,unit test有點難寫.
機制方面的偵錯,就比較是冒險了. 剛開始一定會試跑程式幾次,製造一些執行上的
狀態來確認軟體運作的行為是不是正確. 但是最後比較會是軟體交給使用者運行多次
之後,由使用者提醒有什麼樣怪怪的情況. 至於在事前預防的方式,我是用畫圖方式
將自己做好的軟體內容畫出來(UML)幫忙核對軟體的行為.
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 59.112.229.204
推
04/26 22:08, , 1F
04/26 22:08, 1F
→
04/26 22:08, , 2F
04/26 22:08, 2F
→
04/26 22:13, , 3F
04/26 22:13, 3F
→
04/26 22:14, , 4F
04/26 22:14, 4F
→
04/26 22:17, , 5F
04/26 22:17, 5F
→
04/26 22:18, , 6F
04/26 22:18, 6F
→
04/26 22:18, , 7F
04/26 22:18, 7F
推
04/26 22:29, , 8F
04/26 22:29, 8F
推
04/26 22:44, , 9F
04/26 22:44, 9F
→
04/26 22:57, , 10F
04/26 22:57, 10F
→
04/26 22:57, , 11F
04/26 22:57, 11F
→
04/26 22:58, , 12F
04/26 22:58, 12F
→
04/26 22:58, , 13F
04/26 22:58, 13F
→
04/26 23:02, , 14F
04/26 23:02, 14F
→
04/26 23:03, , 15F
04/26 23:03, 15F
→
04/26 23:04, , 16F
04/26 23:04, 16F
→
04/26 23:05, , 17F
04/26 23:05, 17F
→
04/26 23:05, , 18F
04/26 23:05, 18F
→
04/26 23:06, , 19F
04/26 23:06, 19F
→
04/27 00:39, , 20F
04/27 00:39, 20F
→
04/27 00:40, , 21F
04/27 00:40, 21F
→
04/27 06:56, , 22F
04/27 06:56, 22F
→
04/27 06:57, , 23F
04/27 06:57, 23F
→
04/27 06:58, , 24F
04/27 06:58, 24F
→
04/27 09:43, , 25F
04/27 09:43, 25F
推
04/27 09:46, , 26F
04/27 09:46, 26F
→
04/27 09:47, , 27F
04/27 09:47, 27F
推
04/27 11:36, , 28F
04/27 11:36, 28F
→
04/27 11:36, , 29F
04/27 11:36, 29F
→
04/27 12:37, , 30F
04/27 12:37, 30F
→
04/27 12:45, , 31F
04/27 12:45, 31F
→
04/27 13:11, , 32F
04/27 13:11, 32F
→
04/27 13:12, , 33F
04/27 13:12, 33F
基本型: 不使用 not (!)運算,所以
if ( !a ) {
b();
}
要寫成
if ( a ) {
} else {
b();
}
複雜式化簡: 以下這樣若要反轉判斷式,邏輯技巧是笛摩根定律
if ( a || b ) { => if ( !a && !b ) {
c(); c_();
} }
不要用稍微複雜的判斷式,所以原程式寫成:
if ( a ) {
c();
} else if ( b ) {
c();
}
要反轉的時候就是改成:
if ( a ) {
//c();
} else if ( b ) {
//c();
} else {
c_();
}
※ 編輯: yauhh 來自: 59.112.224.243 (04/27 13:37)
推
04/27 16:19, , 34F
04/27 16:19, 34F
→
04/27 16:20, , 35F
04/27 16:20, 35F
推
04/27 20:49, , 36F
04/27 20:49, 36F
推
04/28 10:50, , 37F
04/28 10:50, 37F
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 2 之 10 篇):