最近重讀了一遍《程式碼整潔之道》,這本書既是整潔程式碼的定義,也是寫出整潔程式碼的指南。我認為既適合新手閱讀,快速提升程式碼質量;也適合老鳥閱讀,持續精進。本篇將彙總《程式碼整潔之道》的必讀要點,把書讀薄,方便各位快速閱讀。
為什麼要閱讀《程式碼整潔之道》
第一,是個程式設計師;第二,想成為更好的程式設計師。
一、什麼是程式碼整潔之道?
有多少程式設計師,就有多少對整潔程式碼的定義。就像武術家一樣,有不同的流派,程式碼整潔也有不同的思想流派。鮑勃大叔是 「物件導師整潔程式碼派」的,《程式碼整潔之道》一書傳授正是這一流派的思想和方法。
二、有意義的命名是什麼樣子的?
- 名副其實
例:使用有意義的名稱代替魔法數 - 避免誤導
例:避免使用小寫字母l和大寫字母O作為變數名 - 做有意義的區分
例:新增變數新增數字(a1、a2)、或者廢話(nameString)是沒有意義的 - 使用讀得出來的名稱
- 使用可搜尋的名稱
單字母名稱僅用於段方法中的本地變數;變數名稱應與其作用域大小相對應。 - 避免使用編碼
- 避免思維對映
- 類名
類名和物件名應該是名詞或者名詞短語 - 方法名
方法名應該是動詞或者動詞短語 - 別抖機靈
- 每個概念對應一個詞
- 別用雙關語
- 使用解決方案領域名稱
- 使用源自所涉問題領域的名稱
- 新增有意義的語境、不要新增沒用的語境
三、如何寫好函式
每個系統都是使用某種領域特定語言搭建,而這種語言是程式設計師設計來描述那個系統的。函式是語言的動詞,類是名詞。程式設計藝術是且一直就是語言設計的藝術。
大師級程式設計師把系統當作故事來講,而不是當作程式來寫。他們使用選定程式語言提供的工具構建一種更為豐富且更具表達力的語言,用來講那個故事。
寫函式需要乾淨利落,這樣可以形成一種精確而清晰的語言,幫助講故事。
- 短小
函式的第一條規則是要短小,第二條規則是還要更短小。 - 只做一件事情
函式應該只做一件事情。做好這件事。只做一件事。 - 每個函式一個抽象層級
- 使用具有描述性的名稱
如果每個例程都讓你感到深合己意,那就是整潔程式碼。
別害怕長名稱。長而具有描述性的名稱,要比短而令人費解的名稱好。長而具有描述性的名稱,要比描述性的長註釋好。使用某種命名約定,讓函式名稱中的多個單詞容易閱讀,然後使用這些單詞給函式取個能說清其功用的名稱。 - 函式引數
函式引數越少越好,最理想的引數數量是0個。
標識引數是醜陋不堪的,想函式傳入布林值簡直是駭人聽聞的做法,更好的做法是將函式一分為二。
如果函式需要2個、3個或者3個以上的引數,可以將其中一些引數封裝成類。 - 無副作用
- 分隔指令與詢問
函式應該修改某物件的狀態,或是返回該物件有關的資訊,如果兩樣都幹,常會導致混亂。 - 使用異常代替返回錯誤碼
- 別重複自己
- 結構化程式設計
結構化程式設計認為,每個函式、函式中的每個程式碼塊都應該有一個入口、一個出口。
鮑勃大叔雖然贊成結構化程式設計的目標和規範,但認為只要函式保持短小,偶爾出現的return、break或continue語句沒有壞處,甚至還比單入單出原則更具有表達力。
四、註釋
什麼也比不上放置良好的註釋來得有用。什麼也不會比亂七八糟的註釋更有本事搞亂一個模組。什麼也不會比陳舊、提供錯誤資訊的註釋更有破壞性。
好註釋與壞註釋:
好註釋 | 壞註釋 |
---|---|
1 法律資訊 2 提供資訊的註釋 3 對意圖的解釋” 4 闡釋 5 警示 6 TODO註釋 7 放大 8 公共API中的Javadoc |
1 喃喃自語 2 多餘的註釋 3 誤導性註釋 4 循規式註釋 5 日誌式註釋 6 廢話註釋 7 可怕的廢話 8 能用函式或變數時就別用註釋 9 位置標記 10 括號後面的註釋 11 歸屬與署名 12 註釋掉的程式碼 13 HTML註釋 14 非本地資訊 15 資訊過多 16 不明顯的聯絡 17 函式頭 18 非公共程式碼中的Javadoc |
五、格式
程式碼格式不可忽略。程式碼格式關乎溝通,而溝通是專業開發者的頭等大事。
5.1 垂直格式
- 向報紙學習
原始檔要像報紙文章那樣。名稱簡單且一目瞭然。名稱本身應該足夠告訴我們是否在正確的模組中。
原始檔最頂部應該給出高層次概念和演算法。細節應該往下漸次展開,直至找到原始檔中最底層的函式和細節。 - 概念間垂直方向上的區隔
每個空白行都是一條線索,標識出新的獨立概念。 - 垂直方向上靠經
緊密相關的程式碼應該互相靠近。 - 垂直距離
變數宣告應儘可能靠近其使用位置。 - 垂直順序
被呼叫的函式應該放在執行呼叫的函式下面,這樣可以建立了一種自頂向下貫穿原始碼模組的良好資訊流。
5.2 橫向格式
一行程式碼應該有多寬?
應該遵循無需拖動捲軸到右邊的原則。鮑勃大叔認為這個上限是120個字元。
- 水平方向上的區隔和靠近
我們使用空格字元將彼此緊密相關的事物連線到一起,也用空格字元把相關性較弱的事物分隔開。 - 水平對齊(變數宣告和賦值不需要對齊)
- 縮排
5.3 遵循團隊規則
每個程式設計師都有自己喜歡的格式規則,但如果在一個團隊中工作,就是團隊說了算。
六、物件和資料結構
將變數設定為私有(private)有一個理由:我們不想其他人依賴這些變數。
-
資料、物件的反對稱性
過程式程式碼(使用資料結構的程式碼)便於在不改動既有資料結構的前提下新增新函式。
物件導向程式碼便於在不改動既有函式的前提下新增新類。
所以,對於物件導向較難的事,對於過程式程式碼卻較容易,反之亦然! -
得墨忒耳律認為,模組不應瞭解它所操作物件的內部情形。
-
資料傳送物件:
最為精練的資料結構,是一個只有公共變數、沒有函式的類。這種資料結構有時被稱為資料傳送物件,或DTO(Data Transfer Objects)。DTO是非常有用的結構,尤其是在與資料庫通訊、或解析套接字傳遞的訊息之類場景中。
物件曝露行為,隱藏資料。資料結構曝露資料,沒有明顯的行為。
七、錯誤處理
編寫既整潔又強固的程式碼——雅緻地處理錯誤程式碼的一些技巧和思路。
- 使用異常而非返回碼
- 先寫Try-Catch-Finally語句
- 使用不可控異常
- 給出異常發生的環境說明
- 依呼叫者需要定義異常類
- 定義常規流程
- 別返回null值
- 別傳遞null值
整潔程式碼是可讀的,但也要強固。可讀與強固並不衝突。如果將錯誤處理隔離看待,獨立於主要邏輯之外,就能寫出強固而整潔的程式碼。做到這一步,我們就能單獨處理它,也極大地提升了程式碼的可維護性。
八、邊界
如何將外來程式碼乾淨整合進自己的程式碼?這其實就是邊界的問題,邊界上的程式碼需要清晰的分割和測試。
九、單元測試
整潔的測試有什麼要素?有三個要素:可讀性,可讀性和可讀性。
每個測試函式只測試其中一個概念。每個測試一個斷言。
十、類
10.1 類的組織
遵循標準的Java約定,類應該從一組變數列表開始。如果有公共靜態常量,應該先出現。然後是私有靜態變數,以及私有實體變數。很少會有公共變數。
公共函式應跟在變數列表之後。我們喜歡把由某個公共函式呼叫的私有工具函式緊隨在該公共函式後面。這符合了自頂向下原則,讓程式讀起來就像一篇報紙文章。
10.2 類應該短小
關於類的第一條規則是類應該短小。第二條規則是還要更短小。
單一職責原則(SRP):類或模組應有且只有一條加以修改的理由。
系統應該由許多短小的類而不是少量巨大的類組成。每個小類封裝一個權責,只有一個修改的原因,並與少數其他類一起協同達成期望的系統行為。
十一、系統
系統也應該是整潔的。侵害性架構會湮滅領域邏輯,衝擊敏捷能力。當領域邏輯受到困擾,質量也就堪憂,因為缺陷更易隱藏,使用者故事更難實現。當敏捷能力受到損害時,生產力也會降低。
在所有的抽象層級上,意圖都應該清晰可辨。只有在編寫POJO並使用類方面的機制來無損地組合其他關注面時,這種事情才會發生。
無論是設計系統或單獨的模組,別忘了使用大概可工作的最簡單方案。
十二、逐步改進
鮑勃大叔認為:沒什麼能比糟糕的程式碼給開發專案帶來更深遠和長期的損害了。進度可以重訂,需求可以重新定義,團隊動態可以修正。但糟糕的程式碼只是一直腐敗發酵,無情地拖著團隊的後腿。我無數次看到開發團隊蹣跚前行,只因為他們匆匆搞出一片程式碼沼澤,從此之後命運再也不受自己控制。
注:但是,國內的開發狀況卻是不管程式碼質量,只追求快速上線,只追求短期利益,而不做有長期價值的事情。
所以,解決之道就是保持程式碼持續整潔和簡單。永不讓腐壞有機會開始。
十三、其他
最後,我認為第17章《味道與啟發》可以作為案例來自查和學習,對提高程式碼質量很有幫助。
一起學習
歡迎各位在評論區或者私信我一起交流討論,或者加我主頁weixin,備註技術渠道(如部落格園),進入技術交流群,我們一起討論和交流,共同進步!
也歡迎大家關注我的掘金、公眾號(碼上暴富),點贊、留言、轉發。你的支援,是我更文的最大動力!