防御性編程

搜集了一些關(guān)于“防御性編程”資料,將其中一些思想備份下,學(xué)習(xí)


軟件工程師的智慧,就是在于其是否開始意識(shí)到:使程序能用和使程序正確,這兩者之間有什么樣的差別
編寫在常規(guī)情況下都能用的代碼是很容易的,只要提供常規(guī)的輸入集,這些代碼就會(huì)給出常規(guī)的輸出集。但是如果提供了一些意外的輸入,這些代碼可能就會(huì)崩潰
正確的代碼是絕不會(huì)崩潰的,對(duì)于所有可能的輸入集,它的輸出都將是正確的,不過(guò),所有可能輸入的集合會(huì)常常大得驚人,并且難以測(cè)試
然而并不是所有的正確的代碼都是優(yōu)秀的代碼,因?yàn)橛行┱_的代碼的邏輯可能很難理解,其代碼可能很不自然,并且可能幾乎無(wú)法維護(hù)
因此,編寫優(yōu)秀的代碼才應(yīng)該是不懈追求的目標(biāo),優(yōu)秀的代碼是健壯的,高效的,也是正確的。當(dāng)面對(duì)不常見的輸入的時(shí)候,產(chǎn)品級(jí)的代碼不會(huì)crash,也不會(huì)出現(xiàn)錯(cuò)誤的結(jié)果,同時(shí)還滿足所有其他的要求,包括線程安全、時(shí)間約束和重入等
經(jīng)常面對(duì)風(fēng)格奇異的遺留代碼,那些由現(xiàn)在早已不在的代碼猴子所編寫的舊代碼
面對(duì)各種各樣的困難,怎么保證所編寫的代碼穩(wěn)定耐用
答案就是 防御性編程


設(shè)想導(dǎo)致我們寫出帶有缺陷的軟件,下面是一些很常見的設(shè)想:
這個(gè)函數(shù) 絕不會(huì) 被那樣調(diào)用,傳遞的參數(shù)總是有效的
這段代碼肯定會(huì) 一直 正常運(yùn)行,它絕不會(huì)出現(xiàn)錯(cuò)誤
如果吧這個(gè)變量標(biāo)記為 僅限內(nèi)部使用 就沒有人會(huì)嘗試訪問(wèn)這個(gè)變量了
在進(jìn)行防御性編程的時(shí)候,我們不應(yīng)該做任何設(shè)想,我們不應(yīng)該設(shè)想“那不會(huì)發(fā)生”
經(jīng)驗(yàn)告訴我們,唯一可以肯定的是:代碼在某天會(huì)因?yàn)槟撤N原因而出錯(cuò),有人會(huì)做出愚蠢的舉動(dòng)。墨菲定律這樣說(shuō):凡是可能會(huì)出錯(cuò)的事,準(zhǔn)會(huì)出錯(cuò)。防御性編程通過(guò)遇見到 或者至少是預(yù)先推測(cè)到 問(wèn)題的所在,斷定代碼中每個(gè)階段可能出現(xiàn)的錯(cuò)誤,并做出相應(yīng)的防范措施,來(lái)防止這類意外的發(fā)生
這也許是有點(diǎn)偏執(zhí),但適度的偏執(zhí)并沒有什么壞處。coding從一開始就適度的偏執(zhí),可以使代碼在很長(zhǎng)的時(shí)間內(nèi)更加健壯


防御性編程是一種細(xì)致、謹(jǐn)慎的編程方法,為了開發(fā)可靠地軟件,需要設(shè)計(jì)系統(tǒng)中的每個(gè)組件,使其盡可能的保護(hù)自己,我們通過(guò)明確的在代碼中對(duì)設(shè)想進(jìn)行檢查,擊碎了未記錄下來(lái)的設(shè)想,這是一種努力,防止 或者至少是觀察 我們的代碼以錯(cuò)誤行為的方式被調(diào)用
防御性編程使我們可以盡早發(fā)現(xiàn)較小的問(wèn)題,而不是等它們發(fā)展成災(zāi)難的時(shí)候才發(fā)現(xiàn),當(dāng)然防御性編程并不能排除所有的程序錯(cuò)誤,但是問(wèn)題所帶來(lái)的麻煩將會(huì)減少,并易于修改,防御性程序員只是抓住飄落的雪花,而不是被埋葬在錯(cuò)誤的雪崩中
防御性編程是一種防衛(wèi)方式,而不是一種補(bǔ)救形式


對(duì)防御性編程的誤解
防御性編程 并不是 檢查錯(cuò)誤:如果代碼中存在可能出現(xiàn)錯(cuò)誤的情況,無(wú)論如何都應(yīng)該檢查這些錯(cuò)誤,這并不是防御性編程,這只是一種好的做法,是編寫正確的代碼的一部分
防御性編程 并不是 測(cè)試:測(cè)試代碼并不是防御,而只是開發(fā)工作的另一份典型的部分。測(cè)試工作不是防御性的,這項(xiàng)工作可以驗(yàn)證代碼現(xiàn)在是正確的,但不能保證代碼在經(jīng)理將來(lái)的修改之后不會(huì)出錯(cuò)。即便是擁有了全世界最好的測(cè)試工具,也還是會(huì)有人對(duì)代碼進(jìn)行更改,并是代碼進(jìn)入過(guò)去未測(cè)試的狀態(tài)
防御性編程并不是調(diào)試:在調(diào)試期間,你可添加一些防御性代碼,不過(guò)調(diào)試是在程序出錯(cuò)之后進(jìn)行的,防御性編程首先是防止程序出錯(cuò)的措施 或者在錯(cuò)誤以不可理解的方式出現(xiàn)之前發(fā)現(xiàn)它們


防御性編程可以節(jié)省大量的調(diào)試時(shí)間,使你可以去做更有意義的事情
編寫可以正確運(yùn)行、只是速度有些慢的代碼,要遠(yuǎn)遠(yuǎn)好過(guò)大多數(shù)時(shí)間都正常運(yùn)行,但是有時(shí)候會(huì)crash的代碼
我們可以設(shè)計(jì)一些在版本構(gòu)建中物理移除的防御性代碼,以解決性能問(wèn)題,總之我們這里所考慮的大部分防御性措施,并不具有明顯的開銷
防御性編程避免了大量的安全問(wèn)題,這是現(xiàn)代軟件開發(fā)中是一個(gè)重大的問(wèn)題,避免這些問(wèn)題可以帶來(lái)很多好處


防御性編程技巧

  1. 使用好的編碼風(fēng)格和合理的設(shè)計(jì)
    我們可以通過(guò)采用良好的編程風(fēng)格,來(lái)防范大多數(shù)編碼錯(cuò)誤,如選用有意義的變量名,或者謹(jǐn)慎的使用括號(hào),在開始coding之前,先考慮大體的設(shè)計(jì)方案,從實(shí)現(xiàn)一套清晰的API、一個(gè)邏輯系統(tǒng)結(jié)構(gòu)以及一些定義良好的組件角色與責(zé)任開始入手
  2. 不要倉(cāng)促的編寫代碼
    使用閃電式編程方式的程序員會(huì)很快的開發(fā)出一個(gè)函數(shù),馬上把這個(gè)函數(shù)交給編譯器來(lái)檢查已發(fā),接著運(yùn)行一邊看看能不能使用,然后進(jìn)入下一個(gè)任務(wù)。這種方式充滿了危險(xiǎn)。相反,在寫每一行時(shí)候都三思,可能會(huì)出現(xiàn)什么錯(cuò)誤,是否已經(jīng)考慮了所有可能出現(xiàn)的邏輯分支,放慢速度,有條不紊編程雖然看上去很平凡,但是的確是減少缺陷的好辦法
  3. 不要相信任何人
    真正的用戶:意外地提供了假的輸入,或者錯(cuò)誤地操作了程序
    惡意的用戶:故意造成不好的程序行為
    客戶端代碼:使用錯(cuò)誤的參數(shù)調(diào)用了你的函數(shù),或者提供了不一致的輸入
    運(yùn)行環(huán)境:沒有為程序提供足夠的服務(wù)
    外部程序庫(kù):運(yùn)行失誤,不遵從你所依賴的接口協(xié)議
  4. 編碼的目標(biāo)是清晰,而不是簡(jiǎn)潔
    如果要你從簡(jiǎn)潔但是可能讓人困惑的代碼和清晰但是有可能比較冗長(zhǎng)的代碼中選擇,一定要選擇那些看上去和預(yù)期相符合的代碼,即使它不太優(yōu)雅。例如,將復(fù)雜的代數(shù)運(yùn)算拆分為一系列的單獨(dú)的語(yǔ)句,使邏輯更清晰。想一想,誰(shuí)會(huì)是的代碼的讀者,這些代碼也許需要一位初級(jí)程序員來(lái)維護(hù),如果他不能理解代碼邏輯,那么他肯定會(huì)犯一些錯(cuò)誤,復(fù)雜的結(jié)構(gòu)或不常用的語(yǔ)言技巧可以證明你在運(yùn)算符優(yōu)先級(jí)方面淵博的知識(shí),但是這些實(shí)際上會(huì)扼殺代碼的可維護(hù)性,請(qǐng)保持代碼簡(jiǎn)單。不能維護(hù)的代碼是不安全,舉一個(gè)極端的例子,過(guò)于復(fù)雜的表達(dá)式會(huì)使編譯器生成錯(cuò)誤的代碼,許多編譯器優(yōu)化的錯(cuò)誤就是因此造成的
  5. 不要讓任何人做他們不該做的修補(bǔ)工作
    內(nèi)部的事情應(yīng)該留在內(nèi)部,私人的東西就應(yīng)該用鎖和鑰匙保管起來(lái),不要吧你的代碼初稿公之于眾,不管你多么有禮貌的懇求,主要稍不注意,別人就會(huì)篡改你的數(shù)據(jù),然后嘗試條用 僅用于執(zhí)行 的例行程序。不要讓他們這么做
    a. 在面向?qū)ο蟮恼Z(yǔ)言中,通過(guò)將屬性設(shè)為 private 來(lái)防止對(duì)內(nèi)部類數(shù)據(jù)的訪問(wèn)
    b. 在過(guò)程語(yǔ)言中,仍可以使用面向?qū)ο蟮拇虬拍?,將private 數(shù)據(jù)打包在不透明的類型背后,并提供可以操作它們的定義良好的公共函數(shù)
    c. 將所有變量保持在盡可能小的范圍內(nèi),不到萬(wàn)不得已,不要聲明全局變量,如果變量可以聲明為函數(shù)內(nèi)部的局部變量,就不要在文件范圍上聲明。如果變量可以聲明為循環(huán)體內(nèi)的局部變量,就不要在函數(shù)范圍上聲明
  6. 編譯時(shí)候打開所有的警告開關(guān)
    大多數(shù)語(yǔ)言的編譯器都會(huì)在你傷了它們感情的時(shí)候給出一大堆錯(cuò)誤信息,當(dāng)這些編譯器碰到潛在的有缺陷的代碼時(shí)候,它們也會(huì)給出各種各樣的警告。通常情況下這些警告可以有選擇地啟用或禁用
    如果代碼中充滿了危險(xiǎn)的構(gòu)造,將會(huì)得到數(shù)頁(yè)的警告信息,糟糕的是,通常的反應(yīng)是禁用編譯器的警告功能,或者干脆不理會(huì)這些信息,這兩種做法都是不可取的
    在任何情況下都要打開你的編譯器的警告功能,如果代碼產(chǎn)生了任何警告信息,應(yīng)立即修正代碼,讓編譯器的報(bào)錯(cuò)聲停下來(lái)。在啟用了警告功能之后,不要對(duì)不能安靜地完成編譯的代碼感到滿意。警告的出現(xiàn)總歸是有原因的,即使你認(rèn)為某個(gè)警告無(wú)關(guān)緊要,也不要置之不理,否則,總有一天這個(gè)警告會(huì)隱藏一個(gè)確實(shí)重要的警告
  7. 使用靜態(tài)分析工具
    編譯器警告是對(duì)代碼的一次有限的靜態(tài)分析,即在程序運(yùn)行之前執(zhí)行代碼的檢查的結(jié)果,還有許多獨(dú)立的靜態(tài)分析工具可以使用,在日常編程工作中,應(yīng)該包括使用這些工具來(lái)檢查你的代碼,它們會(huì)比編譯器跳出更多的錯(cuò)誤
  8. 使用安全的數(shù)據(jù)結(jié)構(gòu)
    如果做不到,就安全地使用危險(xiǎn)的數(shù)據(jù)結(jié)構(gòu)。最常見的安全隱患大概是由緩沖溢出引起的。緩沖溢出是由于不正確的使用固定大小的數(shù)據(jù)結(jié)構(gòu)而造成的。如果代碼在沒有檢查一個(gè)緩沖的大小之前就寫入這個(gè)緩沖,那么寫入的內(nèi)容總是可能會(huì)超出緩沖的末尾的
  9. 檢查所有的返回值
    如果一個(gè)函數(shù)返回一個(gè)值,它這樣做肯定是有理由的。檢查這個(gè)返回值,如果返回值是一個(gè)錯(cuò)誤的代碼,就必須辨別這個(gè)代碼并處理所有的錯(cuò)誤,不要讓錯(cuò)誤悄無(wú)聲息的侵入程序,忍受錯(cuò)誤會(huì)導(dǎo)致不可預(yù)知的行為,這既適用于用戶自定義的函數(shù),也適用于標(biāo)準(zhǔn)庫(kù)的函數(shù),大多數(shù)難以察覺的錯(cuò)誤都是因?yàn)槌绦騿T沒有檢查返回值而出現(xiàn)的,不要忘記,某些函數(shù)會(huì)通過(guò)不同的機(jī)制返回錯(cuò)誤,不論合適都要在適應(yīng)的級(jí)別上捕獲和處理相應(yīng)的異常
  10. 謹(jǐn)慎的處理內(nèi)存 和其他寶貴的資源
    對(duì)于在執(zhí)行期間所獲取的任何資源,必須徹底釋放。內(nèi)存使這類資源最常提到的一個(gè)例子,但是并不是唯一的一個(gè)。文件和縣城所也是必須小心使用的寶貴資源,做一個(gè)好管家
    不要因?yàn)橛X得操作系統(tǒng)會(huì)在你的程序退出時(shí)候清除程序,就不注意關(guān)閉文件或釋放內(nèi)存。對(duì)于代碼還會(huì)執(zhí)行多長(zhǎng)時(shí)間,是否會(huì)耗盡所有的文件句柄或者占用所有的內(nèi)存,你對(duì)此一無(wú)所知,甚至不能肯定操作系統(tǒng)是否會(huì)完全釋放你的資源,有的操作系統(tǒng)不是這樣的。Java 和 .NET 使用垃圾回收機(jī)制來(lái)執(zhí)行這些繁重的清潔工作,在運(yùn)行時(shí)會(huì)不時(shí)的清掃,不過(guò)不要因此對(duì)安全性抱有錯(cuò)誤的想法,你仍然需要思考,你必須顯示地終止對(duì)那些不再需要,或者不會(huì)被自動(dòng)清除的對(duì)象的引用:不要意外的保留對(duì)對(duì)象的引用。不太現(xiàn)今的垃圾回收器也很容易被循環(huán)引用蒙蔽(A引用B,B又引用A,除此之外沒有對(duì)A和B的引用),這就會(huì)導(dǎo)致對(duì)象永遠(yuǎn)不會(huì)被清除;這就是一種難以發(fā)現(xiàn)的內(nèi)存泄露形式
  11. 在聲明位置初始化所有變量
  12. 盡可能推遲一些聲明變量
    這樣可以使變量的聲明位置與使用它的位置盡量接近,從而防止它干擾代碼的其他部分,這樣做也是的使用變量的代碼更加清晰,不再需要導(dǎo)出尋找變量的類型和初始化,在附近聲明使用這些都變得非常明顯。不要在多個(gè)地方重用同一個(gè)臨時(shí)變量,即使每次使用都在邏輯上相互分離的區(qū)域中進(jìn)行。變量重用會(huì)使得以后對(duì)代碼重新完善的工作變得異常復(fù)雜,每次創(chuàng)建一個(gè)新的變量---編譯器會(huì)解決任何有關(guān)效率的問(wèn)題
  13. 使用標(biāo)準(zhǔn)語(yǔ)言庫(kù)
    明確的定義你正在適應(yīng)的是哪個(gè)語(yǔ)言版本,除非項(xiàng)目要求,否則不要將命運(yùn)交給編譯器,或者對(duì)該語(yǔ)言的任何非標(biāo)準(zhǔn)的擴(kuò)展。如果該語(yǔ)言的某個(gè)領(lǐng)域還沒定義,就不要依賴你所使用的特定編譯器的行為,這樣會(huì)產(chǎn)生非常脆弱的代碼
  14. 使用好的診斷信息日志工具
    當(dāng)編寫新的代碼時(shí)候,常會(huì)加入許多診斷信息,以確定程序的運(yùn)行情況,在調(diào)試結(jié)束后是否應(yīng)該刪除這些診斷信息吶?保留這些信息對(duì)以后再次訪問(wèn)代碼會(huì)帶來(lái)很多方便,特別是如果在此期間可以有選擇地禁用這些信息。有許多診斷信息日志系統(tǒng)可以幫助實(shí)現(xiàn)這種功能,這些系統(tǒng)中很多都可以使診斷信息在不需要的時(shí)候不帶來(lái)任何開銷,可以有選擇的使它們不參加編譯
  15. 謹(jǐn)慎地進(jìn)行強(qiáng)制轉(zhuǎn)換
    大多數(shù)語(yǔ)言都允許你將數(shù)據(jù)從一種類型強(qiáng)轉(zhuǎn)或者轉(zhuǎn)換為另一種類型,這種操作有時(shí)候比其他操作更成功,如果試著將一個(gè)64位的整數(shù)轉(zhuǎn)換為較小的8位數(shù)據(jù)類型,那么其他56位會(huì)怎么樣,你的執(zhí)行環(huán)境可能會(huì)突然拋出異常,或者悄悄地將你的數(shù)據(jù)的完整性降級(jí),因此程序就會(huì)表現(xiàn)出不正常的行為
  16. 細(xì)則
    低級(jí)別防御性代碼的編寫技巧有很多,這些技巧是日常編程工作的組成部分,包含在對(duì)現(xiàn)實(shí)世界的一種健康的懷疑當(dāng)中,下面幾條細(xì)則值得考慮:
    提供默認(rèn)的行為
    遵從語(yǔ)言習(xí)慣
    檢查數(shù)值的上下限
    正常設(shè)置常量

約束:
我們?nèi)绾伟丫幊虝r(shí)候做的一些設(shè)想 切實(shí)地與我們的軟件聯(lián)系起來(lái),從而使它們不再成為隨時(shí)會(huì)出現(xiàn)的問(wèn)題?只需要編寫一小段額外的代碼來(lái)檢查每種可能出現(xiàn)的情況。這段代碼充當(dāng)每個(gè)設(shè)想的記錄,使設(shè)想從暗處走到了明處。通過(guò)這種方式,就把約束編入到了程序的功能和行為當(dāng)中。
當(dāng)約束被破壞了,遭到破壞的約束不僅僅是一個(gè)簡(jiǎn)單的容易找到和更正的運(yùn)行時(shí)的錯(cuò)誤,事實(shí)上我們已經(jīng)無(wú)時(shí)無(wú)刻不在做這種檢查和處理,它一定是存在于程序邏輯中的一個(gè)缺陷,我們對(duì)程序可能做出的反應(yīng)有以下幾種:

  1. 對(duì)問(wèn)題視而不見,期望最終不會(huì)因此出現(xiàn)任何差錯(cuò)
  2. 做一些小改動(dòng),使程序得以繼續(xù)運(yùn)行,如打印一份診斷報(bào)告,或者將錯(cuò)誤記錄到日志中
  3. 直接把程序打入冷宮,不讓它繼續(xù)運(yùn)行下去,以立即受控或者非受控的方式終止程序

在許多不同的場(chǎng)景中都需要運(yùn)用約束:

  1. 前置條件:這些條件是在輸入一段代碼之前必須保持為真的條件,如果前置條件不成立,那是因?yàn)榭蛻舳舜a的缺陷所致
  2. 后置條件:這些條件是編寫一段代碼之后必須保持為真的條件,如果后置條件不成立,那是因?yàn)樘峁┱叽a的錯(cuò)誤所致
  3. 不變條件:這些條件是每當(dāng)程序的執(zhí)行到達(dá)一個(gè)特定點(diǎn),如循環(huán)中,方法調(diào)用等等,時(shí)都保持為真的條件,如果不變條件不成立,則意味著程序邏輯存在錯(cuò)誤
  4. 斷言:斷言是任何其他關(guān)于程序在給定位置狀態(tài)的陳述

#如果沒有語(yǔ)言的支持,實(shí)施上面的所列的前兩個(gè)條件將非常困難,如果一個(gè)函數(shù)有多個(gè)退出點(diǎn),那么插入后置條件就會(huì)非常麻煩。Eiffel在核心語(yǔ)言中支持前置和后置條件,并且也可以確保約束校驗(yàn)不帶有任何副作用。雖然很乏味,但是代碼中所表達(dá)的好的約束可以使你的程序更加清晰,也更加易于維護(hù),由于約束構(gòu)成了代碼段之間一個(gè)不可改變的契約,所以這一技術(shù)也稱作“契約式設(shè)計(jì)”(design by contract)

  1. 約束內(nèi)容
    a. 檢查所有的數(shù)組訪問(wèn)是否都在邊界內(nèi);
    b. 在廢棄的指針之前斷言指針是非零的;
    c. 確保函數(shù)的參數(shù)有效;
    d. 在函數(shù)的結(jié)果返回之前對(duì)其進(jìn)行充分的檢查;
    e. 在操作對(duì)象之前證明他的狀態(tài)是一致的;
    f. 警惕代碼中會(huì)寫下的注釋“不應(yīng)該執(zhí)行到這里”的任何一段;
    g. 可讀性是衡量程序質(zhì)量的最佳標(biāo)準(zhǔn),如果一個(gè)程序易于閱讀,那么這個(gè)程序就可能是一個(gè)好的程序
    h. 在主要的函數(shù)中放置前置條件和后置條件,并且在關(guān)鍵的循環(huán)中放置不變條件就已足夠
  2. 移除約束
    通常只有在程序構(gòu)建的開發(fā)和調(diào)試階段,才需要這種約束校驗(yàn),當(dāng)用約束使自己確信(無(wú)論實(shí)際對(duì)錯(cuò))程序的邏輯是正確之后,理論上就應(yīng)該移除它們,從而節(jié)省很多不必要的運(yùn)行時(shí)的開銷

進(jìn)攻性編程:需要主動(dòng)嘗試打破代碼中的常規(guī),而不只是防止問(wèn)題的發(fā)生,也就是,不是保護(hù)代碼,而是主動(dòng)進(jìn)攻代碼,這種策略也叫測(cè)試。嚴(yán)格的測(cè)試對(duì)軟件考法具有不可低估的正面影響,可以極大地提高代碼質(zhì)量,并且使開發(fā)過(guò)程變得穩(wěn)定起來(lái)
都應(yīng)該成為進(jìn)攻性程序員
筆者等項(xiàng)目時(shí)間寬松點(diǎn)的時(shí)候,在繼續(xù)搜集進(jìn)攻性編程資料,然后再整理


總結(jié):
編寫不僅正確而且優(yōu)秀的代碼非常重要,這需要積累下所有已作出的設(shè)想,這將會(huì)使得維護(hù)更加容易,也會(huì)使得錯(cuò)誤減少。防御性編程是一種預(yù)想最壞的情況并為之做好準(zhǔn)備的方法。這是一種可以防止簡(jiǎn)單的錯(cuò)誤變得難以找到的錯(cuò)誤的技術(shù)
與防御性代碼一起使用編入代碼的約束,可以使你的軟件更加健壯。與其他好的編碼習(xí)慣,如單元測(cè)試一樣,防御性編程也是明智的并且比較早的多花一些額外的時(shí)間,以便在以后節(jié)省更多的時(shí)間,精力和成本,這樣可以使整個(gè)項(xiàng)目免于crash


如果錯(cuò)誤攻破了你謹(jǐn)慎的防御,你將需要一種策略來(lái)驅(qū)逐它們
防御性編程是編寫安全的軟件系統(tǒng)的關(guān)鍵技術(shù)
你必須記錄前置和后置條件,不然別人怎么知道它們的存在?如果你指定了任何約束,就可以添加防御性代碼來(lái)斷言它們


何時(shí)進(jìn)行防御性編程?
你是否在事情不順利時(shí)候才開始這么做?或者在整理了一些你不理解的代碼的時(shí)候才開始?這樣是不對(duì)的,應(yīng)該從始至終地使用這些防御性編程的技巧。成熟的程序員已經(jīng)從經(jīng)驗(yàn)中得到教訓(xùn),在吃過(guò)不止一遍的苦頭后才明白增加防御措施是明智的。
在開始編寫代碼的時(shí)候就應(yīng)用防御性策略,比改進(jìn)代碼時(shí)才應(yīng)用要容易的多。如果恨晚才試著將這些策略強(qiáng)加進(jìn)去,就不可能做到萬(wàn)無(wú)一失。如果在問(wèn)題出現(xiàn)后才開始添加防御性代碼,實(shí)際上是在調(diào)試,被動(dòng)地做出反應(yīng),而不是積極地防患于未然
然而在調(diào)試的過(guò)程中,甚至在添加新的功能時(shí)候,會(huì)發(fā)現(xiàn)一些希望驗(yàn)證的情況,這常常是添加防御性代碼的好時(shí)機(jī)


糟糕的程序員:
不愿意去考慮他們的代碼出錯(cuò)的情況
為繼承才發(fā)布可能會(huì)出錯(cuò)的代碼,并希望別人會(huì)找到錯(cuò)誤
將關(guān)于如何使用他們代碼的信息緊緊攥在手里,并隨時(shí)都可能將其丟掉
很少思考他們正在編寫的代碼,從而產(chǎn)生不可預(yù)知的和不可靠的代碼

優(yōu)秀的程序員:
關(guān)心他們的代碼是否健壯
確保每個(gè)設(shè)想都是顯式地體現(xiàn)在防御性代碼中
希望代碼對(duì)無(wú)用信息的而輸入有正確的行為
在編碼的時(shí)候認(rèn)真思考所編寫的代碼
編寫可以保護(hù)自己不受其他人或者程序員自己 愚蠢傷害的代碼


 不定期更新 不合適的地方 還請(qǐng)指點(diǎn)~ 感激不盡
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容