星期六, 8月 23, 2003

讀Refactoring一書有感

重構

其實很早就拿到這本書原文電子檔
不過語言上的隔閤卻讓我對這道美食始終難以下嚥
總是翻個二、三頁就去見周公去了
時日一久竟也忘了這本書的存在
真是要感謝侯老師及熊節先生的無償提供前1-6章的中文譯本
火熱下載點:http://www.jjhou.com/jjtbooks-refactoring.htm

首先強烈建議先閱讀本書第一章
因為實在是寫得太黯然、太銷魂啦
我真怕以後看不到這樣的好書該怎麼辦
此章透過一個逐步重構的實例來點出重構技巧的神奇
讓一隻堅硬如石的程式慢慢軟化
相信就算您是個修道多年
信仰忠貞以設計為先的道徒
看完這章大概也會馬上拋開所有禮教
還俗投入重構的美麗新世界中

好吧…我承認這樣講是有點誇張,
但是不誇大哪會有噱頭引您往下看哩

其實重構的步驟也不用想得很複雜
重構的目的並不是為程式增加新功能
只是為了提高程式的可讀性及重用性
重構有時只是改變一下程式碼的位置或取個更有意義的變數名稱,
再將其放置在適當的位置
例如像當A類別內某個函式的頻繁的操作B類別的屬性
或許這就是一個暗示,暗示我們應該讓這函式回歸至B類別處
讓資料和引用這些資料的操作總是在同一個類別之中發生

而Design Pattern則是為Refactoring建立了一個依循的方向
所以當我們透過良好的設計範式來切割類別間的關係時
有些類別間比較複雜的函式根本不會知道外面的世界已經變天哩

再來什麼時候你需要重構哩
例如當你發覺程式寫好一週後,再回去看它時
突然懷疑一週前你是不是有被火星人附身時
你肯定需要重構一下你的程式

另外在書中也提到
我們可依循三次法則
事不過三、三則重構

而若是對於已發佈介面published interface進行重構
則我們可以保留舊介面,用其呼叫新介面
但千萬不要再犯copy-paste的錯誤
並可透過deprecated來標記舊介面
提醒及避免其他人再繼續呼叫這個介面

有時為了撰寫上的方便
我們會讓暫存變數被賦與二次以上的值
像類似這種一時的便宜行事,卻會造成事後對程式的意圖造成理解上的困難
於是像這樣的地方,我們也應該透過重構的技巧來重整它
書中常見的手法就是將拆解成多個足以自我說明其意義的變數
然後我們可將新的暫存變數宣告成final,
便可透過compiler來檢驗是否仍有重覆賦值的缺失

而對於Java為何選擇pass by value而非pass by reference有疑問的人
可以看一下Remove Assignments to Parameters這個重構手法
其實重點就在於強化程式的清晰度及減少非預期的邊際效應

相信你一定有這種經驗
看到一個超肥的大型函式…讓人一時之間慌了手腳不知從何剖析它
這時我們可運用必殺技Replace Method with Method Object
將此大型函式獨立宣告成一個物件
如此一來函式內的變數就成了該物件的欄位
然後我們就可任意肢解這個大型函式,而不必傳遞任何參數
使其各自成為精巧且更具可讀性的小型函式

另外書中有段話雖然跟重構無關,但我覺得實在是講得太好了
也順便節錄一下
"懶惰是程式員的美德
所以能立即查閱的東西
千萬別記在腦子裡
免得把腦袋塞爆"

而書中有些教條式的守則
我想就算一時間不能體會
背起來也是無妨
例如:見到黑影就開槍
喔~不對、不對....
是看到switch就想到polymorphism
或是
當你感覺需要撰寫註解前請先嘗試重構,試著讓所有註釋都變得多餘
(設計良好的程式本身就應具有解譯自身意圖的能力)

在第四章提到了撰寫自我測試程式的重要性
測試是重構的前提
而一般慣用的手法都是寫test main()
不過缺點就在於難以執行多種測試
所以在此章裡介紹了如何透過JUnit來執行測試

總的瀏覽本書前一至六章一遍後
我想起我的前小組長也十分愛玩重構的遊戲
每每看到我寫得亂七八糟的垃圾一到他手裡就被重構的井然有序
內心深處總是覺得十分的佩服…
曾幾何時我幾乎認為那是我達不到的彼岸

因為覺得自已即不是記憶力超強的陳俊生
也不是火星來的假面怪客
能在腦中憑空勾勒出理想中的設計模型

不過現在若是能一步步透過書中所介紹的重構技巧…
或許能使得平凡如我,也能有機會一窺外星人的境界

也記得有陣子我看到OO就很煩
總感到造成追縱程式流程的困難,就是在不斷的delegation之後
看了本書中p.61間接層及重構後
仔細想想才體會到原來間接層所帶來的利益為何

慢慢發覺我的壞習慣是太愛追根究底
實際上好的切割及命名法則,可使我們更能憑著直覺,
來理解程式的執行

而一如GOF的Design Pattern般的鉅作
本書照慣例創造了許多術語
不過感覺上各項重構的命名是容易會意的多,若是為了溝通方便
其實倒是蠻容易記憶的
請想像一下以下的討論場景

強者H:嘿…我覺得這裡該嘗試用Extract Method來重構
小呆P:嘩~醬子這個Method得傳入一狗票參數耶
強者H:呀不然這邊再搞個Preserve Whole Object
小呆P:鳴鳴鳴…Object之間的界定還是很難搞定呀
強者H:好吧…那就出必殺技Replace Method with Method Object吧
小呆P:救命!!! 我頭昏了啦 @_@

是不是覺得有了術語的協助,其實更能增進溝通的效率呢?

雖然從現實角度來看一個軟體專案的執行
往往都因deadline緊迫而壓縮整個開發的時程
這個時候去考量重構來讓往後開發或維護更加順利似乎是有點緩不濟急
不過方法在這裡,如何巧妙的應用及選擇合適的時機點切入
相信就要由聰明的您自已來判斷了

最後我想這本書讓我感到最珍貴的
就在於作者Erich Gamma將平時一些難以言傳的重構技巧
作一個有系統的整理及說明
讓想要學習重構技巧的人能感到有所依循
跟隨著大師的腳步前進
相信總是比憑著自已的直覺要來的準確的多

看到這裡,大家有沒有開始覺得手癢起來了呢?
對於你一直看不爽的code,現在就讓我們動手來肢解它們吧!!!

後記:
雖然書中也提到重構不是建構軟體的銀子彈
至多只能算是把銀鉗子
但我還是感到十分的興奮
迫不及待的想把讀後心得分享出來
並且開始對Smalltalk產生了好奇心
有沒人要來澆盆冷水的呀 :p