由學(xué)習(xí)《軟件設(shè)計(jì)重構(gòu)》所想到的代碼review(一)

Paste_Image.png

前言

對(duì)于一個(gè)程序員來講如何來最直接的來衡量他的技術(shù)能力和產(chǎn)出呢?我想最直觀的作法是看他的代碼編寫能力评架,就拿我經(jīng)常接觸的一些程序員來看,他們買了很多技術(shù)重構(gòu)類書籍,但是看完后代碼編寫能力并沒有顯著提高夭坪。有人說可以用代碼review工具啊,但是像市面上的這些代碼review工具过椎,只能幫助我們解決表面的bug和規(guī)范點(diǎn)室梅,還無法幫助我們發(fā)現(xiàn)更深層次的設(shè)計(jì)問題。

下面我將結(jié)合《軟件設(shè)計(jì)重構(gòu)》這本書談?wù)勗谶M(jìn)行代碼review的時(shí)候,需要關(guān)注的哪些點(diǎn)亡鼠。

一赏殃、技術(shù)債務(wù)

何為技術(shù)債務(wù)?

技術(shù)債務(wù)是有意或無意的做出錯(cuò)誤的或非最優(yōu)的設(shè)計(jì)決策所引發(fā)的倆務(wù)

我們?cè)诖areview的時(shí)候,經(jīng)常碰到一些實(shí)現(xiàn)有瑕疵的方案间涵,然后對(duì)方說因?yàn)闀r(shí)間太緊急臨時(shí)采用的方案仁热,等第二期項(xiàng)目將其完善,于是往往第二期以后這個(gè)臨時(shí)方案就很難再去觸動(dòng)了勾哩,時(shí)間越長(zhǎng)代碼冗余越大抗蠢,越難去做修改,于是這就是典型的技術(shù)債務(wù)思劳,債務(wù)越積越多迅矛,最后只能重新徹底重構(gòu)項(xiàng)目才能解決問題,這也叫做技術(shù)破產(chǎn)潜叛。

于是我們的做法有一個(gè)債務(wù)管理系統(tǒng)诬乞,在代碼review的時(shí)候,會(huì)將這些債務(wù)或者臨時(shí)方案錄入到系統(tǒng)中并制訂償還日期钠导,那么后續(xù)債務(wù)順利償還后震嫉,更改系統(tǒng)狀態(tài),否遭遇一直沒有償還的牡属,系統(tǒng)將以郵件的方式提醒票堵,債務(wù)累積到一種數(shù)目后將與績(jī)效掛鉤考核。

二逮栅、設(shè)計(jì)的壞味道

前面只是從債務(wù)的角度說明了所帶來的危害悴势,其實(shí)引起技術(shù)債務(wù)的一個(gè)很重要的原因是對(duì)設(shè)計(jì)壞味和重構(gòu)認(rèn)識(shí)不足。

我們從設(shè)計(jì)的角度來看代碼時(shí)措伐,要遵循六要素:

  • 可理解性
    代碼理解起來的難易程度
  • 可修改性
    在修改既有功能時(shí)特纤,不會(huì)導(dǎo)致連鎖反應(yīng)。
  • 可擴(kuò)展性
    支持新功能侥加,不會(huì)導(dǎo)致連鎖反應(yīng)
  • 可重用性
    可以在代碼的其他地方引用其一塊代碼
  • 可測(cè)試性
    項(xiàng)目要能夠支持單元測(cè)試
  • 可靠性
    在正確的實(shí)現(xiàn)了功能的同時(shí)捧存,也能夠考慮各種異常情況如何容錯(cuò)

2.1、設(shè)計(jì)壞味的分類

Paste_Image.png

2.1.1 抽象型壞味道

Paste_Image.png

1担败、缺失抽象
舉例說明:

  • 問題點(diǎn):
    在JDK1.0中方法printStackTrace()以字符串的方式將棧跟蹤打印到標(biāo)準(zhǔn)錯(cuò)誤流:
public class Throwabe {
    public void printStackTrace();
}

在需要以編程方式訪問棧跟蹤元素的客戶程序中昔穴,必須要編程代碼來獲取數(shù)據(jù),如行號(hào)等提前,由于客戶程度依賴這種字符串格式吗货,JDK設(shè)計(jì)人員只能在后續(xù)版本中兼容這種格式了。

  • 解決方法
public class Throwabe {
    public void printStackTrace();
    public StackTraceElement[] getStackTrace();
}

從Jdk1.4起對(duì)JAVA的API進(jìn)行了改進(jìn)狈网,StackTraceElement類就是原來設(shè)計(jì)中缺失的對(duì)象宙搬,定義如下:

public final class StackTraceElement {
    public String getFilename();
    public int getLineNumber();
    public String getClassname();
    ......
}

2笨腥、命令式抽象
舉例如下:

  • 問題點(diǎn):


    Paste_Image.png

    注:其中每個(gè)類都只包括一個(gè)方法,這些方法分別是:create勇垛、display和copy等扇雕,因此存在命令式投象壞味,這種問題不僅會(huì)增加類的數(shù)量窥摄,還會(huì)增加開發(fā)和維護(hù)工作復(fù)雜性镶奉,而且將本應(yīng)內(nèi)聚的方法進(jìn)行了不必要的分享。

  • 解決方案


    Paste_Image.png

    注:根據(jù)高內(nèi)聚原則崭放,統(tǒng)一歸集到一個(gè)Report類中哨苛。

3、不完整的抽象
抽象未支持所有互補(bǔ)或相關(guān)的方法時(shí)币砂,將導(dǎo)致不完整的抽象建峭,比如一個(gè)抽象的公有接口提供了用于分配資源的initalize()方法,但是卻沒有提供刪除或者回收資源的方法dispose()决摧,這種情況下就屬于不完整的抽象亿蒸。

一些常見的互補(bǔ)方法對(duì)如下:

列一 列二 列三 列四
min/max open/close create/destroy get/set
start/stop print/scan first/last begin/end
source/target lock/unlock show/hide up/down
enable/disable acquire/release left/right on/off

4、多方面的抽象
對(duì)象被賦予不止一項(xiàng)職責(zé)時(shí)掌桩,將導(dǎo)致這種問題边锁。

舉例如下:

  • 問題點(diǎn)
    java.util.Calendar類承擔(dān)了多項(xiàng)職責(zé),不僅提供了日期相關(guān)的功能波岛,還提供了與時(shí)間有關(guān)的功能茅坛,存大多方面抽象。由于同時(shí)支持日期和時(shí)間的方法则拷,Calendar類接口很大且難為理解贡蓖,在JDK7中,java.util.Calendar類包括了2825行代碼煌茬,有67個(gè)方法和71個(gè)字段斥铺。

  • 解決方案
    對(duì)于Calendar類,一種可能的重構(gòu)是坛善,將Calendar類與時(shí)間相關(guān)的功能提取到新類Time中晾蜘,并將相關(guān)方法和字段移到新提取的類中,在Java8中引入了一些支持日期和時(shí)間的新類浑吟,這些類位于java.time中笙纤。

5、不必要的抽象
舉例如下:

  • 問題點(diǎn):
public interface WindowConstants {
    public static final int DO_NOTHING_ON_CLOSE=0;
    public static final int HIDE_ON_CLOSE=1;
}

注:這個(gè)接口是典型的常量接口javax.swing.WindowConstants组力,為啥用接口來存儲(chǔ)常量,因?yàn)槭紫让杜e是jdk1.5才引入的抖拴,其次通過接口中定義常量燎字,可方便類通過繼承而不是委托來使用它們腥椒,因?yàn)橥ㄟ^實(shí)現(xiàn)接口,類可方便的訪問接口中的常量候衍,為什么不使用類來存儲(chǔ)常量呢笼蛛,因?yàn)榻涌谥С侄嗬^承。
那么接口這樣定義常量有哪些問題呢蛉鹿?
A滨砍、派生類被無關(guān)的常量影響。
B妖异、這些常量屬于實(shí)現(xiàn)細(xì)節(jié)惋戏,通過接口暴露它們違反封裝原則。
C他膳、接口中存儲(chǔ)常量响逢,修改它們會(huì)影響其他使用者。

  • 解決方案
    將WindowsConstants定義為枚舉棕孙,直接使用舔亭。

6、重復(fù)的抽象
根據(jù)DRY原則規(guī)定:對(duì)于每個(gè)技術(shù)點(diǎn)蟀俊,系統(tǒng)中都只能有一個(gè)明確的表示钦铺。
導(dǎo)致重復(fù)抽象的原因有:
A、復(fù)制-粘貼編程手法
B肢预、即興維護(hù)
C职抡、交流不暢

舉例說明:

  • 問題點(diǎn):
    java.util.Date和其派生類java.sql.Date同名,這兩個(gè)類位于不同的包中误甚,編譯器不會(huì)因?yàn)樗鼈兺鴪?bào)錯(cuò)缚甩,但這讓使用者一頭霧水,這樣將導(dǎo)致二義性窑邦。

  • 解決方案
    將Date名稱前面加上用途限定語(yǔ)擅威,比如java.sql.SQLDate更合適。

三冈钦、小結(jié)

由于內(nèi)容太多郊丛,我們?cè)诘谝徊糠种唤榻B抽象型設(shè)計(jì)原則,接下來我將繼續(xù)寫那粕福化型設(shè)計(jì)原則厉熟,封裝型設(shè)計(jì)原則和層次化設(shè)計(jì)原則,與大家深入討論從設(shè)計(jì)角度來看较幌,什么樣的代碼才是真正的好代碼揍瑟。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市乍炉,隨后出現(xiàn)的幾起案子绢片,更是在濱河造成了極大的恐慌滤馍,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,207評(píng)論 6 521
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件底循,死亡現(xiàn)場(chǎng)離奇詭異巢株,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)熙涤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,455評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門阁苞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人祠挫,你說我怎么就攤上這事那槽。” “怎么了茸歧?”我有些...
    開封第一講書人閱讀 170,031評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵倦炒,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我软瞎,道長(zhǎng)逢唤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,334評(píng)論 1 300
  • 正文 為了忘掉前任涤浇,我火速辦了婚禮鳖藕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘只锭。我一直安慰自己著恩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,322評(píng)論 6 398
  • 文/花漫 我一把揭開白布蜻展。 她就那樣靜靜地躺著喉誊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纵顾。 梳的紋絲不亂的頭發(fā)上伍茄,一...
    開封第一講書人閱讀 52,895評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音施逾,去河邊找鬼敷矫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛汉额,可吹牛的內(nèi)容都是我干的曹仗。 我是一名探鬼主播,決...
    沈念sama閱讀 41,300評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼蠕搜,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼怎茫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起讥脐,我...
    開封第一講書人閱讀 40,264評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤遭居,失蹤者是張志新(化名)和其女友劉穎啼器,沒想到半個(gè)月后旬渠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俱萍,經(jīng)...
    沈念sama閱讀 46,784評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,870評(píng)論 3 343
  • 正文 我和宋清朗相戀三年告丢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了枪蘑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,989評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡岖免,死狀恐怖岳颇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颅湘,我是刑警寧澤话侧,帶...
    沈念sama閱讀 36,649評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站闯参,受9級(jí)特大地震影響瞻鹏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鹿寨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,331評(píng)論 3 336
  • 文/蒙蒙 一新博、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脚草,春花似錦赫悄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,814評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至写隶,卻和暖如春倔撞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背樟澜。 一陣腳步聲響...
    開封第一講書人閱讀 33,940評(píng)論 1 275
  • 我被黑心中介騙來泰國(guó)打工误窖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秩贰。 一個(gè)月前我還...
    沈念sama閱讀 49,452評(píng)論 3 379
  • 正文 我出身青樓霹俺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親毒费。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丙唧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,995評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,352評(píng)論 25 707
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法觅玻,內(nèi)部類的語(yǔ)法想际,繼承相關(guān)的語(yǔ)法培漏,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 31,669評(píng)論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理胡本,服務(wù)發(fā)現(xiàn)牌柄,斷路器,智...
    卡卡羅2017閱讀 134,722評(píng)論 18 139
  • 文/夏彼得 埃里克·里斯在其著作《精益創(chuàng)業(yè)》中提出了“最小可行產(chǎn)品”(Minimum Viable Product...
    夏彼得閱讀 2,244評(píng)論 0 3
  • 在今日頭條里面經(jīng)持涠停看到有許多小編在抱怨,自己的頭條號(hào)還在新手期守屉,每天堅(jiān)持原創(chuàng)惑艇,感覺靈感都要用光了。剛開始我也是深有...
    語(yǔ)見生活閱讀 160評(píng)論 1 0