魔鬼在細節中

最近一直擔心Dubbo分佈式服務框架後續如果維護人員增多或變更,會出現質量的下降,
我在想,有沒有什麼是需要大家共同遵守的,
根據平時寫代碼時的一習慣,總結了一下在寫代碼過程中,尤其是框架代碼,要時刻牢記的細節,
可能下面要講的這些,大家都會覺得很簡單,很基礎,但要做到時刻牢記,
在每一行代碼中都考慮這些因素,是需要很大耐心的,
大家經常說,魔鬼在細節中,確實如此。

1. 防止空指針和下標越界
這是我最不喜歡看到的異常,尤其在覈心框架中,我更願看到信息詳細的參數不合法異常,
這也是一個健狀的程序開發人員,在寫每一行代碼都應在潛意識中防止的異常,
基本上要能確保一次寫完的代碼,在不測試的情況,都不會出現這兩個異常纔算合格。

2. 保證線程安全性和可見性
對於框架的開發人員,對線程安全性和可見性的深入理解是最基本的要求,
需要開發人員,在寫每一行代碼時都應在潛意識中確保其正確性,
因爲這種代碼,在小併發下做功能測試時,會顯得很正常,
但在高併發下就會出現莫明其妙的問題,而且場景很難重現,極難排查。

3. 儘早失敗和前置斷言
儘早失敗也應該成爲潛意識,在有傳入參數和狀態變化時,均在入口處全部斷言,
一個不合法的值和狀態,在第一時間就應報錯,而不是等到要用時才報錯,
因爲等到要用時,可能前面已經修改其它相關狀態,而在程序中很少有人去處理回滾邏輯,
這樣報錯後,其實內部狀態可能已經混亂,極易在一個隱蔽分支上引發程序不可恢復。

4. 分離可靠操作和不可靠操作
這裏的可靠是狹義的指是否會拋出異常或引起狀態不一致,
比如,寫入一個線程安全的Map,可以認爲是可靠的,
而寫入數據庫等,可以認爲是不可靠的,
開發人員必須在寫每一行代碼時,都注意它的可靠性與否,
在代碼中儘量劃分開,並對失敗做異常處理,
併爲容錯,自我保護,自動恢復或切換等補償邏輯提供清晰的切入點,
保證後續增加的代碼不至於放錯位置,而導致原先的容錯處理陷入混亂。

5. 異常防禦,但不忽略異常
這裏講的異常防禦,指的是對非必須途徑上的代碼進行最大限度的容忍,
包括程序上的BUG,比如:獲取程序的版本號,會通過掃描Manifest和jar包名稱抓取版本號,
這個邏輯是輔助性的,但代碼卻不少,初步測試也沒啥問題,
但應該在整個getVersion()中加上一個全函數的try-catch打印錯誤日誌,並返回基本版本,
因爲getVersion()可能存在未知特定場景異常,或被其他的開發人員誤修改邏輯(但一般人員不會去掉try-catch),
而如果它拋出異常會導致主流程異常,這是我們不希望看到的,
但這裏要控制個度,不要隨意try-catch,更不要無聲無息的吃掉異常。

6. 縮小可變域和儘量final
如果一個類可以成爲不變類(Immutable Class),就優先將它設計成不變類,
不變類有天然的併發共享優勢,減少同步或複製,而且可以有效幫忙分析線程安全的範圍,
就算是可變類,對於從構造函數傳入的引用,在類中持有時,最好將字段final,以免被中途誤修改引用,
不要以爲這個字段是私有的,這個類的代碼都是我自己寫的,不會出現對這個字段的重新賦值,
要考慮的一個因素是,這個代碼可能被其他人修改,他不知道你的這個弱約定,final就是一個不變契約。

7. 降低修改時的誤解性,不埋雷
前面不停的提到代碼被其他人修改,這也開發人員要隨時緊記的,
這個其他人包括未來的自己,你要總想着這個代碼可能會有人去改它,
我應該給修改的人一點什麼提示,讓他知道我現在的設計意圖,
而不要在程序裏面加潛規則,或埋一些容易忽視的雷,
比如:你用null表示不可用,size等於0表示黑名單,
這就是一個雷,下一個修改者,包括你自己,都不會記得有這樣的約定,
可能後面爲了改某個其它BUG,不小心改到了這裏,直接引爆故障。
對於這個例子,一個原則就是永遠不要區分null引用和empty值。

8. 提高代碼的可測性
這裏的可測性主要指Mock的容易程度,和測試的隔離性,
至於測試的自動性,可重複性,非偶然性,無序性,完備性(全覆蓋),輕量性(可快速執行),
一般開發人員,加上JUnit等工具的輔助基本都能做到,也能理解它的好處,只是工作量問題,
這裏要特別強調的是測試用例的單一性(只測目標類本身)和隔離性(不傳染失敗),
現在的測試代碼,過於強調完備性,大量重複交叉測試,
看起來沒啥壞處,但測試代碼越多,維護代價越高,
經常出現的問題是,修改一行代碼或加一個判斷條件,引起100多個測試用例不通過,
時間一緊,誰有這個閒功夫去改這麼多形態各異的測試用例?
久而久之,這個測試代碼就已經不能真實反應代碼現在的狀況,很多時候會被迫繞過,
最好的情況是,修改一行代碼,有且只有一行測試代碼不通過,
如果修改了代碼而測試用例還能通過,那也不行,表示測試沒有覆蓋到,
另外,可Mock性是隔離的基礎,把間接依賴的邏輯屏蔽掉,
可Mock性的一個最大的殺手就是靜態方法,儘量少用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章