《程式碼整潔之道》學習總結
1. 整潔程式碼
1.1 整潔的程式碼力求集中,每個函式,每個類和每個模組都全神貫注於一事,完全不受四周細節的干擾和汙染。
1.2 減少重複程式碼,提高表達力,提早構建簡單物件(即不要重複程式碼,只做一件事,表達力,小規模抽象)。
1.3 設計原則的引用,包括單一職責原則(Single Responsibility Principle,SRP),開放閉合原則(Open Closed Principle,OCP)和依賴倒置原則(Dependency Inversion Principle,DIP)
2. 有意義的命名
2.1 如果名稱需要註釋來補充,那就不算是名副其實。
2.2 在命名時可以選擇指明瞭計量物件和計量單位的名稱。
2.3 別用accountList來指明一組賬號,除非它真的是List型別,List一詞對程式設計師有特殊意義,容易引起錯誤的判斷,用accountGroup或bunchOfAccount,甚至用accounts都會好一些。
2.4 長名稱勝於短名稱,搜得到的名稱勝於用自造編碼代寫就的名稱,當然短名稱若能表達出明顯的意圖則更好。
2.5 如果介面和實現必須選一個來編碼的話,選擇實現。ShapeFactoryImpl,甚至是醜陋的CShapeFactory,都比對介面名稱編碼來的好。
2.6 類名和物件名應該是名詞或名詞短語,不應當是動詞。
2.7 方法名應當是動詞或動詞短語。
2.8 過載構造器時,使用描述了引數的靜態工廠方法名,可以考慮將相應的構造器設定為private,強制使用這種命名手段。(即通過構造器私有化,通過靜態方法提供例項物件。)
2.9 當涉及多個概念(類似一系列controller,manager,driver等)時,可以通過公共類特徵+s進行統一。
2.10 避免將同一單詞用於不同目的,同一術語用於不同概念,即雙關語。比如多個類中均有add方法,則按不同的語義情景進行命名,也可以通過給名稱加前後綴,以此新增語境加以區分。
3. 函式
3.1 函式應該做一件事。做好這件事,只做這一件事。函式的語句都要在同一抽象層級上。
3.2 別害怕長名稱,長而具有描述性的名稱,要比短而令人費解的名稱好。長而具有描述性的名稱,要比描述性的長註釋好。
3.3 使用與模組名一脈相承的短語,名詞和動詞給函式命名。
3.4 如果函式要對輸入引數進行轉換操作,轉換結果就該體現為返回值。
3.5 如果函式需要兩個,三個或三個以上引數,就說明其中一些引數應該封裝為類了。
3.6 普遍而言,應避免使用輸出引數(需求減少)。
3.7 在進行boolean值判斷時,應當把指令與詢問分隔開來,相當於可以把判斷邏輯封裝在函式裡,用類似xxxIsTrue/Existed代替。
3.8 最好把try和catch程式碼塊的主體部分抽離出來,另外形成函式。
3.9 使用異常代替錯誤碼,新異常就可以從異常類派生出來,無需重新編譯或重新部署。
3.10 在不斷嘗試中消滅重複。打磨程式碼,分解函式,修改名稱,消除重複,甚至縮短和重新安置方法,拆散類,保持測試通過。
4. 註釋
4.1 註釋總是一種失敗,我們總無法找到不用註釋就能表達自我的方法,所以總要有註釋。儘管有時也需要註釋,我們也該多花心思儘量減少註釋量。
4.2 用程式碼去解釋你大部分的意圖,唯一真正好的註釋是你想辦法不去寫的註釋。
4.3 註釋的作用是解釋未能自行解釋的程式碼,如果註釋本身還需要解釋,那就太遺憾了。
4.4 雖然Javadoc對於公共API非常有用,但對於不打算作公共用途的程式碼就令人厭惡了。
5. 格式
5.1 幾乎所有的程式碼都是從上往下讀,從左往右讀。每行展現一個表示式或一個子句,每組程式碼行展示一條完整的思路,這些思路用空白行區分開來。(比如不同方法間,展現垂直方向上區隔的作用)。
5.2 被呼叫的函式應該放在執行呼叫函式的下面,這樣就建立了一種自頂向下貫穿原始碼模組的良好資訊流。
5.3 水平分割中,強聯絡的程式碼單詞之間不用空格分開,弱聯絡的用空格字元加強分隔效果。(類似乘法因子之間沒加空格,因為它們具有較高優先順序。加減法運算項之間用空格隔開,因為加法和減法優先順序較低)。
6. 物件和資料結構
6.1 物件把資料隱藏於抽象之後,曝露操作資料的函式。資料結構曝露其資料,沒有提供有意義的函式。(兩種定義本質上是對立的)。
6.2 過程式程式碼難以新增新資料結構,因為必須修改所有函式。面向物件程式碼難以新增新函式,因為必須修改所有類。
6.3 得墨忒耳律認為:模組不應瞭解它所操作物件的內部情形,方法不應呼叫由任何函式返回的物件的方法(類似於呼叫了返回值結果的方法,效果呈現連續呼叫,也稱“火車失事”)。
6.4 最為精煉的資料結構,是一個只有公共變數,沒有函式的類。這種資料結構有時被稱為資料傳送物件,或DTO(Data Transfer Objects)。DTO是非常有用的結構,尤其是在於資料庫通訊,或解析套接字傳遞的訊息之類場景中。
6.5 物件曝露行為,隱藏資料,便於新增新物件型別而無需修改既有行為,同時也難以在既有物件中新增新行為;資料結構曝露資料,沒有明顯的行為,便於向既有資料結構新增新行為,同時也難以向既有函式新增新資料結構。
7. 錯誤處理
7.1 錯誤處理很重要,但如果它搞亂了程式碼邏輯,就是錯誤的做法。
7.2 使用異常而非返回碼,往往使用定義異常+錯誤碼+Msg。
7.3 用特定物件返回代替業務邏輯與錯誤處理結合,將異常行為封裝到指定物件中。
7.4 如果你打算在方法中返回null值,不如丟擲異常,或是返回特例物件。如果你在呼叫某個第三方API中可能返回null值的方法,可以考慮用新方法打包這個方法,在新方法中丟擲異常或返回特例物件。(類似於一箇中間轉換)。
7.5 如果將錯誤處理隔離看待,獨立於主要邏輯之外,就能寫出強固而整潔的程式碼。
8. 邊界
8.1 邊界上的介面(Map)是隱藏的,它能隨來自應用程式其他部分的極小的影響而變動。
9. 單元測試
9.1 TDD三定律:
定律一 在編寫不能通過的單元測試前,不可編寫生產程式碼 。
定律二 只可編寫剛好無法通過的單元測試,不能編譯也算不通過。
定律三 只可編寫剛好足以通過當前失敗測試的生產程式碼。
9.2 測試程式碼和生產程式碼一樣重要,需要保證可讀性。
9.3 雙重標準,有些事你大概永遠不會在生產環境中做,而在測試環境中做卻完全沒有問題。
9.4 單個測試中的斷言數量應該最小化。
9.5 最佳規則也許是應該儘可能減少每個概念的斷言數量,每個測試函式只測試一個概念。
10. 類
10.1 系統應該由許多短小的類而不是少量巨大的類組成。每個小類封裝一個權責,只有一個修改的原因,並與少數其他類一起協同達成期望的系統行為。
10.2 開放-閉合原則(Open Closed Principle,OCP):類應當對擴充套件開放,對修改封閉。在理想系統中,我們通過擴充套件系統而非修改現有程式碼來新增新特性。
10.3 依賴倒置原則(Dependency Inversion Principle,DIP),本質而言,DIP認為類應當依賴於抽象而不是具體細節。
(未完待續~)