代碼質量和產出是衡量一個程序員是否優秀最直接的標準。如何提升代碼質量和產出?這就要從軟件重構和review入手。市面上有不少關於重構和review的書籍,可是看完以後,代碼能力並不能立竿見影顯著提高,只能幫助咱們解決表面的bug和規範點,沒法幫助咱們發現更深層次的設計問題。java
從設計角度來考慮review,識別代碼壞味道能夠能夠有效減小技術債務。技術債務是指有意或無心的作出錯誤的或非最優的設計決策所引起的債務。債務越積越多,最後只能從新完全重構項目才能解決問題,這也叫作技術破產。如何解決技術債務問題,就要從根源上明確引發技術債務的重要的緣由——設計壞味和重構認識不足。程序員
首先要明確軟件設計原則編程
抽象原則:經過精簡和歸納來簡化實體:精簡指的是刪除沒必要要的細節,歸納是找出並定義重要的通用特徵。設計模式
非循環依賴原則:包之間的關係不可造成循環。微信
不自我重複原則:在詳細設計中,設計實體和代碼和重複可能表現爲類型名重複和實現重複。編程語言
封裝原則:經過隱藏抽象的實現細節和隱藏變化等方法實現關注點分離和信息隱藏。模塊化
信息隱藏原則:找出棘手或可能變化的設計決策,並建立合適的模塊或類型來對其餘模塊或類型隱藏這些決策。微服務
保持簡單原則:簡潔是軟件系統設計的重要目標,應避免引入沒必要要的複雜性。性能
里氏替換原則:全部的子類型都必須至少提供超類型承諾的行爲且對每一個超類型的引用均可替換成子類型實例。測試
層次接口原則:使用分類、歸納、替換、排序等方法以層次方式組織對抽象。
模塊化原則:經過集中和分解等手法建立高內聚、低耦合的抽象。
開閉原則:類型應對擴展開放,對修改關閉。具體是模塊應該可以在不修改代碼狀況下支持新需求。
單一職責原則:毫不應有多個致使類須要修改的緣由,如修改一個成員可能影響類的其餘不相關職責,致使類難以維護。
變化封裝原則:倡導一種信息隱藏方式,建議將可能發生變化的概念封裝起來。不少設計模式都體現了這種設計原則,如策略模式、橋樑模式、觀察者模式。
咱們從設計的角度來看代碼時,要遵循六要素:
瞭解完設計原則和六要素後,咱們再來看設計壞味。
本文中每種壞味咱們只選其中一例作具體說明。
抽象型壞味
抽象原則倡導經過精簡和歸納來簡化實體:精簡指的是刪除沒必要要的細節,而歸納指的是找出並定義經過的重要特徵。交通標誌是用於交流的抽象示例,而數字符號和編程語言是用於解決問題的抽象示例。
缺失抽象
使用一系列數據或者編碼字符串,而不建立類或者接口時會產生這種壞味
1. 概念
應用抽象原則的一種實現手法是建立概念邊界清晰,身份惟一的實體。因爲沒有建立抽象來表示實體,而是使用基本數據類型或編碼字符串等原始數據來表示它,這違反了抽象原則,將這種壞味稱爲缺失抽象(Missing Abstraction)。沒必要要的抽象也違反了模塊化原則。
2. 潛在緣由
未作重複的設計分析 未重構 錯誤的將重點放在細微的性能改善上
3. 示例
在JDK1.0中方法printStackTrace()以字符串的方式將棧跟蹤打印到標準錯誤流。 在須要以編程方式訪問棧跟蹤元素的客戶程序中,必需要編程代碼來獲取數據,如行號等,因爲客戶程度依賴這種字符串格式,JDK設計人員只能在後續版本中兼容這種格式了。
重構建議:從Jdk1.4起對JAVA的API進行了改進,StackTraceElement類就是原來設計中缺失的對象。
4. 別名 基本類型偏執:使用基本類型對日期、金額進行編碼,而不建立類時,將引起這種壞味。 數據泥團:在不少地方同事使用一系列數據項,而不建立類時,將引起這種壞味。
5. 現實考慮 避免過分設計:有時候,實體只是數據元素,沒有任何相關聯的行爲。這種狀況下使用類或者接口來表示它們可能致使過分設計。
封裝型壞味
封裝原則倡導經過隱藏抽象的實現細節和隱藏變化等手法實現關注的分離和信息隱藏。好比開車必須知道發動機原理嗎?
不充分的封裝
對於抽象的一個或多個成員,聲明的訪問權限超過了實際需求時,將致使這種壞味。例如,將字段聲明爲公有的類就存在「不充分封裝」壞味。
1. 概念
封裝的原則是將接口和實現分離,以便能獨立修改。這種關注點分離,讓客戶程序只依賴抽象的接口,而對它們隱藏具體實現。修改實現不影響客戶程序。對抽象的內部隱藏的不充分稱爲不充分的封裝(Deficient Encapsulation)。
2. 潛在緣由 爲方便測試 在面向對象中採用過程思惟 快速交付
3. 示例 來看看java.lang.System,in、out、err都被聲明成final,但能夠經過java.lang.System的setIn、setOut、setErr分別賦值。任何代碼都能很方便的使用它們,好比System.out.println(); PrintStream是java 1.0就有的,只支持8位的ASCII值,Java1.1出的PrintWriter支持Unicode,然而就是由於應用程序都能直接使用PrintStream來訪問PrintStream的方法,根本不能摒棄PrintStream類。
4. 重構建議:Java 1.6引入了java.io.Console類,他提供了用於訪問基於字符的控制檯的方法。reader()、writer()來獲取Console相關的Writer和Reader對象。
5. 別名
可隱藏的公有屬性、方法 未封裝的類 包含未參數化方法的類
6. 現實考慮 嵌套或匿名類中過於寬鬆的訪問性 性能考慮:好比前面說的java.lang.System
模塊化壞味
模塊化原則倡導利用集中和分解等手法建立高內聚、低耦合的抽象。
拆散的模塊化
應集中放在一個抽象中的數據和方法分散在多個抽象中時,將致使這種壞味。表現爲類被用做數據容器沒有任何方法、類的方法更多的被其餘類的成員調用。
1. 概念
一種重要的模塊化實現手法是「將相關的數據和方法集中在一塊兒」。若是抽象中只包含數據成員,而操做這些數據成員的方法位於其餘抽象中,它就違反了這種實現手法,存在「拆散的模塊化」壞味。稱爲拆散的模塊化(Broken Modularization)。
2. 潛在緣由
以過程思惟使用面嚮對象語言 不熟悉既有設計
3. 重構建議 對於包含大量數據類的過程型設計,可採用重構手法「將過程型設計轉換爲對象」。
4. 別名
被動地存儲數據的類 數據類 數據記錄 記錄類 數據容器 錯位的操做 依戀情結 錯位的控制
5. 現實考慮 自動生成的代碼 數據傳輸對象 層次型壞味 層次結構原則倡導採用分類、歸併、替換和排序等手法以層次方式組織抽象。好比地球上的870萬種生物。
缺失的層次結構
代碼片斷使用條件邏輯來顯式管理行爲變化,而本來能夠建立一個層次目錄,並使用它來封裝這些變化,會產生這種壞味
1. 概念
基於類型碼的switch語句(或串接的if-else語句)是最著名的設計壞味之一。 使用類型碼來處理行爲變化代表沒有進行有意義的分類,致使設計中缺乏相應的層次結構。稱爲缺失層次結構(Missing Hierarchy)。
2. 潛在緣由 錯誤的採用過於簡單的設計 過程型設計思惟 忽視了繼承也是一種設計手法
3. 示例 串接的if else語句顯示的檢查類型AbstractButton,JToolBar和JTextCompont並在各類條件下調用方法getMargin(),這種形成的狀況是未來可能在代碼中的其餘地方也會出現。
4. 重構建議 若是條件檢查中的多個實現調用方法相同,可引入相關的接口來抽象共同的協議。 若是代碼中包含可轉換爲類的條件語句,可採用重構手法「提取層次結構」來建立一個類層次結構,其中每一個類都表示條件檢查中的一種情形。
5. 別名 標記類 繼承缺位 緊縮的類型層次結構 內嵌功能
6. 現實考慮 與外部交互
——————————————————分割線——————————————————
我是黑少,直男一枚,微服務硬核玩家,喜歡分享、愛交友人、崇尚「實踐出真知」的理念,以折騰鼓搗代碼爲樂
個人微信:weiweiweiblack (備註:開源中國 )
微信公號:黑少微服務,專一微服務技術分享,非技術不八卦!