最近在看【美】Pete GoodLiffe寫的《編程匠藝》,很有感觸。邊讀邊想,發(fā)現(xiàn)能夠與作者產(chǎn)生強烈的共鳴,這真是一種美妙的感覺。所以想把與作者產(chǎn)生共鳴和得學(xué)習(xí)的一些地方記下來,來加深對這些被實踐證明了是正確的編程技巧的掌握。 防御性編程:顧名思義,防
最近在看【美】Pete GoodLiffe寫的《編程匠藝》,很有感觸。邊讀邊想,發(fā)現(xiàn)能夠與作者產(chǎn)生強烈的共鳴,這真是一種美妙的感覺。所以想把與作者產(chǎn)生共鳴和值得學(xué)習(xí)的一些地方記下來,來加深對這些被實踐證明了是正確的編程技巧的掌握。
防御性編程:顧名思義,防御性編程是一種細(xì)致的,謹(jǐn)慎的編程方法。為了開發(fā)可靠的軟件產(chǎn)品,我們要謹(jǐn)慎地設(shè)計系統(tǒng)的每個細(xì)節(jié),便是其能盡可能的“保護”自己,,我們通過明確的代碼中增加很多的假設(shè),當(dāng)假設(shè)在現(xiàn)實的客戶環(huán)境中執(zhí)行時才不至于崩潰,給一些客戶莫名奇妙的錯誤或者異常。防御性編程是一種防衛(wèi)方式,而不是一種補救方式。
圖1 修補性的編程
下面是常見的防御性編程技巧:
1.使用好的編碼風(fēng)格和合理的設(shè)計:
好的編碼風(fēng)格會讓人耳目一新,而且越是清晰地代碼,越是體現(xiàn)了作者思路的清晰度,模塊組件內(nèi)部的高內(nèi)聚,低耦合也會使代碼的維護和使用更加便捷,更不容易出錯。
2.不要倉促的編寫代碼:
不要在腦袋里有了大體思路之后就馬上很“職業(yè)”地噼里啪啦的敲下代碼,然后大體檢查后剩下的就交給編譯器去檢查吧,于是運行通過,編寫下面一個函數(shù),這樣就會隱藏大量的危險的代碼,久而久之就會陷入自己給自己挖的大坑里,拔都拔不出腿。
關(guān)鍵: 欲速則不達(dá)。每敲一個字,都要想清楚自己要輸入的是什么。
3. 不相信任何人:
不相信任何可能給自己寫的代碼帶來麻煩的人,這些人包括:真正的客戶,惡意的用(有可能是黑客),客戶端的代碼(Client Code),運行環(huán)境(可能存在磁盤空間已滿,網(wǎng)絡(luò)斷開等),外部運行庫(自己寫的代碼所依賴的外部dll已從請求位置移除)。
4 . 編碼的目標(biāo)是清晰,不是一味地準(zhǔn)求簡潔:
如果從簡潔(可能理解起來比較困惑)和清晰(可能比較冗長)的代碼里選擇一種,我想大部分人會選擇清晰地代碼,盡管比較冗長(畢竟代碼不是寫在花銀子買來的紙上的 :-) )。
5.不想讓其他人做他們不該做的事情:
設(shè)計上不想讓其他人訪問的屬性或者方法要盡量將可訪問性限制在類或者包的內(nèi)部。
6.編譯時打開所有的警告開關(guān)
日益發(fā)達(dá),功能強大的編譯器會告訴我們,哪些代碼寫的不太符合規(guī)范,哪些變量聲明了未使用等等這些可能在實際的運行環(huán)境中給我們帶來意外結(jié)果,我們卻感覺莫名其妙,無從下手修補的代碼。重視編譯后的警告信息會讓我們的代碼更加健壯。
7.使用安全的數(shù)據(jù)結(jié)構(gòu):
最常見安全隱患是緩沖區(qū)溢出,例如:一個buffer的長度是10,但是向buffer寫入了長度為11的數(shù)據(jù),這樣會可能覆蓋掉其他的數(shù)據(jù),這樣可能會造成遭難性的影響。當(dāng)然現(xiàn)在.net 這樣優(yōu)秀的開發(fā)平臺有CLR去管理內(nèi)存,給我們騰出了更多的時間和精力去考慮我們想要用代碼完成的事情。
8.檢查所有的返回值:
如果一個函數(shù)有返回值,這樣做肯定是有理由的。要對這個返回值進行檢查,如果不對返回值檢查就會產(chǎn)生很多難以察覺的錯誤。檢查這個返回值,這個返回值可能是一個錯誤代碼(C程序一般都是返回錯誤代碼吧),必須辨別這個代碼并處理所有的錯誤,忍受這個錯誤,危險就會悄無聲息的潛入我們的程序。C#提供了沿堆棧逐級向外拋出的異常機制,我們應(yīng)該在寫的C#代碼中,對不同級別的異常做合理的封裝(底層異常要體現(xiàn)底層這個級別來例如:DBException,業(yè)務(wù)層的異常要體現(xiàn)出業(yè)務(wù)類的異常來ProductInfoInitialException)。
9.審慎的處理內(nèi)存等寶貴的資源:
這些資源包括:內(nèi)存,磁盤文件,網(wǎng)絡(luò)連接,數(shù)據(jù)庫連接。哈哈,現(xiàn)在jvm,clr都可以做到自動的清理資源和垃圾回收,我們真是太幸福了,但是也不要太大意了,我們還是需要顯示的釋放那些我們不再需要的資源,畢竟jvm和clr都是遵循一定的機制(詳見http://www.cnblogs.com/anorthwolf/archive/2009/12/07/1618744.html),我們必須顯示的終止對那些不再使用和不會被自動清理的對象的引用,不太先進的垃圾回收器會被循環(huán)引用對象所蒙蔽。
10.盡量晚的聲明變量:
也就是要靠著使用變量最近的代碼段來聲明變量。
11.在聲明變量的位置初始化變量:
如果初始化了所有的變量,那么他的用途就是明確的。“如果我不初始化它,我就不關(guān)心它”的經(jīng)驗主義是錯誤的,如果一個變量在一個位置聲明,在另一個位置初始化,并在第三個地方被使用,那么一旦初始化代碼被跳過,就會得到意想不到的結(jié)果,到時候我們再去查找原因,那就難嘍。
12.小心的進行強制類型裝換:
有些類型之間雖然可以進行強制類型轉(zhuǎn)換,但是有些類型在轉(zhuǎn)換的過程中會丟失掉一些數(shù)據(jù)。
13.提供默認(rèn)的行為:
例如:Switch語句,要對default 有默認(rèn)的實現(xiàn)。
14.檢查數(shù)值的上下線:
.net 框架中已經(jīng)對一些數(shù)值類型有了范圍的約束,但是如果我們在一些業(yè)務(wù)開發(fā)中要對是否符合現(xiàn)實情況作出檢查:例如年齡不能為負(fù)數(shù)等等。
15.約束:
約束主要包括:
1.5.1 前置條件:輸入一段代碼之前必須為真。
1.5.2 后置條件:輸入一段代碼之后必須為真。
1.5.3 不變條件:程序運行到一個特定點,必須為真。
1.5.3 斷言:任何其他關(guān)于程序在給定位置的狀態(tài)的陳述。
具體內(nèi)容是:
檢查所有的數(shù)組邊界。
在廢除指針前,斷言指針是否清零。
確保函數(shù)參數(shù)的有效性。
在函數(shù)結(jié)果返回前,進行充分的檢查。
在操作對象之前證明他的狀態(tài)時一致的。
總結(jié)一下,編寫正確而且優(yōu)秀的代碼是很重要的,這需要記錄下你所做的所有的設(shè)想。這樣會使程序維護起來更加的容易,會使錯誤減少。防御性編程就是一種預(yù)想最壞的情況并為之做好準(zhǔn)備的方法。他是一種可以防止簡單的錯誤變成難以找到的錯誤的技術(shù)。與防御性代碼一起使用編入代碼的約束,會使程序更加的健壯。
作者:小倫 出處:http://www.cnblogs.com/shiyulun1984/
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com