程式碼重構的實戰經驗和那些坑

孫薇發表於2016-05-14

2012年冬,我在一家創業公司的小團隊裡搞軟體開發。彼時我們有一位真實的企業客戶,且軟體的第一版也已釋出。開發按進度完工,在釋出時我欣喜若狂,也非常驕傲,看著系統服務於每天幾百萬的獨立使用者,併傳送出數千萬條簡訊真是太令人滿意了。到了第二年夏天,公司拿到了真實收入,我的職位變成了開發主管,公司又招了些新人,正待蓬勃發展,一切都很美好。然後我們做了一個巨大的決策失誤:決定重寫軟體——從頭開始。

為什麼我們覺得有必要從頭重寫軟體呢?

在第一次編寫系統程式碼時,我們的時間表十分緊迫,必須與時間賽跑,在計劃時間內趕完進度。因此無論是設計討論,還是審查會議都沒花太長時間——我們沒有時間浪費在這上面——只能匆匆完成一個功能、快速測試,然後趕著去做下一個。我們與別的公司共享辦公空間,我還記得其他公司的軟體開發都會花很長時間做設計、討論架構,再花上數週討論設計模型。

除了設計倉促,原本的系統寫得不差,總體來說架構也不錯。其中有些義大利麵條式的程式碼,是公司之前做概念驗證時留下的,因為這些程式碼能用,再加上工期緊張,當時我們沒有去碰。但後來我們不考慮執行優化改進,卻決定要從頭重寫程式碼的原因在於:

  • 老舊程式碼很糟糕,很難維護;
  • “單一整體式的java架構”對我們的未來發展不利,無法支援有6千萬移動使用者以及多站點部署的大型執行商;
  • 我想要嘗試炫酷的新技術,比如Apache Cassandra、虛擬化技術、二進位制協議、SOA等等。

結果很不幸:我們說服了全公司以及董事會,實現了願望。

程式碼重寫之旅

正式的開發時間是從2012年春天開始的,我們將2013年1月末設定為釋出時間。由於計劃太過龐大,我們需要更多的人,於是在印度聘請了顧問與幾個遠端開發者。但是,我們沒有充分預期到維護原本系統、進行新的開發工作與理解客戶需求這些並行起來的工作量。

還記得我在文章最開始說過,我們有一個真實客戶麼?這位客戶是南美最大的移動運營商之一。在我們開發的系統投入使用後,他們開始對變更和新功能提出要求,因此我們只能繼續更新原來的系統。但是,由於這個系統將會被廢棄,在更新時我們總有些敷衍了事,儘可能找藉口拒絕了客戶許多的新功能需求。結果導致了工期拖延,沒能在原定的deadline完成進度。事實上,我們的進度拖延了整整8個月。

不過我們還是先說說結果吧:當專案終於完工時,新系統看起來非常棒,滿足所有需求。我們做了負載測試,結果顯示新系統能很容易地支援超過1億的使用者,配置集中,檢視圖表的UI工具也很美觀,是時候廢棄舊系統,改換新系統了……

但是客戶拒絕了升級的請求:原本的系統已經獲得了廣泛應用,他們的使用者已經開始依賴舊系統了,他們完全不想冒風險。長話短說,浪費了幾個月之後我們收效甚微。該專案正式宣告失敗。

何時需要重寫程式碼

Joel Spolsky強烈反對重寫程式碼,他建議大家都不要這樣做。不過我不是特別認同:有時候逐步優化與重構非常困難,唯一讀懂程式碼的方式就是重寫。此外軟體開發人員喜歡編寫程式碼,創造新東西——閱讀別人寫的程式碼,嘗試理解他們的程式碼與“思維抽象”會很無聊。不過,優秀的程式設計師也是優秀的維護者。

如果你想要重寫程式碼,一定要出於正確的理由,並有著合適的計劃。比如:

有時候在釋出新版很久之後,老舊程式碼仍需維護,維護兩個版本的程式碼需要耗費大量工作,在開始重寫前請根據專案規模評估所需的時間與資源。

想想其他失去的機會,並比較任務的優先順序。

重寫大型系統比小型系統風險更高,考慮一下能否逐步重寫。我們同時執行了以下幾項工作:切換到新的資料庫、使用“SOA”架構、更換為二進位制協議,其實本可以逐步執行這些更換。

考慮開發者的偏見。在開發者想要學習新技術或新語言的時候,他們會想要使用這些來重寫某些程式碼。不過我不反對這樣做,這也是良好環境與文化的標誌,但應當將它與風險和機遇做比較。

Michael Meadows對何時有需要進行“大型”重寫有著很好的看法

技術上

  • 元件的耦合度很高,無法單獨對某個元件進行修改。重新設計單個元件會導致一連串的變化,不僅會影響到相鄰的元件,甚至間接影響到所有的元件。
  • 技術堆疊太過複雜,未來狀態設計需要變更很多的基礎架構。出於這個原因執行完全重寫十分必要,逐步重新設計在這種情況下沒有優勢。
  • 重新設計單個元件無論如何都會導致對該元件的重寫,在現有設計中沒有可以插入新功能的地方。這種情況下逐步重新設計沒有優勢。

政策上

  • 贊助商無法理解逐步重新設計需要對專案進行長期投入。不可避免的是:大多數公司對於在逐步重新設計上繼續耗費預算沒有興趣。在完全重寫程式碼時,這種現象也很難避免,但贊助商更願意繼續投入,因為他們不想用著半成品的新系統與部分過時的舊系統。
  • 系統使用者更習慣使用“原本的介面”:在這種情況下,政策上不會允許修改系統的重要部分(前端)。但如果完全從頭開始重寫,則會繞過這個問題。使用者還會堅持使用“相同的介面”,但這次你反擊的理由更為充足。要記得:逐步重新設計的總成本總是要高於完整重寫程式碼,但一般來說對企業的影響更小一些。在我看來,如果重寫理由充足,公司又有超級優秀的開發者,那麼就開工吧。

放棄正在開發的專案很危險:浪費大量的時間和金錢重複實現已有功能,同時還會放棄實現新功能的機會,有可能激怒客戶並導致工作計劃推遲。如果你正在重寫程式碼,那是你的權力,不過請確保這麼做的理由正確,同時瞭解風險也做了相關計劃。

相關文章