《代碼簡潔之道–Clean Code》摘記

《代碼簡潔之道–Clean Code》摘記

第 2 章 有意義的命名

  • 名副其實: 變量、函數或類的名稱應該告訴你,它為什麼會存在,它做什麼事,應該怎麼用。如果名稱需要註釋來補充,那就不算名副其實。
  • 代碼的模糊度:即上下文在代碼中未被明確體現的程度。
  • 避免誤導: 提防使用不同之處較小的名稱。
  • 做有意義的區分: 要區分名稱,就要以讀者能鑑別不同之處的方式來區分。
  • 使用讀得出來的名字。
  • 使用可搜索的名稱 : 長名稱勝於短名稱,搜得到的名稱勝於自造編碼代寫就的名稱。單字母名稱僅用於端方法中的本地變量。名稱長短應與其作用域大小相對應。
  • 避免使用編碼 : 不要用類型前綴、特定前綴來標記成員。
  • 避免思維映射 : 聰明程序員和專業程序員之間的區別在於,專業程序員瞭解,明確是王道
  • 類名 : 類名和對象名應該是名詞或名詞短語。
  • 方法名 : 方法名應當是動詞或動詞短語。重載構造器時,使用描述了參數的靜態工廠方法名。
  • 每個概念對應一個詞 : 給每個抽象概念選一個詞,並且一以貫之。
  • 別使用雙關語;
  • 使用解決方案領域名稱 :
  • 使用源自所涉問題領域的名稱;
  • 添加有意義的語境
  • 不要添加沒用的語境 : 精確是命名的要點。

取好名字最難的地方在於需要良好的描述技巧和共有文化背景。

第 3 章 函數

  • 短小 : 函數的第一規則是要短小,第二條規則是還要更短小。每個函數都只做一件事,且每個函數都依序把讀者帶到下一個函數,這就是函數應該達到的短小程度。
  • if 語句、else 語句、 while 語句等,其中的代碼塊應該只有一行,該行大抵是一個函數調用語句。這樣不但能保持函數短小,而且,因為塊內調用的函數擁有較具說明性的名稱,從而增加了文檔上的價值。所以,函數的嵌套層級不該多於一層或兩層。
  • 只做一件事 : 函數應該只做一件事。編寫函數是為了把大一些的概念拆分為另一抽象層上的一序列步驟。只做一件事的函數無法被合理地切分為多個區段。
  • 每個函數一個抽象層級 : 要確保函數只做一件事,函數中的語句都要在同一抽象層級上。
  • switch 語句 : 利用抽象工廠和多態來化解。
  • 使用描述性名的稱 : 函數越短小、功能越集中,就越便於取個好名字。命名方式要保持一致,使用於模塊名一脈相承的短語、名詞和動詞給函數命名。
  • 函數參數 : 最理想的參數數量是零個,儘量避免三個刪除。參數與函數名處在不同的抽象層級,它要求你瞭解目前並不特別重要的細節。儘量不要有標識(比如boolean類型的)參數。
  • 無副作用 : 函數最好是無副作用的。輸出參數是會被修改的函數的參數;應避免使用輸出參數,如果函數必須要修改某種狀態,就修改所屬對象的狀態。
  • 分隔指令與詢問 : 函數應該修改某對象的狀態(指令),或是返回該對象的有關信息(詢問)。兩樣都做會導致混亂。
  • 使用異常代替返回錯誤碼 : 抽離 try/catch 語句到另外的函數;錯誤處理就是一件事;使用異常替代錯誤碼,新異常就可以從異常類派生出來,無須重新編譯或重新部署。
  • 別重複自己, DRY : 重複可能是軟件中一切邪惡的根源。
  • 結構化編程 : 每個函數、函數中的每個代碼塊都應該有一個入口、一個出口。這個規則對於大函數有明顯好處。

第 4 章 註釋

什麼也比不上放置良好的註釋來得有用,什麼也不會比亂七八糟的註釋更有本事搞亂一個模塊,什麼也不會比陳舊、提供錯誤信息的註釋更有破壞性。

註釋最多是一種必須的惡。

如果有足夠的表達力,根本就不需要註釋。

第 5 章 格式

代碼格式關乎溝通,而溝通是專業開發者的頭等大事。

每行展現一個表達式或一個語句,每組代碼行展示一條完整的思路。這些思路用空白行區隔開來。

概念相關:概念相關的代碼應該放在一起,相關性越強,彼此之間的距離就該越短。

自上向下展示函數的調用依賴順序。

第 6 章 對象和數據結構

對象把數據隱藏於抽象之後,曝露操作數據的函數。數據結果曝露其數據,沒有提供有意義的函數。

過程式代碼(使用數據結構的代碼)便於在不改動既有數據結構的前提下添加新函數。面向對象代碼便於在不改動既有函數的前提下添加新類。

得墨忒爾律(The Law of Demeter)認為,模塊不應瞭解它所操作對象的內部情形。

得墨忒爾律認為,類 C 的方法 f 只應該調用以下對象的方法:

  • C ;
  • 由 f 創建的對象;
  • 作為參數傳遞給 f 的對象;
  • 由 C 的實體變量持有的對象;
  • 方法不應調用由任何函數返回的對象的方法。

對象曝露行為,隱藏數據,便於添加新對象類型而無需修改既有行為,同時也難以在既有對象中添加新行為。

數據結構曝露數據,沒有明顯的行為,便於向既有數據結構添加新行為,同時也難以向既有函數添加新數據結構。

第 7 章 錯誤處理

  • 使用異常而非返回碼
  • 先寫 try-catch-finally 語句
  • 使用不可控異常 : 使用可控異常,就得在 catch 語句和拋出異常處之間的每個方法簽名中聲明該異常。這意味著對軟件中較低層級的修改,都將波及較高層次的簽名。
  • 給出異常發生的環境說明。
  • 依調用者需要定義異常類。
  • 定義常規流程 : 創建一個類或配置一個對象,用來處理特例。這樣客戶代碼就不用應付異常行為了,異常行為被封裝到特例對象中。
  • 別返回 null 值;
  • 別傳遞 null 值;

第 10 章 類

  • 類的組織 : 首先是公共靜態常量,私有靜態變量,私有實體變量,公共函數;公共行數調用的私有工具函數緊隨在該公共函數後面。
  • 類應該短小 : 類的大小以權責(responsibility)多少來衡量。 單一職責原則(SRP)認為類或模塊應有且只有一條加以修改的理由。 內聚:類應該只有少量實體變量,類中的每個方法都應該操作一個或多個實體變量;方法操作是實體變量越多,就越黏聚到類上,如果類中的每個實體變量都被每個方法所使用,則該類具有最大的內聚性。 保持內聚性就會得到許多短小的類。
  • 為了修改而組織 : 隔離修改。

依賴倒置原則: Dependency Inversion Principle, DIP 。

第 11 章 系統

11.2 將系統的構造與使用分開

軟件系統應將起始過程和起始過程之後的運行邏輯分離開,在起始過程中構建應用對象,也會存在互相纏結的依賴關係。

實現方法:

分解 main :將全部構造過程搬遷到 main 或稱之為 main 的模塊中,設計系統的其餘部分時,假設所有對象都已正確構造和設置。 工廠: 依賴注入:在依賴管理情景中,對象不應負責實體化對自身的依賴,反之,它應當將這份權責移交給其他“有權力”的機制,從而實現控制的反轉。因為初始設置是一種全局問題,這種授權機制通常要麼是 main 例程,要麼是有特定目的的容器

11.3 擴容

與物理系統相比軟件系統比較獨特,它們的架構都可以遞增式地增長,只要我們持續將關注面恰當地切分。軟件系統短生命週期的本質使這一切變得可行。

面向方面編程(aspect-oriented programming, AOP),是一種恢復橫貫式關注面模塊化的普適手段。

在 AOP 中,被稱為方面(aspect)的模塊構造指明瞭系統中哪些點的行為會以某種一直的方式被修改,從而支持某種特定的場景。這種聲明是用某種簡潔的聲明火編程機制來實現的。

AOP 有時會與其他技術混淆,例如方法攔截和通過代理做的“封包”。AOP 系統的真正價值在於用簡潔和模塊化的方式指定系統行為。

11.4 Java 代理

代碼量和複雜度是代理的兩大弱點,創建簡潔代碼變得很難。代理也沒有提供在系統範圍內指定執行點的機制,而那正是真正的 AOP 解決方案所必須的。

11.7 測試驅動系統架構

用 POJO 編寫應用程序的領域邏輯,在代碼層面與架構關注面分離開,就有困難真正地用測試來驅動架構。

最佳的系統架構由模塊化的關注面領域組成,每個關注面均用純 Java(或其他語言)對象實現。不同的領域之間用最不具有侵害性的方面或類方面工具整合起來。

在所有的抽象層級上,意圖都應該清晰可辨。只有在編寫 POJO 並使用類方面的機制來無損地組合其他關注面時,這種事情才會發生。

無論是設計系統或單獨的模塊,別忘了使用大概可工作的最簡單方案

第 12 章 迭進

Kent Beck 關於簡單設計的四條規則:

  • 運行所有測試;
  • 不可重複;
  • 表達了程序員的意圖;
  • 儘可能減少類和方法的數量;
  • 以上規則按其重要程度排列。

12.2 簡單設計規則1:運行所有測試

全面測試並持續通過所有測試的系統,就是可測試的系統。只要系統可測試,就會導向保持類短小且目的單一的設計方案。遵循 SRP 的類,測試起來較為簡單。測試編寫的越多,就越能持續走向編寫教易測試的代碼。確保系統完全可測試能幫助創建更好的設計。

測試消除了對清理代碼就會破壞代碼的恐懼。

12.4 不可重複

重複是擁有良好設計系統的大敵。它代表著額外的工作、額外的風險和額外且不必要的複雜度。

“小規模複用”可大量降低系統複雜性。要想實現大規模複用,必須理解如何實現小規模複用。

12.5 表達力

軟件項目的主要成本在於長期維護。

做到有表達力的最重要方式卻是嘗試


分享到:


相關文章: