重 構 改善 既 有 程式 的 設計

內容簡介

“任何一個傻瓜都能寫出電腦可以理解的程式,唯有優秀的程式設計師能寫出讓人讀懂的程式。”
—M. Fowler (1999)

完全修訂及更新:包含新的重構方法和範例程式

二十多年來,世界各地經驗豐富的程式員都使用Martin Fowler的《重構》來改善既有程式的設計、提升軟體的易維護性,以及讓既有的程式更容易被人瞭解。

為了反映程式設計領域的重大變化,作者全面翻新書籍內容,推出這本備受期待的新版本。《重構 第二版》提供了新的重構名錄,加入JavaScript範例程式以及新的實用範例來展示各種重構。

這個版本與第一版一樣,將解釋什麼是重構、為何重構、如何認出需要重構的程式,以及如何成功地重構,無論你是使用哪一種語言。

‧瞭解重構的程序與一般原則
‧快速運用實用的重構技術,讓程式更容易理解與修改
‧辨認暗示有待重構的程式碼“異味”
‧探討重構,每一個案例都包括說明、動機、作法與簡單的範例
‧為重構建立可靠的測試程式
‧認識重構的取捨與障礙

本書原文網站提供免費的web標準版本,包含更多重構資源,書中內容將說明如何取得。

作者介紹

作者簡介

Martin Fowler

MARTIN FOWLER 是ThoughtWorks首席科學家。自稱是“軟體開發界的作者、演說者、顧問與大嘴巴。”Fowler擅長設計企業軟體,研究什麼是好的設計,以及其建立的方法。

目錄

Chapter 1 重構:第一個範例
Chapter 2 重構的原理
Chapter 3 程式碼異味
Chapter 4 建構測試程式
Chapter 5 名錄簡介
Chapter 6 第一組重構
Chapter 7 封裝
Chapter 8 移動功能
Chapter 9 移動功能
Chapter 10 簡化條件邏輯
Chapter 11 重構 API
Chapter 12 處理繼承

詳細資料

  • ISBN:9789865021832
  • 規格:平裝 / 520頁 / 18.5 x 23 x 2.6 cm / 普通級 / 全彩印刷 / 二版
  • 出版地:台灣
  • 本書分類:電腦資訊> 程式設計/APP開發> 其他程式設計相關

主題活動

  • 2022開學書展|百萬大學生按讚推薦,暢銷5折起
  • 2022開學最大電腦書展|5折起,未來必備職場技能,快速學會各種程式

最近瀏覽商品

相關活動

  • 重 構 改善 既 有 程式 的 設計

購物說明

若您具有法人身份為常態性且大量購書者,或有特殊作業需求,建議您可洽詢「企業採購」。 

退換貨說明 

會員所購買的商品均享有到貨十天的猶豫期(含例假日)。退回之商品必須於猶豫期內寄回。 

辦理退換貨時,商品必須是全新狀態與完整包裝(請注意保持商品本體、配件、贈品、保證書、原廠包裝及所有附隨文件或資料的完整性,切勿缺漏任何配件或損毀原廠外盒)。退回商品無法回復原狀者,恐將影響退貨權益或需負擔部分費用。 

訂購本商品前請務必詳閱商品退換貨原則。 

《重構 — 改善既有的程式設計》雜感

出自 Martin Fowler 的這本經典書籍《Refactoring》理應是每位程式設計師都該拜讀的一本好書。這本書是第二版,範例改採用 JavaScript 來做說明,因我對 JavaScript OO著墨不深,我第一個程式語言就是學 Java,私心覺得還是第一版的 Java 範例看得比較好懂。

從本書的前言章節,就對重構做了如下的定義:

  • 重構指在不改變程式原有行為的基礎上,對既有程式碼進行修改,以改進其內部結構。
  • 重構是有紀錄地清理程式碼,盡量降低Bug發生機率的方法。基本上,重構就是改善已經寫好的設計。

一看完定義就可以秒懂,為何「重構」這件事在大部份公司內完全不受重視,甚至可說是鄙視!

「重構指在不改變程式原有行為的基礎上,對既有程式碼進行修改」意味著程式碼重構這件事對既有功能完全沒有改變,可做可不做,食之無味棄之可惜。從長官的角度來看更是如此,做這件事完全沒有任何新產出,沒有新增任何功能或改善任何介面,進度簡報上要如何呈現給大老闆看?尤其這改善工程看不見摸不著,又花了本該用來開發新功能、彌足珍貴的大把時間,你要解釋做了的好處又不具體,支支吾吾、講得不清不楚。天啊!沒說你在重構,還以為你在打混哩!

「重構是有紀錄地清理程式碼」代表著要刪減重複的程式碼或根本不會執行到的程式碼(Dead Code),進行精簡瘦身。這樣行數豈不是大幅地變少,熱愛數字管理的PM或技術Leader,用一些版控指令或計算程式行數的工具如 CLOC 掐(食)指(點滑鼠)一算,我最近Commit上去的檔案,程式碼行數不增反減,File Size越來越小,這樣我的產出和貢獻度豈不是大大下降!不對,產出甚至是負的啊!天啊!這樣績效能看嗎?!

「重構是盡量降低Bug發生機率的方法」要知道,RD就是靠解Bug吃飯的呀!降低Bug發生機率不就代表著可以吃的飯變少了?且未來沒Bug可解的機率變高,省下來的時間,長官們一定會想出各式嘆為觀止、非必要的新功能去填補。Bug解的數量變少,在熱愛數字管理的PM或技術Leader眼中,產值又變更低了,天啊!再度證明這是一個降低自我績效、自廢武功的行為。

「重構就是改善已經寫好的設計」如果程式全部是自己寫的倒還好,但如果是前輩寫的,你去翻動他的架構,擅改同事前輩的程式碼,這還有沒有倫理道德啊!我有准你亂動我的東西嗎?天啊!這簡直大逆不道!幹此等大逆不道的事,將來我要怎麼教小孩?

基於以上種種分析,這本書在台灣軟體界基本沒用處,讀了有害無益,可以扔了。(反串先註明)

等等,但如果你剛好待的是個高度重視軟體工程、著重安全開發與測試、提倡DevSecOps的好公司,這本書可以再撿回來,並且好好閱讀一番,相信是很有收穫的;尤其是自我要求極高,對於寫出高品質、高可閱讀性、高可重用度的程式碼很有興趣者,真的很有幫助。這本可謂是重構界的聖經,沒有第二本了。

呆子都寫得出電腦可以瞭解的程式,但只有優秀的程式員寫得出人看得懂的程式。 — p.12

一些程式架構如最早的MVC、WPF,乃至MVP或MVVM模式,Design Pattern,都是設計在架構上能有效達到使用者介面(View)、商業邏輯(ViewModel 或 ViewController)與資料(Model)的分離,透過抽象化的設計去避免或減少各函式、物件、元件會引起麻煩的緊耦合,使介面設計人員與程式設計人員能更有效率。如果程式開發人員沒有這領域的Sense,僅憑著學過程式語言語法的一招半式便去開發硬幹各種功能,寫出來的程式很大機率就會如同本書第三章提到的「程式碼異味」,包括了如:神秘命名、重複程式碼、冗長函式和參數列、全域資料、發散式修改、霰彈式修改、資料泥團、重複的切換邏輯、暫時欄位、過度耦合的訊息鏈、龐大的Class、過多註解…等等。

遇到上述這些程式碼時,便可考慮進行重構。而本書的Ch.6~Ch.12就是演示各種可以重構的方法,可說是本書淬鍊而出的精華所在。如:封裝、移動功能、組織資料、簡化條件邏輯、重構API、處理繼承...等等。每一個重構的方法都有詳述其動機、作法與簡單的範例。裏頭有很多有架構和撰寫程式的技巧是我從未想過的,這幾章看完真的讓人大開眼界、值回票價。因牽涉比較深度的Coding技術層面和實作細節,在此就不一一贅敘了。唯一我想再三強調的是:「每一次的重構都要進行完整的測試,而且這測試必須是可自動化完成的。」如果一開始的開發就是採TDD(Test-Driven Development)的方式,那就再好不過了。

在重構之前,請先準備好堅實的測試程式,測試程式必須是自檢的。 — p.6

如果有人說他在重構時程式好幾天無法運作,他肯定不是在做重構。 — p.52

當你想要在程式中加入一項功能,但是那段程式的結構很不方便時,請先重構程式,讓你可以輕鬆地加入功能後,再加入那項功能。 — p.5

當你看到程式碼已經充滿異味(臭掉了)或遇到如書上提到的「三次法則」時,就是考慮進行重構程式的時機。長痛不如短痛,發現新功能很難加上去時,先乖乖地先重構好原有的程式,再加新功能,否則技術債(Technical debt)的積累會是呈指數上升的,到時還債時將是百倍千倍的痛苦。一開始貪圖方便不想花時間解決的小問題,猶如發現不穩固的地基,不拔樁重建,反而直接在其上蓋起大樓,一層一層、越疊越高、搖搖欲墜,等到人毀樓塌時,為時已晚。(雖然說大家心態可能就像玩Jenga疊疊樂一樣,只要倒掉前的最後一片不是我放的,就不甘我的事。)

在寫程式的路上,我永遠記得翻譯那本C++聖經的候捷老師,曾在文章中耳提面命的一個比喻:「勿在浮沙築高台。」也記得JAVA大神王建興老師,曾說過的一句話:「抄捷徑的技術債,遲早要還的。」最後便以這兩句發人深省的經典句子做個結尾,細細品味之,不僅適用於Coding,更可用於人生。

[閱讀筆記] 重構---改善既有程式的設計,第一章

為什麼

知道自已不知道

上次在公司內部開始進行 Coding Dojo,在 FizzBuzz 的 Kata 嚐到了甜頭
但是下一道題目「Bowling」,卻卡住了。
我們有測試,也通過測試,但是卻寸步難行,
在重構上我們非常的弱,這裡的重構不是指一次性的全面翻掉,
而是逐步的、可靠的前進,
我想習得這樣的技能,因為現場的代碼腐敗的更加嚴重,
如果連 Kata 產生的代碼都不能優化,
那想對產品指手劃腳只不過是說幹話。

閱讀經典:重構—改善即有的程式設計

重 構 改善 既 有 程式 的 設計

這是一本來自 Martin Fowler 的經典書籍,新版已經出了,而且是以 JavaScript 作為範例語言。
不過我手頭上借到的是以 Java 作為範例的板本。

CH1 重構,第一個案例

第一個問題就是我找不到書中說的「線上範例」,
即使找到我也沒有 Java 的開發環境,所以心一橫就開始了改寫成 C# 的計劃
這部份比我想像中的簡單很多,兩個語言是相同類似的,
第 1 章,第一個案例

接下來只要照著書上一步一步作就會…覺得越來越沒 fu …
為什麼 ???

其實 Martin 大叔在書中有提到「為即將修改的程式建立可靠的測試…畢竟是人,可能會犯錯。所以我需要可靠的測試」。
沒 fu 的原因就是我沒加測試,即使重構了,我也不知道好壞。
沒有反饋是很糟糕的一件事。

CH1 重構,第一個案例,加上測試

那麼要怎麼加測試呢 ?
書上的案例我分析了一下,其實重構的目標只是一個單純的方法
會針對不同的情境回傳不同的字串。

簡單的說,我只要讓測試覆蓋這個方法就可以開始重構了,
我選擇 dotCover來檢驗我的覆蓋率。
選擇的原因很簡單,因為我買了 ReSharper,
其中就包含這個好用的工具。
試著投資一些金錢在工具上的回報是相當值得的。
如果有更好用更便宜的工具也請介紹給我。

OS:課金真的能解決很多人生問題啊(茶)…

最後的結果,我開了一個分支包含了 100%的測試覆蓋率,
這樣就可以開開心心重構了,相信我有測試真得很有感覺。

重構的技法請自行看書,我只稍微作個記錄,有興趣可以 fork 回去玩。

  • Extract Method
  • Move Method
  • Replace Temp with Query
  • Replace Type Code with State/Strategy Pattern
  • Replace Conditional with Polymorphism
  • Self Encapsulate Field

在重構的過程中我儘可能讓步驟小(Baby Step),看我的 commit 歷程即可知道,但是最好可以自已作作看。
另外有一些心法,也稍作個記錄

  • 把一坨爛 Code 抽到獨立的方法之中
  • 如果一個類別方法並沒有使用到該類別的資訊
    • 考慮職責,是不是要讓它搬家
    • 提醒自已這是個壞味道
  • 拆分職責時,有個方法相依兩個不同的類別的資訊,那應該將方法放在哪裡呢?(這裡花了點時間理解)
    • 將方法放在未來可能變化較大的類別之中
    • 相依的資訊作為方法參數傳進來
    • 這樣未來有異動就被縮限在這個類別裡面。
  • 暫存變數常常會帶來問題(壞味道)
    • 儘可能的把它消除
    • 要考慮效能的問題(書上後面會說。)
  • 保持小步調、頻繁測試
    • 使用中繼方法可以縮小重構步調(特別是對 public 的方法)
    • 讓新的 return 值插在舊的 return 之前
    • 測試 ok 就可以刪掉舊 code (有時刪不掉也還是可以運作的)
    • 善用變異測試
  • UML 可以幫助對程式重構前後的理解
  • Java 與 C# 對繼承的處理是不同的
    • Java inheritance vs. C# inheritance

後記

第一章的範例完成後的結果大致如下

重 構 改善 既 有 程式 的 設計

很帥氣的 100%啊,這樣的 code 測試覆蓋率 100 % 全綠燈,
而且完成了重構,根本是現場不可能出現的完全體程式碼!!!
代碼的部份我會放在最後的參考區塊。

重 構 改善 既 有 程式 的 設計

下一步,我有沒有可能讓它更好?或是找出他的缺陷呢?

這個時候我想起了變異測試
還沒有實作過,來玩看看好了。

首先要選擇測試工具,這裡使用了Stryker Mutator,
但是注意只能用在 .Net Core 的版本
照著官網安裝完成後執行

1
>dotnet stryker

跑下去竟然真的找到有存活的變異

重 構 改善 既 有 程式 的 設計

這兩個變異存活的原因是類似的,

1
2
3
4
double result = 2;
if (daysRented > 2)
result += (daysRented - 2) * 1.5;
return result;

變異點發生在 daysRented > 2 的判斷式之中,
現有的測試在變異發生(daysRented >= 2)時,無法提出警訊,也就是測試上的不足。
不過依現有的邏輯,不論是進入 if 進行了加 0 運算,或是直接回傳 result,
都是等價的(回傳 2 ),目前還沒有想法怎麼強化我的測試,
希望有先進願意不嗇指點,實務上跟本沒在跑變異測試。

後記 2

回歸一下我們當初 Kata 的目的:

  • 學習 Pair ,並透過 Pair 彼此學習
  • 學習 TDD ,並透過 TDD 學習重構
  • 學習 Vim,並提昇開發速度

事情沒有那麼簡單,比如說學習 Vim 的過程中,
我們的目的是增進開發速度,但是一開始反而會變慢,
一定要刻意的練習才能習得,
你必須擁有以下的能力。

  • 打字速度,網路上很多資源,我是使用Ratatype作練習
    • 能盲打
    • 指法要正確(特別在特殊符號)
    • 快速切換中英(建議加入英文輸入法用 win + space 之切換過去)
  • 英文能力。命名是開發很重要的一課,英文不好看不懂寫得差,命名自然不會好。
  • 熟悉工具,特別是你的 IDE 與外掛
    • Visual Studio
    • Resharper
    • OzCode
    • more ..
  • Vim
    • Vim Basic 基本功(v、c、i、s、j、k、g、h、l….)
    • VimRc 要學會配置自已的 VimRC,這裡不僅要刻意練習,還要刻意試錯找到自已最順的模式

彼此學習方面需要相當的軟技能,
溝通、尊重、謙虛…;這些一生的功課我就不贅言了。
Pair Programming 一半是 Pair 一半是 Programming;
而在進入 Programming 之前請搞懂你要作什麼

同樣的在 TDD 的過程之中,我們沒有事先理好需求,
沒有想好作好需求分析,隨便選了測試案例就開始進行,
如果好好分析,是可以歸納出其中的邏輯,
甚至是理出 test case 的順序。

重要的是過程,但是我們太在乎結果,以致程式快速的腐敗。
甚至到了難以修改的狀態,僅管有測試保護,卻無法重構。

這是很好的一課,特別在這裡記錄一下。

參考

  • Ratatype
  • 重構 ─ 改善既有程式的設計, 2/e (Refactoring: Improving The Design of Existing Code)
  • dotCover: A Code Coverage Tool for .NET by JetBrains
  • Java inheritance vs. C# inheritance
  • marsen/Marsen.NetCore.Dojo

(fin)

Newer

[實作筆記] ASP.Net Core Logger

Older

[實作筆記]使用 Windows PowerShell 批次上傳 AWS S3

Please enable JavaScript to view the LikeCoin. :P