商業需求對於Refactor的重要性
自從大學畢業進到第一份工作時才開始接觸refactor, 從如何消除code smell到理解什麼是好的refactor
Refactor對於我自己來說有三個目的
- 易閱讀
- 易維護
- 易測試
易閱讀:不管任何人來看程式碼都可以清楚明白涵意
易維護:當需要對於原本的程式碼做修改時可以快速且不影響其他功能
易測試:讓程式碼可以容易寫自動化測試
“易維護”以及“易測試”很容易理解, 因為平常在開發的時候就會深刻體會到程式碼不好新增、修改以及寫測試是多痛苦的事情
“易閱讀”說得白話一點就是看程式碼像是看一篇文章
一開始對於它的理解只局限於命名變數的時候需要注意、該抽方法的時候要注意單一職責、方法名稱要清楚表明方法做的事情
直到有一次遇到一個case讓我對於“易閱讀”以及refactor有更深刻的了解
範例
功能需求:添加廣告的時候辨識投放廣告的時間是否已經有其他廣告正在投放
收到功能需求後的思路:
- 一次只能放一個廣告的位置需要做檢查,其他一次可以投放多個廣告的位置不需要檢查
- 當新增一個廣告,需要檢查已經存在的廣告是否有佔用想要投放新廣告的位置和時段
- 和已存在廣告的時段、country, language條件都有交集表示此狀況下不能再新增廣告
- 當要更新已經存在的廣告則需要從GetExistAds排除掉目前要更新的廣告, 否則永遠都會比對到自己
If( new/updated Ad's position only can put an Ad )
{
if( the period time that the new/updated Ad display is not available &&
the exist Ad's position only can put an Ad &&
the exist Ad isn't the new/updated Ad )
{
if( new/updated Ad's country has intersection with exist Ad's country &&
new/updated Ad's language has intersection with exist Ad's language )
{
The position isn't available
}
}
}
單純從功能面下手完成的程式碼就如同圖下一樣,基本上可以refactor的部分就只有feature envy, naming的部分, 巢狀for迴圈還是沒有什麼調整空間

從商業需求、目的角度思考
首先問問看看自己這些問題都瞭解了嗎
為什麼需要這個功能?
這個feature目的是什麼?
商業需求:想要盡可能賣出更多廣告版位
從商業需求重新描述這個feature:如果時段內沒有廣告被投放就可以投放其他廠商的廣告
重新描述後就很清楚程式碼應該呈現出來的樣子
If ( the position is empty )
{
put other Ad
}

程式碼的易閱讀就是需要表現出商業需求
Refactor使用的相關技巧
- 語法糖的使用
首先在決定使用什麼語法糖前先要了解這個class或是這些method本質是什麼東西
以這次case來說本質是Helper
一般來說Helper的架構是巢狀, 導致不易閱讀
所以選擇使用extension method語法糖攤平所有過濾的方法, 增加閱讀性

2. Select many:攤平兩層List
List<Restriction> -> List<string>Country
List<Restriction> -> List<string>Lang


3. 傳進method的參數盡量使用object
在使用object當參數的時候可以多思考這麼做的優點是什麼
List<Restriction>當參數:未來如果user成為篩選條件的時候user也可變成restriction
e.g. 喜歡A類型廣告的user, 限定只能看到A類型廣告
4. 處理feature envy時什麼時機點應該推進model
推入model前先思考現在要推的東西和model是否有高內聚,當然也要避免有不必要的耦合
IsLangIntersect是restriction的條件之一,和restriction物件有高內聚特性也沒有不必要的耦合
OnlySupportOneAd這個method和AdvertismentInfo object不是高內聚而是和Position才是高內聚,Position才知道版位是不是只能投放一個廣告,這次暫時使用extension method語法糖呈現
比較好的是調整Position property的type,它的型態應該是個物件,OnlySupportOneAd就可以推入Position的物件中


總結
- Refactor前或實作feature前先理解method或feature的目的及價值
- 了解目前要做的東西本質是什麼才選擇要使用哪種語法糖
- 決定參數要放什麼object之前多想想有哪些好處
- 將method推進model之前考慮和model是否高內聚