作為開(kāi)發(fā)者,我們必須要學(xué)會(huì)defensive programming,尤其是對(duì)要求高可靠性和無(wú)人職守的企業(yè)級(jí)應(yīng)用中,需要特別留意我們的設(shè)計(jì)和編碼,必須盡可能做到足夠defensive。
什么是defensive programming?舉個(gè)大家都看過(guò)的例子:
String str = ...
if ("".equals(str)) {}
在這里我們不寫str.equals("")而是反過(guò)來(lái),就是為了防止出現(xiàn)不必要的NPE – NullPointerException。
運(yùn)行期異常是最最需要特別關(guān)照的一種非正常狀況,除了像上面這類要求我們采用相對(duì)較好的編碼習(xí)慣之外,為了減少運(yùn)行期異常的發(fā)生,通常也需要使用try-catch代碼塊來(lái)把我們相對(duì)脆弱,或者需要格外保護(hù)的邏輯包起來(lái),對(duì)于外部傳進(jìn)來(lái)的參數(shù),一定要assert它們的合法性,即assert它們是否能夠安全的被后面的邏輯所使用。
通常意義上,defensive programming主要cover的是避免不必要的運(yùn)行期異常發(fā)生。我們可以更進(jìn)一步,更廣義的運(yùn)用defensive programming的核心思想:在企業(yè)應(yīng)用中,除了運(yùn)行期異常,對(duì)于有些看似嚴(yán)重的極端的錯(cuò)誤,如網(wǎng)絡(luò)超時(shí),連接丟失,數(shù)據(jù)庫(kù)提交失敗等情況,需要我們具體問(wèn)題具體分析,并非所有checked exception都一定需要我們?nèi)ヒ灰籧atch然后處理。更多的時(shí)候,尤其當(dāng)開(kāi)發(fā)無(wú)人職守的后臺(tái)程序,我們可以采取重試、報(bào)告、修改外部數(shù)據(jù)等方式處理,能夠自行解決的,就不要?jiǎng)硬粍?dòng)就報(bào)錯(cuò),或等待用戶確認(rèn),不能自行解決的,則要及時(shí)報(bào)告并停止運(yùn)行,避免更大的錯(cuò)誤發(fā)生。
舉個(gè)相對(duì)具體的例子,兩個(gè)異構(gòu)的系統(tǒng),通過(guò)一個(gè)中間層的消息平臺(tái)相互發(fā)送消息,通信協(xié)議采用最基本的socket方式,這三個(gè)系統(tǒng)隨時(shí)都可能出現(xiàn)宕機(jī)或鏈接中斷的情況。為了保證數(shù)據(jù)的完整性,我們拿其中一個(gè)需要發(fā)送和接收消息的系統(tǒng)來(lái)細(xì)說(shuō):
一個(gè)可能的實(shí)現(xiàn)方式是:該系統(tǒng)所有要發(fā)送的消息保存到數(shù)據(jù)庫(kù),給它一個(gè)初始狀態(tài);另一個(gè)獨(dú)立進(jìn)程從數(shù)據(jù)庫(kù)按照時(shí)間先后拿出消息,更新拿出的這條消息的狀態(tài)為處理中,并嘗試發(fā)送消息;成功后根據(jù)需要,更新消息狀態(tài)為成功發(fā)送或者直接刪除,如果遇到失敗或異常,消息恢復(fù)為初始狀態(tài),線程sleep一段時(shí)間,然后再次嘗試,多次嘗試或者嘗試跨度超過(guò)一定時(shí)間范圍,則停止處理,向管理員匯報(bào)(通過(guò)郵件、短信等途徑)。對(duì)于接收到的消息,同樣是先存入數(shù)據(jù)庫(kù),然后再由后續(xù)的進(jìn)程用類似的方式取出并處理。如果程序崩潰,可以自動(dòng)重新啟動(dòng)(應(yīng)用或整個(gè)服務(wù)器)。這樣不管哪一段通信線路出現(xiàn)故障或阻塞,或者宕機(jī),系統(tǒng)都可以一步一個(gè)腳印,確保任務(wù)主動(dòng)而自動(dòng)的執(zhí)行,并且忠實(shí)記錄下有價(jià)值的狀態(tài)信息,出現(xiàn)問(wèn)題時(shí)管理員可以很直觀的看到在哪個(gè)環(huán)節(jié)出現(xiàn)故障,從而快速找到問(wèn)題關(guān)鍵并有效解決。
Defensive programming可以讓我們的應(yīng)用更健壯,在保證數(shù)據(jù)正確性、完整性的前提下,面對(duì)困難也能更加獨(dú)立自主。和defensive programming相關(guān)的話題我想大家如果感興趣,可以展開(kāi)更多更深入的探討,這里只是給大家做個(gè)介紹性的鋪墊,能拋磚引玉當(dāng)然更好。