代碼整潔之道 讀書筆記,之道讀書筆記
第1章 整潔代碼
1.1 要有代碼
1.2 糟糕的代碼
稍後等於永不
1.3 混亂的代價 如果前期不注意,後期的添加代碼、修改效率都非常低
1.3.1 華麗新設計
1.3.2 態度
1.3.3 迷題
1.3.4 整潔代碼的藝術
1.3.5 什麼是整潔代碼
1.4 思想流派1.5 我們是作者 讀和寫代碼的時間可能是10:1,可以用編輯器的回放功能查看自己的編寫記錄1.6 童子軍軍規
1.7 前傳與原則
第2章 有意義的命名
2.1 介紹
2.2 名副其實 變數名太隨意,haha、list1、ok 這些都沒啥意義2.3 避免誤導 包含List等關鍵字、字母o與數字0等
2.4 做有意義的區分 反面教材,變數名:a1、a2、a3 避免冗餘,不要出現Variable、表欄位中避免出現table、字串避免出現NameString - 直接Name就好2.5 使用讀得出來的名稱 不要使用自己拼湊出來的單詞,所謂的駝峰命名法,盡量使用完整的單詞
2.6 使用可搜尋的名稱 一些常量,最好不直接使用數字,而指定一個變數名,這個變數名可以便於搜尋到
2.7 避免使用編碼
2.7.1 匈牙利語標記法 避免像這樣使用縮寫
2.7.2 成員首碼 避免使用首碼,但是Android中一個比較好的喜歡用m表示私人等,個人感覺比較好
2.7.3 介面和實現 作者不喜歡把介面使用I來開頭,實現也希望只是在後面添加imp
2.8 避免思維映射 僅僅使用簡單的a、b、c等縮減一些單詞2.9 類名
類名與對象名應該是
名詞與
名詞短語,不能使動詞。2.10 方法名 方法名應當是動詞或者動詞短語 不使用構造器,而使用相應的public(構造器太常用了,為這些參數起名字也比較費腦筋,所以這個不太贊同)2.11 別扮可愛 有的變數名叫haha、banana
2.12 每個概念對應一個詞 項目中同時出現Control與Manager,為什麼不統一使用其中一種?
2.13 別用雙關語 有時可能使用add並不合適,比例insert、apped。add表示完整的新添加的含義。
2.14 使用解決方案領網域名稱稱 看代碼的都是程式員,所以起名字的時候可以多考慮專業詞彙。
2.15 使用源自所涉問題領域的名稱
2.16 添加有意義的語境 可以把相關的變數放到一個類中,使用這個類來表明語境。
2.17 不要添加沒用的語境 名字中帶有項目的縮寫,這樣完全沒有必要
2.18 最後的話
取好名字最難的地方在於需要良好的描述技巧和共有文化背景。
第3章 函數
3.1 短小 不要寫幾百行的函數
3.2 只做一件事 盡量保證每個函數僅做一件事情
3.3 每個函數一個抽象層級 自頂向下讀代碼:向下規則
3.4 switch語句 把switch放到工廠中,外面不需要考慮裡面如何具體實現。
3.5 使用描述性的名稱3.6 函數參數 參數的個數盡量小於3個,越少越好 3.6.1 一元函數的普遍形式
3.6.2 標識參數 - 如果需要向方法傳入true或者false說明方法肯定要做兩件事情
3.6.3 二元函數
3.6.4 三元函數
3.6.5 參數對象 - 如果參數過多,可以直接把這些參數封裝到一個對象中
3.6.6 參數列表 - 即使是可以傳入多個參數,但是超過3個還是要考慮下如何精簡
3.6.7 動詞與關鍵字3.7 無副作用 方法可能需要某種情境下調用才能有理想的結果。例如有些僅能在初始化的時候被調用,可以通過命名checkPassowrdAndInitializeSession 輸出參數,函數的內容是在輸入參數上改動,這種情況盡量避免或者使用appedFooter(StringBuffer report)這樣的命名
3.8 分隔指令與詢問 如果方法裡面設定一個變數的值,並且有返回值,可以命名為setAndCheckIfExists3.9 使用異常替代返回錯誤碼 3.9.1 抽離Try/Catch代碼塊 把try塊中的內容抽取到一個方法中
3.9.2 錯誤處理就是一件事
3.9.3 Error.java依賴磁鐵
3.10 別重複自己 避免項目中功能重複的代碼,更切記直接把一個函數copy到幾個地方使用
3.11 結構化編程 函數只要短小,偶爾出現return、break、continue語句沒有壞處
3.12 如何寫出這樣的函數
3.13 小結
3.14 SetupTeardownIncluder程式
3.15 文獻
第4章 注釋
4.1 注釋不能美化糟糕的代碼 注釋除去編寫的毫無疑義外,可能還會因為修改代碼而忘記修改相應的注釋,導致代碼上面的注釋其實不是不是下面代碼的意思。
4.2 用代碼來闡述
4.3 好注釋
4.3.1 法律資訊
4.3.2 提供資訊的注釋 - 在Regex上添加符合要求的例子。返回值的含義包含在函數名中。
4.3.3 對意圖的解釋 - 有些地方編寫的代碼可能跟常識不符合,但是是因為某種特定環境下必須這樣寫,可以用注釋解釋下。
4.3.4 闡釋
4.3.5 警示 - 對代碼修改的注意事項等。
4.3.6 TODO注釋
4.3.7 放大
4.3.8 公用API中的Javadoc - 可以學習下javadoc
4.4 壞注釋
4.4.1 喃喃自語 - 有些注釋沒解釋清楚事情,好像是作者寫給自己看的啞謎 4.4.2 多餘的注釋 - 函數的代碼很簡單,很容易理解。但是注釋卻寫的非常長
4.4.3 誤導性注釋 - 某種特別情況注釋中卻沒有描述,但是使用函數卻不是和注釋一樣的效果。
4.4.4 循規式注釋 - 每個變數名、每個函數都有注釋反倒成了愚蠢可笑。
4.4.5 日誌式注釋 - 添加誰修改了,但是現在SVN等代碼管理工具可以查看了
4.4.6 廢話注釋
4.4.7 可怕的廢話
4.4.8 能用函數或變數時就別用注釋
4.4.9 位置標記 - 使用//// 把一些功能分開,書中不建議使用,但是我個人感覺這樣能使代碼清晰些。
4.4.10 括弧後面的注釋 - 多層嵌套,在括弧的結尾添加上屬於哪個控制關鍵字的結尾括弧。這種情況可以抽取到多個方法中
4.4.11 歸屬與署名 - 不需要,因為有原始碼控制系統
4.4.12 注釋掉的代碼 - 暫時不需要的代碼可以直接刪除,沒必要注釋掉,可以使用原始碼控制系統找到之前版本
4.4.13 HTML注釋
4.4.14 非本地資訊
4.4.15 資訊過多 - 主需要最核心資訊,沒必要大段描述
4.4.16 不明顯的聯絡
4.4.17 函數頭
4.4.18 非公用代碼中的Javadoc - public需要添加javadoc告訴使用者一些資訊,但是private方法很多時候不需要
4.4.19 範例
第5章 格式
5.1 格式的目的
5.2 垂直格式
5.2.1 向報紙學習 可以自頂向下閱讀,最上面的是比較重要的。
5.2.2 概念間垂直方向上的區隔 代碼通常都是從上向下、從左向右讀。 函數間一定要留有空白,這樣可讀性會好些 5.2.3 垂直方向上的靠近 5.2.4 垂直距離 函數內變數聲明 - 在靠近使用的地方 全域變數 - 在類頂部 相關函數 - 當前函數調用的函數應該垂直放到一起 相關概念 - 例如函數名首碼都一樣的,或者重載的函數都放到一起
5.2.5 垂直順序
5.3 橫向格式 每一行代碼放置多少個字元,如果需要橫向滾動就讓人難以接受,所以建議每行容納120個字元左右,當然越短越好。
5.3.1 水平方向上的區隔與靠近 等號(=)兩側添加空格、計算符號(* / ) 左右添加空格
5.3.2 水平對齊 很多變數都變數名左側對齊,這樣很好看,但是處理成統一的格式需要時間,而且除了美觀也沒多大用途
5.3.3 縮排 5.3.4 空範圍 if函數的內容僅有一行就不添加括弧,這樣容易導致誤讀與修改上出現錯誤。5.4 團隊規則
5.5 鮑勃大叔的格式規則
第6章 對象和資料結構
6.1 資料抽象 setter/getter添加這些方法的思考
6.2 資料、對象的反對稱性
6.3 得墨忒耳律
6.3.1 火車失事
6.3.2 混雜
6.3.3 隱藏結構
6.4 資料傳送對象
6.5 小結
對象暴露行為,隱藏資料。
第7章 錯誤處理
7.1 使用異常而非返回碼 不在方法中使用返回的方式,而是使用程式設計語言提供的異常機制來攔截
7.2 先寫Try-Catch-Finally語句7.3 使用不可控異常7.4 給出異常發生的環境說明
7.5 依調用者需要定義異常類
7.6 定義常規流程7.7 別返回null值 返回空的字串或者空的列表(Collections.emptyList())
7.8 別傳遞null值 避免傳入null值而不是在函數內進行判斷(還是在函數內做null判斷吧,畢竟一起編寫代碼,難免別人會傳入)
7.9 小結
7.10 文獻
第8章 邊界
8.1 使用第三方代碼
8.2 瀏覽和學習邊界8.3 學習log4j
8.4 學習性測試的好處不只是免費 在某個API的功能不完全瞭解的情況下,單獨寫一個demo測試下是否是自己理解的那樣,非常省成本而且準確。
8.5 使用尚不存在的代碼 已經定義好介面,類似與寫測試資料一樣。
8.6 整潔的邊界
8.7 文獻
第9章 單元測試
9.1 TDD三定律 1. 在編寫不能通過的單元測試前,不可以編寫生產代碼;
2. 只有編寫剛好無法通過的單元測試,不能編譯也算不通過;
3. 只可編寫剛好足以通過當前失敗測試的生產代碼。
9.2 保持測試整潔 測試代碼和生產代碼一樣重要。它需要被思考、被設計和被照料。
9.3 整潔的測試 每個測試都呈現構造-操作-校正(BUILD-OPERATE-CHECK)模式。
9.3.1 面向特定領域的測試語言
9.3.2 雙重標準
9.4 每個測試一個斷言
9.5 F.I.R.S.T. 快速(Fast):測試回合應該夠快。
獨立(Independent):測試應相互獨立。
可重複(Repeatable):測試應當可在任何環境中重複通過。
自足驗證(Self-Validating):測試應該有布爾值輸出。
及時(Timely)測試應及時編寫。
9.6 小結
第10章 類
10.1 類的組織
10.2 類應該短小
10.2.1 單一權責原則 書中建議:系統應該由很多短小的類而不是少量巨大的類組成。每個小類封裝一個權責,只有一個修改的原因,比與少數其他一起協同達成期望的系統行為。 10.2.2 內聚
10.2.3 保持內聚性就會得到許多短小的類
10.3 為了修改而組織
第11章 系統
11.1 如何建造一個城市 討論如何在較高的抽象層級 - 系統層級上保持整潔。
11.2 將系統的構造與使用分開
11.2.1 分解main 建構函式都放到入口的main中?
11.2.2 工廠 應用程式需要確定何時建立對象時可以使用工廠。
11.2.3 依賴注入 可以分析構造與使用。
11.3 擴容11.4 Java代理
11.5 純Java AOP架構
11.6 AspectJ的方面
11.7 測試驅動系統架構
11.8 最佳化決策
11.9 明智使用添加了可論證價值的標準
11.10 系統需要領特定領域語言
11.11 小結
第12章 迭進
12.1 通過迭進設計達到整潔目的 Kent Beck關於“簡單設計”的四條規則: 1. 運行所有測試 2. 不可重複 3. 表達了程式員的額意圖 4. 儘可能減少類和方法的數量12.2 簡單設計規則1:運行所有測試
12.3 簡單設計規則2~4:重構
12.4 不可重複
12.5 表達力
12.6 儘可能少的類和方法
12.7 小結
第13章 並發編程
13.1 為什麼要並發
13.2 挑戰 並發的執行是無序的,需要確保安全執行緒。
13.3 並發防禦原則 13.3.1 單一權責原則 方法/類/組件應當只有一個修改的理由。建議:把並發與非並發的代碼分離開。 13.3.2 推論:限制資料範圍 synchronized,謹記資料封裝;嚴格限制對可能被共用的資料的訪問。
13.3.3 推論:使用資料複本 避免資料的共用,多線程返回的資料是單獨的,執行完成後在合并到主線程。
13.3.4 推論:線程應儘可能地獨立
13.4 瞭解Java庫 限定資源 - 並發環境中有著固定尺寸或數量的資源。例如資料庫連接盒固定尺寸讀/寫緩衝等。 互斥 - 每一時刻僅有一個線程能訪問共用資料或共用資源 線程饑餓 - 一個或一組線程在很長時間內或永久被禁止。例如:總是讓執行的快的線程先運行,例如執行得快的線程沒完沒了,則執行時間長的線程就會“挨餓” 死結 - 兩個或者多個線程互相等待執行結束。每一個線程都擁有其他線程需要的資源,得不到其他線程擁有的資源,就無法終止。 活鎖 - 執行次序一致的線程,每個都想要起步,但發現其他線程已經“在路上”。由於競爭的原因,線程會持續嘗試起步,但在很長的時間內都無法如願,甚至永遠無法啟動。
13.5 瞭解執行模型
*** 13.5.1 生產者-消費者模型 一個或多個生產則會線程建立某些工作,共置於緩衝或隊列中。一個或多個消費者線程從隊列中擷取並完成這些工作。生產者消費者之間的隊列是一種限定資源。
*** 13.5.2 讀者-作者模型
*** 13.5.3 宴席哲學家
13.6 警惕同步方法之間的依賴 避免使用一個共用對象的多個方法。
13.7 保持同步地區微小
13.8 很難編寫正確的關閉代碼
13.9 測試線程代碼
13.9.1 將偽失敗看作可能的線程問題
13.9.2 先使非線程代碼可工作
13.9.3 編寫可插拔的線程代碼
13.9.4 編寫可調整的線程代碼
13.9.5 運行多於處理器數量的線程
13.9.6 在不同平台上運行
13.9.7 裝置試錯代碼
13.9.8 寫入程式碼
13.9.9 自動化
13.10 小結
13.11 文獻
第14章 逐步改進
14.1 Args的實現 我怎麼做的? 要編寫整潔代碼,必須先寫骯髒代碼,然後再整理它。例如寫作文,先寫草稿,再寫作文等。
14.2 Args:草稿
14.2.1 所以我暫停了 再新增列需求需要修改代碼的之後,才能發現有哪些代碼需要改動,改進的方法就是找出這些改動的地方: 1. 每個參數類型都要有解析器範式元素、從而為該種類型選擇HashMap的方法。 2. 每種類型都需要再命令列字串中解析,然後再轉換為真是類型。 3. 每種參數類型都需要一個getXXX方法,按照其真實類型向調用者返回參數值。
14.2.2 漸進
14.3 字串參數
14.4 小結 修改前已經編寫好Junit測試,這樣能保證每次修改的時候都不會對系統功能造成影響。 找出之後會爆炸式增長的地方。 先添加一個變數等一步步的小範圍修改,每次修改都需要通過Junit測試。
第15章 JUnit內幕
15.1 JUnit架構
15.2 小結
第16章 重構SerialDate
16.1 首先,讓它能工作
16.2 讓它做對
16.3 小結
16.4 文獻
第17章 味道與啟發注釋
C1.不恰當的注釋
讓不恰當的注釋儲存到原始碼控制系統。
C2.廢棄的注釋
過時、無關或不正確的注釋就是廢棄的注釋不應該保留必須馬上刪除。
C3.冗餘的注釋
注釋應該談及代碼自身沒提到的東西,否則就是冗餘的。
C4.糟糕的注釋
值得編寫的注釋必須正確寫出最好的注釋,如果不是就不要寫。
C5.注釋掉的代碼
注釋掉的代碼必須刪除。
環境
E1.需要多步才能實現的構建
構建系統應該是單步的小操作。
E2.需要多步才能實現的測試
只需要單個指令就可以運行所有單元測試。
函數
F1.過多的參數
函數參數應該越少越好,堅決避免有3個參數 的函數。
F2.輸出參數
輸出參數違反直接,抵制輸出參數。
F3.標識參數
布爾值參數令人迷惑,應該消滅掉。
F4.死函數
永不被調用函數應該刪除掉。
一般性問題
G1.一個源檔案存在多個語言
盡量減少源檔案語言的數量和範圍。
G2.明顯的行為未被實現
遵循“最少驚異原則”,函數或者類應該實現其他程式員有理由期待的行為,不要讓其他程式員看代碼才清楚函數的作用。
G3.不正確的邊界行為
代碼應該有正確的行為,追索每種邊界條件並進行全面測試。
G4.忽視安全
關注可能引起問題的代碼,注重安全與穩定。
G5.重複
消除重複代碼,使用設計模式。
G6.在錯誤的抽象層級上的代碼
抽象類別和衍生類別概念性模型必須完整分離,例如:與實現細節有關的代碼不應該在基類中出現。
G7.基類依賴於衍生類別
基類應該對衍生類別一無所知。
G8.資訊過多
類中的方法,變數越少越好,隱藏所有實現,公開介面越少越好。
G9.無作用程式碼
找到並刪除所有不被調用的代碼。
G10.垂直分隔
變數和函數的定義應該靠近被調用代碼。
G11.前後不一致
函數參數變數應該從一而終,保持一致,讓代碼便於閱讀和修改。
G12.混淆視聽
沒用的變數,不被調用的函數,沒有資訊量的注釋應該清理掉。
G13.人為耦合
不互相依賴的東西不該耦合。
G14.特性依戀
類的方法應該只對自身的方法和變數感興趣,不應該垂青其他類的方法和變數。
G15.選擇運算元參數
避免布爾型別參數,使用多態代替。
G16.晦澀的意圖
代碼要儘可能具有表達力,明白的意圖比高效和效能重要。
G17.位置錯誤的權責
“最少驚異原則”,把代碼放在讀者想到的地方,而不是對自己方便的地方。
G18.不恰當的靜態方法
如果要使用靜態方法,必須確保沒機會打算讓它有多態行為。
G19.使用解釋性變數
把計算過程打散成一系列命名良好的中間值使程式更加可讀性。
G20.函數名稱應該表達其行為 G21.理解演算法
G22.把邏輯依賴改為物理依賴
依賴應該是明顯而不應該是假設的依賴。
G23.用多態替代If/Else或Switch/Case G24.遵循標準約定 G25.用命名常量替代魔術數 G26.準確
代碼中的含糊和不準確要麼是意見不同的結果,要麼源於懶散,都必須消除。
G27.結構甚於約定 G28.封裝條件
把條件封裝成方法。
G29.避免否定性條件
使用肯定性條件。
G30.函數只該做一件事 G31.掩蔽時序耦合
建立順序隊列暴露時序耦合,每個函數都產生一下函數所需參數,就可保障正確的時序。
G32.別隨意
代碼不能隨意,需要謹慎考慮。
G33.封裝邊界條件
例如:+1或-1操作必須封裝起來。
G34.函數應該只在一個抽象層級上
封裝不在一個抽象層級上的代碼,保持每個函數只在一個抽象層級上。
G35.在較高層級放置可配置資料
把配置資料和常量放到基類裡。
G36.避免傳遞瀏覽
“得墨忒耳律”,編寫害羞代碼,讓直接共同作業者提供所需的服務,而不要逛遍整個系統。
JAVA
J1.通過使用萬用字元避免過長的匯入清單 J2.不要繼承常量 J3.常量VS.枚舉
使用枚舉enum代替常量。
名稱
N1.採用描述性名稱
名稱對應可讀性有90%的作用,必須認真命名。
N2.名稱應與抽象層級相符
不要取溝通實現的名稱:取反映類或函數抽象層級的名稱。
N3.儘可能使用標準命名法 N4.無歧義的名稱
N5.為較大作用範圍選用較長名稱 N6.避免編碼
不應該在名稱中包含類型或範圍的資訊,例如:m_,f等首碼。
N7.名稱應該說明副作用
名稱應該說明類、變數或函數的所有資訊,不應該隱藏副作用。
測試 T1.測試不足
保證足夠的測試。
T2.使用覆蓋率工具
覆蓋率工具可以更好地找到測試不足的模組、類、函數。
T3.別略過小測試
T4.被忽略的測試就是對不確定事物的疑問
用@Ignore表達我們對需求的疑問。
T5.測試邊界條件
邊界判讀錯誤很常見,必須測試邊界條件。
T6.全面測試相近的缺陷
缺陷趨向於紮堆,如果在函數中發現一個缺陷,那麼就全面測試這個函數。
T7.測試失敗的模式有啟發性
你可以通過測試失敗找到問題所在。
T8.測試覆蓋率的模式有啟發性
通過測試覆蓋率檢查,往往可以找到測試失敗的線索。
T9.測試應該快速
慢測試會導致時間緊時會跳過,導致可能出現問題。
代碼整潔之道怎
寫代碼有時候就像整理畫建築圖紙,沒有一個清晰得思路和架構,必然搗鼓出一個髒亂差的社區,更談不上一棟一棟蓋高樓了。 整潔的代碼這本書讀罷,覺得需要好好審視自己以往的代碼和思考方式。 敲代碼,說實話是個技術活也是個流水線活兒。關鍵在於花多大心思去整它。 讀一讀,應該會讓你有所悟。
錯誤提示