[寫在開始]代碼質(zhì)量是每個項目都在呼吁的郊丛。卻是大家都不愿實施的虫给。長期效益誘惑抵抗不了短期收益的現(xiàn)實躯喇。目前辫封,它給予的程序猿只有自我滿足和成就感。一個深陷老舊系統(tǒng)無法脫身程序員面對代碼無奈大家都有耳聞廉丽。在追求交付至上的項目倦微,代碼質(zhì)量問題不是團隊、項目璃诀、公司面臨的問題,只屬于程序猿蔑匣。
最近花時間整理:我對代碼的可讀性和可測試性理解。代碼質(zhì)量提升又沒有統(tǒng)一標準裁良,如果尋找不可能完成的任務(wù):說服程序猿修改自己的代碼,一定包含其中价脾。所以,本文純屬個人理解侨把。
這篇文章分為2部分:代碼可讀性和代碼可測試性犀变。
可讀性和可測試是沒有統(tǒng)一的量化標準获枝,尤其是新語言不斷涌現(xiàn)的。
一切量化指標都有綱領(lǐng)性文件骇笔。本文指導性綱領(lǐng):最為我們熟知的是SOLID, KISS, DRY ...。內(nèi)容是他們的具體化笨触。
1、注釋可讀性原則
代碼用來維護和閱讀的"文檔"芦劣,代碼是功能最直接的傳達者。而注釋是為什么要如此傳達的解釋虚吟。開發(fā)模式摒棄注釋本身就不利于代碼可讀性和可維護性源梭。注釋編寫包括如下幾個方面娱俺。
- 注釋內(nèi)容
注釋描述為什么code,而不是code是什么废麻。最好描述code是什么的是:代碼實現(xiàn),而不是字面的描述荠卷。而為什么這么做,是代碼無法描述的烛愧。 - 注釋變化
保持注釋持續(xù)更新油宜,使之與當前實現(xiàn)匹配。不匹配的注釋非但不是理解code的助推器怜姿,反而是阻燃劑慎冤。 - 不要添加無意義的注釋
- 不增加的關(guān)于調(diào)試信息描述
getUTCTime()// debug:獲取UTC 用于記錄耗時
- 不要無意義的注釋
new Date() // 生成Date 信息
以上反例表明:能用代碼解決的就不要加注釋。
- 注釋跟蹤
注釋跟蹤:記錄代碼注釋歷史沧卢。既為了追溯蚁堤,也便于閱讀者和修改方進行信息傳遞。
2但狭、通用可讀性原則
通用原則指對變量披诗、方法、以及類都適用的原則立磁。
- 格式規(guī)范化
項目規(guī)范代碼格式化內(nèi)容呈队。諸如 空格縮進、方式修飾符使用唱歧、{}宪摧、if ...else.. 等控制關(guān)鍵字使用、駝峰式命名或者匈牙利命名等颅崩。規(guī)劃化的格式才是代碼可讀性的基礎(chǔ)几于。 - 命名規(guī)范化
- 英文使用規(guī)劃化
比如:修復對應(yīng)的英文, 包括repair fix ...。如何選擇合適的詞匯來描述沿后。盡量使用軟件行業(yè)專用詞匯沿彭,對老舊系統(tǒng)即使無法統(tǒng)一,也不要出現(xiàn)相同術(shù)語而使用不同的詞匯得运。 - 不要在命名中嵌入數(shù)據(jù)類型尤其是函數(shù)中
- 英文使用規(guī)劃化
//功能是把日期轉(zhuǎn)換成Int膝蜈,這是不建議的方式锅移,*函數(shù)的返回類型*標識的Int
//函數(shù)中加入類型是畫蛇添足
.... //偽代碼
getDate2Int()
使用好的框架
避免重復造輪子熔掺,使用好的框架。在每個領(lǐng)域都有優(yōu)秀的開源框架非剃。如數(shù)據(jù)庫連接池管理庫Druid HikariCP DBCP...置逻,線程池管理框架、支持緩存的Redis备绽,CacheMem券坞。優(yōu)秀的框架即戰(zhàn)力很強大鬓催,我們都值得擁有。避免重復的代碼
堅持DRY(don't repeat yourself.)原則一百年不動搖恨锚。代碼模塊化
模塊化沒有直接受益,我只能說對可讀性而言太重要猴伶。
模塊化和組件化設(shè)計意味著最小知識、技能和依賴在系統(tǒng)中筝尾,防止教條出現(xiàn)、構(gòu)建抽象層筹淫、避免設(shè)計復雜的相互依賴呢撞、功能獨立性等....代碼review原則
讓review真正運作起來。review代碼是檢驗可讀性最佳標準薛匪。review過程中的逸尖,信息溝通和經(jīng)驗傳遞是提升編碼水平和形成習慣的最佳途徑瘸右。
- 給代碼以時間
套用大劉的這句話。試想幾個月后甚至更久后苞俘,我們回看代碼龄章,若邏輯不清晰、結(jié)構(gòu)待調(diào)整岗憋,說明代碼可讀性有提升空間锚贱。如果你意識到代碼可讀性差,也表明個人能力提升晋修。所以一切交給時間吧凰盔。
3、函數(shù)可讀性原則
- 函數(shù)簡短化
受過長函數(shù)苦的趴拧,就不要讓其它人繼續(xù)受累山叮。我們不武斷提倡每個函數(shù)少于5行,但絕不讓它們超過 50行脑又。 - 參數(shù)列表簡短化
限制參數(shù)的長度锐借, 3~5個為宜。過長的參數(shù)列表严卖,往往意味這超長的函數(shù)和復雜代碼邏輯哮笆。 - 參數(shù)最小化原則
遵守參數(shù)最小化原則汰扭,即不需要的參數(shù)不用傳入。參數(shù)沒有最小化项阴,是代碼腐化的主要原因笆包。
calss Person(name: String, addr: String, age: Int, sex: String)
def isFemale(person: Person): Boolean = {
....
}
上例中判斷是否是性別歉胶,只用傳入sex就滿足功能要求跨扮,傳入的參數(shù)是Person 違背參數(shù)最小化原則验毡。
- 代碼執(zhí)行邏輯統(tǒng)一
我們功能實現(xiàn)時,過程控制條件太多晶通,且沒有統(tǒng)一邏輯。代碼經(jīng)骋灰玻看到if ...else...滿天飛椰苟,但細讀下來各個分支邏輯并不同树叽。如下正例:都是根據(jù)小時條件生成結(jié)果。反例則可讀性不高洁仗。
{
DateTime time = DateTime.Now;
if (time.Hour >= 0 && time.Hour < 6)
{
return "Night";
}
if (time.Hour >= 6 && time.Hour < 12)
{
return "Morning";
}
....
return "Evening";
}
//反例性锭,lineitem card并不是一個維度內(nèi)容
if (lineItem != null && (lineItem.quantity > 0 && customer.isActive() && (card.expirityYear > 2010 || card.type == AMX)) || couponCode.isValid()) {
// details..
}
//封面圖是又一可讀性反證
代碼有效性
義無反顧的刪除過期代碼和調(diào)試代碼草冈。減少無用日志輸出。讓代碼有意義單一職責
就是我們常說的SRP方淤。就函數(shù)而言蹄殃,保證以上原則SRP就滿足了。
3讳苦、類可讀性原則
數(shù)據(jù)類和實現(xiàn)類分離
數(shù)據(jù)的提供者和使用者分離鸳谜。避免類中存儲數(shù)據(jù)式廷,外部數(shù)據(jù)在類生成時傳入,類只負責對數(shù)據(jù)的操作蝗肪。不同類提供不同接口
如果內(nèi)部相似的類,對外卻提供不同的接口辛馆,讓其接口統(tǒng)一:創(chuàng)建接口層豁延,etc.保持內(nèi)外提供相同接口。簡化初始化邏輯
面向?qū)ο缶幊烫桑嘀乩^承讓類初始化邏輯異常復雜袋狞。為了簡化邏輯,類初始化邏輯耦合盡量小法焰。減少類接口暴露數(shù)量
是時候使用訪問級別修飾符限定訪問權(quán)限埃仪,和簡化對外接口陕赃。明確函數(shù)歸屬原則
若函數(shù)實現(xiàn)依賴其它類,那么它屬于依賴函數(shù)傻丝,而不是當前類诉儒。隔離依賴
常見場景:依賴庫如無法進行修改,為了將來便于使用新依賴庫泛释,構(gòu)造接口類進行隔離温算。防止對舊有庫的行為使用。廢棄任何不必須類
任何類都會增加項目的復雜度茄茁,多余功能類進行廢棄和合并重構(gòu)類
如果一個類修改,同時要修改若干其它類付燥,對該類進行進行重構(gòu)锦庸。保證修改僅限在一個類中甘萧。新需求引入穩(wěn)定系統(tǒng)梆掸,可行性方案越少,越利于維護怪得。系統(tǒng)腐化的風險越小卑硫。
后續(xù)
代碼可讀性個人性很強。不同的階段入挣,對美的理解不同径筏。就如同欣賞NBA比賽障陶,時間久了,馬刺黑恢氯,也會成為刺蜜鼓寺。品味是個很玄幻的東西,要個人努力和時間積累指黎。
一切的提升源于認識深入州丹。