重構—改善既有程式的設計(chapter 2,3)
DESCRIPTION
TRANSCRIPT
![Page 1: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/1.jpg)
重構 - 改善既有程式的設計第二、三章
Chris Huang
![Page 2: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/2.jpg)
第二章 重構原則
![Page 3: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/3.jpg)
何謂重構 名詞:對軟體內部的一種調整,目的在不
改變『可察的行為』前提下,提高可理解性,降低修改成本
動詞:使用一系列重構準則,在不改變『可察的行為』前提下,調整其結構
兩頂帽子添加新功能:不應修改既有程式碼重構:不能在添加功能
![Page 4: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/4.jpg)
為何重構 改進軟體設計
只為短期目的而修改程式,程式碼會逐漸腐敗 使軟體更易被理解
你的程式碼還有第二位讀者(可能就是自己) 幫助找臭蟲
可深入瞭解程式行位,幫助除錯 幫助提高編程速度
惡劣的設計很快就會讓開發速度慢下來
![Page 5: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/5.jpg)
何時重構 三次法則
事不過三,三則重構 添加功能時
重構幫助理解方便添加功能方便以後添加功能
修補錯誤時重構幫助理解方便除錯
復審程式碼時幫助審閱別人的程式碼(我比較持保留態度)
![Page 6: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/6.jpg)
怎麼跟經理說 經理懂技術:設法證明給他看
把重構當成 code review 意見引入程式碼內 經理不懂:不要告訴他!
只要能快速創造出高效軟體就好
![Page 7: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/7.jpg)
重構的難題 資料庫
多數商用程式都與 DB schema 緊密結合DB schema 的改變讓人不得不遷移所有資料,可能是
漫長而繁瑣的工作 修改介面
Public interface○ 連同所有用到的程式一起改
Published interface○ 維護兩套介面,讓舊介面使用新介面的函式○ 舊介面加註 deprecate
不要太早發佈介面不要揭露不必要的介面
![Page 8: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/8.jpg)
重構的難題 難以完成的設計改動
很難把『 no security 』重構成『 good security 』 何時不該重構
實在太亂,重寫比較快 現有程式碼不太能正常運作 方案:把大塊頭軟體封裝良好的組件
○ 除一針對個別組件決定重構 or 重建 專案已瀕臨最後期限
○ 沒時間了,先解決燃眉之急吧
![Page 9: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/9.jpg)
重構與設計 預先設計聽來很棒,但確保預先設計完全無誤的壓力太大
重構可成為預先設計的替代品,先照最初想法讓程式有效運作,然後不斷重構得到良好的設計
一開始不需要找出完全正確的解決方案,只要足夠合理的解決方案即可
重構讓日後的修改成本不會太高
![Page 10: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/10.jpg)
重構與效率 不要浪費無謂的時間
隨時關注效能往往沒有效果 90% 的時間花費在 10% 的程式上
Profiling find hot spot tunning 重構雖然會讓程式變慢,但良好的結構反而讓最佳化容易進行 Write tunable software and then tune it
![Page 11: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/11.jpg)
重構起源何處 (自己看書吧)
![Page 12: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/12.jpg)
第三章 程式碼的壞味道決定何時重構、何時停止,跟知道如何重構一樣重要
![Page 13: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/13.jpg)
Duplicated code 用 extract 取出共同的程式碼 Extract push up 推入 superclass 或許可用 from template 函式使用不同演算法,可考慮 substitute algorithm
![Page 14: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/14.jpg)
Long method 感覺需要寫註解把要講得東西寫成函式,以其用途(非實作)命名 99% extract
大量參數或暫時變數 replace temp with query 尋找註解:程式碼用途和實現手法的語意距離 條件式或迴圈
if(connected) { reportStatus();}
foreach(String host: hosts) { shutdownAgent(host);}
![Page 15: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/15.jpg)
Large class Instance 變數太多 duplicated code Extract class Extract subclass Extract interface
![Page 16: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/16.jpg)
Long parameter list 太長的參數列難以理解 函式需要的參數多半可以在 host class 中找到 傳遞物件給函式 Replace parameter with method Preserve whole object Introduce parameter object
void clearCanvas(bytes [] buffer, int width, int height) {}
void clearCanvas(Bitmap bmp) {}
![Page 17: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/17.jpg)
Divergent change 改 feature 1
動 function A, B, E, F 改 feature 2
動 function B, C, D, K (通常這種 class 也會很肥大) 運用 extract class 分拆
![Page 18: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/18.jpg)
Shotgun surgery
牽一髮,動全身 改 feature 1
動 class A, B, E, F 改 feature 2
動 class B, C, D, K
Move method/field Inline class
![Page 19: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/19.jpg)
Feature envy Move method Extract method 反例
Strategy, visitor, self delegation 為了對抗 divergent change
class A {
B b;
void func1() { b.init(); if(b.getConnected()) { info(b.getStatus()); } else { b.alert(); } }
void func2() { while(b.read(buffer)) { b.signal(); } }}
![Page 20: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/20.jpg)
Data clumps 刪定一組中的一個,其他就變得
沒有意意 (通常也有 duplication ) Extract class Introduce parameter object Preserve whole object 改了後可能產生 feature envy 繼續重構
class A { ... string schema; string host; int port; ...}
Class B { ... string schema; string host; int port; ...}
![Page 21: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/21.jpg)
Primitive obsession 不愛用小物件,拼命用 primitive
Ex: Money, Range, Date, PhoneNumber, ZipCode Replace data with object Replace type code with class Replace type code with subclass Replace type code with state/strategy …
![Page 22: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/22.jpg)
Switch statements 通常也有 duplication 改一個,統統都得改 可用多型解決
void connect(int host_type) { ... switch(host_type) { case 1: ((mysql) handle).connect(); break; case 2: ((mssql) handle).connect(); break; }}
void disconnect(int host_type) { ... switch(host_type) { case 1: ((mysql) handle).disconnect(); break; case 2: ((mssql) handle).disconnect(); break; }}
![Page 23: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/23.jpg)
Parallel inheritance 對某個 class 新增 subclass, 也必須為另一個新增 兩個繼承體系的 subclass 名稱自首相同 Refer to Move method, move field
![Page 24: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/24.jpg)
Lazy class Class 經過修改後,重要性已縮水 勇敢砍吧 Collapse hierarchy Inline class
![Page 25: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/25.jpg)
Speculative class 『總有一天會需要』而留的程式 把他搬掉
等用到再說吧 Collapse hierarchy Remove parameter Rename method
![Page 26: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/26.jpg)
Temporary field 暫時變數都放 instance 暫時變數只為某些函式而用,只是為了不想傳參數 Extract method Extract class
![Page 27: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/27.jpg)
Message chains 客戶端將搜尋過程中的
structure of navigation 緊密耦合,修改物件關係將導致客戶端也需修改
string A::getInfo() { return b.getInfo();}
String B::getInfo() { return c.getInfo();}
String C::getInfo() { return d.getInfo();}
String D::getInfo() { return e.getInfo();}
![Page 28: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/28.jpg)
Middle man 過度使用 delegation Remove middle man Replace delegation with
ingeritance
class A { B b; int func1() { return b.func1(); }
int func2() { return b.func2(); }
int func3() { return b.func3(); }}
![Page 29: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/29.jpg)
Inappropriate intimacy 兩個 class 過份親密,互探對方
private Move method Move field Change bidirectional
association to unidirectional Extract class Hide delegate
class A { friend class B; ...}
Class B { friend class A; ...}
![Page 30: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/30.jpg)
Alternative classes with different interface
Rename method 反覆運用 move method 直到 protocol 一致 或 extract superclass
![Page 31: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/31.jpg)
Incomplete library class 3rd-part library 無法更動 Introduce foreign method Introduce local extension
![Page 32: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/32.jpg)
Data class 只有 field 跟一堆 getXXX, setXXX Encapsulate field Encapsulate collection Remove setting method
Move method 把呼叫行為搬進 data class Hide method 把 public 變成 private
![Page 33: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/33.jpg)
Defused bequest 避開某些特定繼承 十之八九壞味道很淡,可以忽略 不能 reuse superclass 的實作(拒絕實作),卻又不支 superclass 的介面
Replace inheritance with delegation
![Page 34: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/34.jpg)
Comments 把 comments 當除臭劑用 程式有很長的註解這裡的程式寫得很糟糕 當你感覺需要寫註解,請先試著重構,試著讓註解
變得多餘 Extract method rename method Introduce assertion
如果你不知道該做什麼,才是寫註解的好時機
![Page 35: 重構—改善既有程式的設計(chapter 2,3)](https://reader033.vdocuments.mx/reader033/viewer/2022061210/548e735cb47959313c8b4607/html5/thumbnails/35.jpg)
Q&A