關于代碼重構(gòu)的實戰(zhàn)經(jīng)驗
大?。?/span>0.4 MB 人氣: 2017-10-10 需要積分:1
為什么我們覺得有必要從頭重寫軟件呢?
在第一次編寫系統(tǒng)代碼時,我們的時間表十分緊迫,必須與時間賽跑,在計劃時間內(nèi)趕完進度。因此無論是設計討論,還是審查會議都沒花太長時間——我們沒有時間浪費在這上面——只能匆匆完成一個功能、快速測試,然后趕著去做下一個。我們與別的公司共享辦公空間,我還記得其他公司的軟件開發(fā)都會花很長時間做設計、討論架構(gòu),再花上數(shù)周討論設計模型。
除了設計倉促,原本的系統(tǒng)寫得不差,總體來說架構(gòu)也不錯。其中有些意大利面條式的代碼,是公司之前做概念驗證時留下的,因為這些代碼能用,再加上工期緊張,當時我們沒有去碰。但后來我們不考慮執(zhí)行優(yōu)化改進,卻決定要從頭重寫代碼的原因在于:
老舊代碼很糟糕,很難維護;
“單一整體式的java架構(gòu)”對我們的未來發(fā)展不利,無法支持有6千萬移動用戶以及多站點部署的大型運行商;
我想要嘗試炫酷的新技術(shù),比如Apache Cassandra、虛擬化技術(shù)、二進制協(xié)議、SOA等等。
結(jié)果很不幸:我們說服了全公司以及董事會,實現(xiàn)了愿望。
代碼重寫之旅
正式的開發(fā)時間是從2012年春天開始的,我們將2013年1月末設定為發(fā)布時間。由于計劃太過龐大,我們需要更多的人,于是在印度聘請了顧問與幾個遠程開發(fā)者。但是,我們沒有充分預期到維護原本系統(tǒng)、進行新的開發(fā)工作與理解客戶需求這些并行起來的工作量。
還記得我在文章最開始說過,我們有一個真實客戶么?這位客戶是南美最大的移動運營商之一。在我們開發(fā)的系統(tǒng)投入使用后,他們開始對變更和新功能提出要求,因此我們只能繼續(xù)更新原來的系統(tǒng)。但是,由于這個系統(tǒng)將會被廢棄,在更新時我們總有些敷衍了事,盡可能找借口拒絕了客戶許多的新功能需求。結(jié)果導致了工期拖延,沒能在原定的deadline完成進度。事實上,我們的進度拖延了整整8個月。
不過我們還是先說說結(jié)果吧:當項目終于完工時,新系統(tǒng)看起來非常棒,滿足所有需求。我們做了負載測試,結(jié)果顯示新系統(tǒng)能很容易地支持超過1億的用戶,配置集中,查看圖表的UI工具也很美觀,是時候廢棄舊系統(tǒng),改換新系統(tǒng)了……
但是客戶拒絕了升級的請求:原本的系統(tǒng)已經(jīng)獲得了廣泛應用,他們的用戶已經(jīng)開始依賴舊系統(tǒng)了,他們完全不想冒風險。長話短說,浪費了幾個月之后我們收效甚微。該項目正式宣告失敗。
我們學到的經(jīng)驗
大多情況下都不該從頭重寫代碼。我們重寫代碼的原因是錯誤的,盡管一部分代碼不怎么樣,如果我們花些時間閱讀理解源代碼,就可以通過重構(gòu)修復問題。對架構(gòu)的可擴展性及性能我們確實有顧慮,擔心它無法支持復雜的業(yè)務邏輯,但完全可以逐步進行修復。
從頭重寫系統(tǒng)對用戶來說沒有價值。新技術(shù)與流行詞對工程師團隊來說看似很酷,但如果不能按照客戶需求提供新的功能,則毫無意義。
我們在集中精力重寫代碼時,錯過了真正的機會。以前我們給客戶提供了一個非?;镜摹罢军c分析工具(Web Tool)”供他們查看圖表與報告。但隨著內(nèi)容越來越多,他們開始要求增加新功能,比如實時圖表、訪問級別等等。由于我們不打算繼續(xù)沿用舊代碼,時間也不足夠,就敷衍著要么拒絕了新需求,要么湊合了事。結(jié)果最后客戶不再使用這個工具了,他們堅持通過郵件來發(fā)報告。本來我們還有另一個機會來構(gòu)建一個有緊迫需求的強健分析平臺。
我低估了在維護舊系統(tǒng)的同時,開發(fā)新系統(tǒng)所需要的工作量。我們原本預計一個月能有3到5次需求,結(jié)果卻是預計數(shù)量的三倍。
我們以為:由于沒能花上數(shù)日討論合適的設計模型與實例,代碼就會很難閱讀與維護,結(jié)果事實上我在較大公司所見過的最專業(yè)代碼,比我們的代碼還要糟糕兩倍。因此,在這一點上我們大錯特錯。
何時需要重寫代碼
Joel Spolsky強烈反對重寫代碼,他建議大家都不要這樣做。不過我不是特別認同:有時候逐步優(yōu)化與重構(gòu)非常困難,唯一讀懂代碼的方式就是重寫。此外軟件開發(fā)人員喜歡編寫代碼,創(chuàng)造新東西——閱讀別人寫的代碼,嘗試理解他們的代碼與“思維抽象”會很無聊。不過,優(yōu)秀的程序員也是優(yōu)秀的維護者。
如果你想要重寫代碼,一定要出于正確的理由,并有著合適的計劃。比如:
有時候在發(fā)布新版很久之后,老舊代碼仍需維護,維護兩個版本的代碼需要耗費大量工作,在開始重寫前請根據(jù)項目規(guī)模評估所需的時間與資源。
想想其他失去的機會,并比較任務的優(yōu)先級。
重寫大型系統(tǒng)比小型系統(tǒng)風險更高,考慮一下能否逐步重寫。我們同時執(zhí)行了以下幾項工作:切換到新的數(shù)據(jù)庫、使用“SOA”架構(gòu)、更換為二進制協(xié)議,其實本可以逐步執(zhí)行這些更換。
考慮開發(fā)者的偏見。在開發(fā)者想要學習新技術(shù)或新語言的時候,他們會想要使用這些來重寫某些代碼。不過我不反對這樣做,這也是良好環(huán)境與文化的標志,但應當將它與風險和機遇做比較。
Michael Meadows對何時有需要進行“大型”重寫有著很好的看法:
技術(shù)上
組件的耦合度很高,無法單獨對某個組件進行修改。重新設計單個組件會導致一連串的變化,不僅會影響到相鄰的組件,甚至間接影響到所有的組件。
技術(shù)堆棧太過復雜,未來狀態(tài)設計需要變更很多的基礎架構(gòu)。出于這個原因執(zhí)行完全重寫十分必要,逐步重新設計在這種情況下沒有優(yōu)勢。
重新設計單個組件無論如何都會導致對該組件的重寫,在現(xiàn)有設計中沒有可以插入新功能的地方。這種情況下逐步重新設計沒有優(yōu)勢。
政策上
贊助商無法理解逐步重新設計需要對項目進行長期投入。不可避免的是:大多數(shù)公司對于在逐步重新設計上繼續(xù)耗費預算沒有興趣。在完全重寫代碼時,這種現(xiàn)象也很難避免,但贊助商更愿意繼續(xù)投入,因為他們不想用著半成品的新系統(tǒng)與部分過時的舊系統(tǒng)。
系統(tǒng)用戶更習慣使用“原本的界面”:在這種情況下,政策上不會允許修改系統(tǒng)的重要部分(前端)。但如果完全從頭開始重寫,則會繞過這個問題。用戶還會堅持使用“相同的界面”,但這次你反擊的理由更為充足。要記得:逐步重新設計的總成本總是要高于完整重寫代碼,但一般來說對企業(yè)的影響更小一些。在我看來,如果重寫理由充足,公司又有超級優(yōu)秀的開發(fā)者,那么就開工吧。
放棄正在開發(fā)的項目很危險:浪費大量的時間和金錢重復實現(xiàn)已有功能,同時還會放棄實現(xiàn)新功能的機會,有可能激怒客戶并導致工作計劃推遲。如果你正在重寫代碼,那是你的權(quán)力,不過請確保這么做的理由正確,同時了解風險也做了相關計劃。
?
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%