面對 Legacy Code ,該重構還是重寫?

在程式已經上線很久很久的情況下,公司也找了不少人來維護這些程式碼;而因為開發者來來去去,加上每個人對程式開發的觀念不同,他們也許都有過這樣的感受:

  • 因為缺少規格文件,這團程式碼到底有哪些是該拔還是不該拔,很抖;算了,放著不管吧。
  • 因為迫於時間壓力,被只求解決眼前問題所帶來的不穩定性困擾著;算了,有 bug 再修。
  • 因為沒有寫過測試,修正程式時常常擔心改東壞西的不安全感;算了,有人叫再說。
  • 因為團隊已有慣例,想要動手調整架構,卻怕同事不支持;算了,給下個人弄吧。
  • 因為依賴語言特性,有些好的作法引入之後反而造成問題;算了,反正會動就好。

結果專案中的技術債越欠越多,而這些程式碼也變成了所謂的 legacy code 。

在維護這樣的 legacy code 時,我想很多開發者應該都思考過這個問題:「我到底應該要重構還是重寫?」老實說我的答案就是 “It depends” 。

重構與重寫沒有哪種方法一定比較好,不過在選擇之前,我還是得先把重構和重寫的不同說明清楚。

重構不是你想的那樣

不過很多人對「重構」這個詞有所誤解,以為它是在功能完成後大幅度地修改原有的程式碼;放在 legacy code 上時,大概就會認為是「架構設計翻新」這種程度的修改。

事實上重構的粒度是非常小的,它並不是整個專案做完之後才開始,而是開發功能的過程中就一小步一小步的進行。重構的時間點不要離寫完程式碼的時間點太遠,像是在完成一小部份的功能後就立刻回頭看看是否能讓程式碼更結構化,或是在每次開始新功能先思考既有結構是否影響了新功能的加入;然後針對這些部份進行微調,所以重構佔的是開發一小部份的時間。

會提出要重構 legacy code 的人,多數是希望不要花太多力氣去撰寫新的程式碼,而是重用已經存在的邏輯;畢竟已上線運作的舊有程式碼,比起那些沒經過時間驗證過的新寫程式碼來得可靠數百倍。只是如果想重用這些既有邏輯有兩個前提:一、它們易於理解且有組織化;二、有自動化測試。不過令人苦惱的是:大多數 legacy code 都很難達成這兩個要求。

但假設這兩個前提達到的情況下,進行大粒度的重構也不是不可能,但還是有些工作得先進行。

重寫也不是你想的那樣

那麼重寫整個專案呢?重寫聽起來是擺脫一些舊包袱的好方法,似乎這樣就可以不用再去理會那些 legacy code 了。所以就可能會有些剛到公司幾個月的新人,會在看不慣前人寫的程式碼時就提出了重寫的建議,只不過事情通常不會是像他們想得這麼簡單。

很多 legacy code 問題都不是技術的問題,而是它已經創造出一個每個人都依賴著它的世界,所有相關人士與現存系統對規則的認知都是基於這些 legacy code ;因此一旦你決定真的要重寫整個專案,你必須有相當的自信去說服所有關係人,並爭取到上頭的支持;最好能提出一份可行的 roadmap ,來讓大家能夠審視你的想法。再來也要考慮到公司是否對這個專案有其他預定中的計劃,有沒有時間讓你重寫。

重寫最重要的一點,是你夠不夠清楚這個系統現行的規格。當你真的可以重寫時,你必須邀請 PM 或熟悉這個系統來龍去脈的人員來協助你瞭解整個舊有系統。很多失敗的重寫,就是因為不夠瞭解原有的系統規則,不清楚為什麼前人針對某些情境撰寫 workaround ,結果在新專案上線時因為少做了某些細部功能而使得整個服務大爆炸。所以當你想大刀闊斧地砍掉重寫,就得想辦法把所有規則都涵蓋到;而這件事本身就是曠日費時,你不可能馬上完成,所以還是必須顧好現行的 legacy code 。

這使得重寫有個很明顯的劣勢:當關係人打算在服務新增功能時,你可能要在舊專案和新專案上同時進行。所以一般重寫時都會請 PM 凍結需求,讓新專案上線後再繼續實作這些新功能;只是這時候你就得跟時間賽跑,如果你家 PM 人很好的話會幫你擋需求,只是他擋得了一時,擋不了一世。

所以我到底該選哪條路?

假設不論是重構或是重寫,公司都給時間了,我們該怎麼選擇呢?雖然說是 “It depends” ,但總應該有些判斷的原則吧?這邊我簡單整理重構時要著重的幾個要點:

  1. 專案本身已經有整理好相關文件,同時也有自動化測試。
  2. 專案本身只是部份程式體質不佳,整體來說還算好理解。
  3. 專案影響到的關係人太多,無法輕易凍結需求。

符合上述特點的專案,你可以考慮用重構,一點一點地來將它的體質調整好。

那麼什麼時候要考慮重寫?

  1. 改個幾行程式碼就得花很多成本來手動測試。
  2. 專案用的技術已經沒人改得動它了,或是新的系統環境不支援。
  3. 現行的技術或是你的能力可能可以更快地實現同樣的系統。
  4. 沒人知道某些功能還有沒有用,文件也早就遺失了。

當然以上列的這些要點不見得有全面的考量,重要的還是要看大家所面對的專案狀況來決定。簡單來說,當 legacy code 的複雜度已經高到你難以維護,每次修改都要耗費大量時間與人力去驗證時,也許就是重寫的契機;在這之前,你還是應該以重構為優先。

不論是重構或重寫,都一定要瞭解這兩者對公司所產生的衝擊,這樣才能找出影響最小的方式來讓 legacy project 煥然一新。

下一篇,我來聊聊一些我在重構或重寫時的經驗與心得