接手歷史悠久的老項目,干or跑?
本文轉載自微信公眾號「跨界架構師」,作者Zachary。轉載本文請聯(lián)系跨界架構師公眾號。
大家好,我是Z哥。
這是我的第199篇原創(chuàng),離200篇還有一步之遙。為了慶祝這重要時刻,我也在琢磨著要不要在第200篇的時候搞個什么小活動。還沒想好,等下周再看吧。
不過不管怎樣,你也應該為Z哥的堅持點個贊吧,哈哈。所以,看完文章后不要忘了劃到文末點贊哦~
好了,回到正題。
很多人吐槽老項目是怎么怎么垃圾。這的確是一個很大的問題。根據(jù) IEEE Spectrum 之前發(fā)布的一份報告數(shù)據(jù):
自 2010 年以來,全世界IT 產(chǎn)品和服務支出約為 35 萬億美元,其中約四分之三用于運營和維護現(xiàn)有的 IT 系統(tǒng)。另外,至少有 2.5 萬億美元用于嘗試替換舊的 IT 系統(tǒng),而且其中約有 7200 億美元被浪費在失敗的替換工作上。
https://spectrum.ieee.org/computing/it/inside-hidden-world-legacy-it-systems
因此,面對不堪的、充滿歷史味道的老項目對程序員群體來說會是一個常態(tài)。
不過我們可以做些什么呢?難道是要么硬著頭皮去填別人挖的坑,要么跑路么?
如果你不跑路的話,最常見的應對方式無非是「重寫」或者「重構」。
一 重寫
一般來說,越是年輕的程序員越是最喜歡重寫。除了年輕氣盛的原因外,主要是因為完全擺脫了老代碼的技術債和束縛,可以盡情地施展自己的才華。
但是對于老系統(tǒng)的重寫,如果沒有高層的支持、業(yè)務部門的配合,靠譜的開發(fā)團隊,這事大概率很難能按預期完成。
而且選擇「重寫」方案不僅僅是重新寫一套代碼這么簡單,系統(tǒng)切換也是一個頭疼的事情,在復雜一些的項目里,它的難度并不亞于重寫一套代碼。
而且一旦選擇「重寫」,意味著在一段時間內要么老系統(tǒng)并行開發(fā),要么會攢一堆需求,業(yè)務方能不能持續(xù)支持「重寫」也會面臨很大的挑戰(zhàn)。
就算這些問題都能搞定?!钢貙憽惯€可能造成的一個結果是:在過了幾個月后,重寫后的系統(tǒng)又成了別人眼中的“破爛不堪的老系統(tǒng)”。這是最諷刺的……
如果在重寫過程中,由于任何原因犧牲了對質量的要求,這個諷刺很容易成為現(xiàn)實。
因此,很多公司之所以不支持重寫,理由是:
又不是不能用。
這么看來他們并不是迂腐,也是一種理性的選擇,也是沒錯的。
二 重構
相對地,年紀越大的程序員可能更傾向于重構。畢竟他們有更多的機會見過、經(jīng)歷過那些慘痛的重寫事件。當然更主要的原因是,他們掌握了更多應對“垃圾代碼”的方式方法,認為通過小范圍的代碼重構也能化腐朽為神奇,提升項目質量。
的確沒錯,但這是有一個前提的。就是垃圾代碼的產(chǎn)生速度要低于重構的速度。可是對大部分中小公司來說,開發(fā)團隊可能不具備這樣的條件。因為技術好的程序員要么走向了管理崗位,要么身上的重擔太多,沒太多時間來做重構。再加上技術差的程序員繼續(xù)復制粘貼,挖更多的坑。通過重構來改善老項目,可能永遠在“重構的路上”。
而且,如果項目的技術復雜度大于業(yè)務復雜度,那么配合重構的測試成本就很高了。
除了這兩種常見的方式外,還有其它的方式也能應對這些老系統(tǒng)。它們的的風險和收益在下圖里已經(jīng)很好地呈現(xiàn)出來了。
其實Z哥認為,這些方式我們都可以用,但是要沿著正確的思路來。(絞殺是什么?往下看)
首先從業(yè)務角度來考慮到底是選擇哪種方案。
- 從業(yè)務敏捷視角來看,能不能讓響應力變得更快?
- 從運營效率視角來看,如何通過系統(tǒng)改造,提升業(yè)務運營的效率?
- 從客戶洞見視角來看,如何讓系統(tǒng)更好地發(fā)現(xiàn)客戶洞見,進而更好地理解客戶需求和演進產(chǎn)品?
其次是從系統(tǒng)本身來考量,比如,我們想通過改造獲得多大的彈性?
最后,根據(jù)整體上對業(yè)務幫助的價值大小來選擇哪一種方式。如果對業(yè)務的幫助巨大,完全值得投入大量資源去重寫,那么就不要畏畏縮縮的小范圍重構。如果對業(yè)務幫助很小,那么也就別想著重寫了,老老實實在小范圍內修修補補就好了。
當你拿捏不準方案的時候,選擇按模塊替換會是一個不錯的辦法,相當于通過每一次換一個零部件,把整個機器上的零部件全部翻新一遍,以此完成重寫的效果。Martin Fowler 稱之為「絞殺法」。
「絞殺法」的最佳實踐是DDD+微服務,因為它們可以提供更好的「隔離性」「自治性」,更有利于「替換」的進行。
當確定好改造的方案后,還需要制定度量指標,在實施改造的過程中持續(xù)關注這些指標的變化。最好能夠通過可視化工具將這些信息共享出來,這樣的好處有兩點,
- 一是能夠讓團隊了解改造進展和成果,確保改造朝著正確的方向走;
- 二是能夠讓相關的干系人(領導、業(yè)務部門)也能了解到工作的進展情況,提高對預期的確定性,以持續(xù)獲得他們的支持。
關于具體重構方法我就不說了,可以翻看我之前的一篇文章《好的重構方法才能擺脫“屎山”》。
關于重寫可以來聊幾句,之前我們沒聊過。我的建議是遵守以下幾個原則。
系統(tǒng)具備演進的能力。
憑借度量指標來把握演進的方向。
小步快速迭代。
01 系統(tǒng)具備演進的能力
既然是重寫系統(tǒng),那么一定要為可見的未來做一些預留,方便后續(xù)的演進。畢竟能夠決定重寫的系統(tǒng)自然是比較核心的系統(tǒng),不管在技術上還是在業(yè)務上都會持續(xù)發(fā)生變化,注重系統(tǒng)的演進能力就是在降低未來項目復雜度增長的幅度。
具體的方法可以概括為3個詞:抽象、分類(分層)、解耦。
02 憑借度量指標來把握演進的方向
前面也提到了度量指標的價值。這里繼續(xù)強調一下它的重要性。
如果說在重寫時期,度量指標是衡量重寫工作完成好壞的尺子,那么在重寫后它就是指引未來系統(tǒng)演進的明燈。
不管系統(tǒng)后續(xù)要做什么升級改造,對自身了解的越清楚,做出的決定和選擇自然越合理。而度量指標起到的就是這個效果。
一個缺少度量指標的系統(tǒng),隨著業(yè)務邏輯的不斷堆砌,很容易自由生長過了頭。
03 小步快速迭代
近些年隨著CI/CD的普及,小步快跑式的敏捷開發(fā)被越來越多人提到,并且開始運用。
它的好處是顯而易見的,對項目的可控性更高,容錯性更強。
如果你不知道“小步”該多“小”?你就按發(fā)布出了問題能不能快速回滾作為標準去考慮就好了。能快速回滾的迭代節(jié)奏就是“小步”。
其實重寫系統(tǒng)完之后還有一個頭疼的事情要解決,就是數(shù)據(jù)遷移。業(yè)界常用的方案有四種,我先大致列一下主要思路,后續(xù)再發(fā)文展開聊聊。
01 雙寫
- 新庫配置為舊庫的從庫,從舊庫同步數(shù)據(jù)。
- 數(shù)據(jù)寫入的時候,不僅要寫入舊庫,也要寫入新庫。
- 數(shù)據(jù)校驗。
- 兩邊數(shù)據(jù)完全同步后,灰度切流量。
由于有雙寫的存在,所以在切換的過程中出現(xiàn)任何的問題,都可以將讀寫流量隨時切換到舊庫去,安全感極強。
02 異步雙寫+對賬
這個方案其實是雙寫的變種,將同步寫入變成了異步寫入。也因此需要一個對賬機制,確保最終一致性的達成。
一般這個異步的機制要么通過 MQ ,要么通過數(shù)據(jù)庫的 binlog 進行。
03 直接用新庫,數(shù)據(jù)惰性遷移
這個方案中間需要架設一個緩存層,用來存放數(shù)據(jù)的key。過程是這樣的:
- 先訪問新庫,如果有數(shù)據(jù)則直接進入步驟 3 ,如無數(shù)據(jù)進入步驟 2 。
- 訪問舊庫,找到相應的數(shù)據(jù) Insert 到新庫,再進入步驟 3 。
- 進行業(yè)務邏輯的操作……
隨著時間的推移,數(shù)據(jù)慢慢會從舊庫同步到新庫。剩下還未同步的數(shù)據(jù)使用同步工具做一次全量同步。
原則上,以上的每一個方案在實際切流量之前都要對數(shù)據(jù)做核對,確保兩邊的數(shù)據(jù)一致。
最后遷移完后可以通過流量回放工具(如阿里的 jvm-sandbox-repeater )或者全鏈路壓測工具來驗證新版本的系統(tǒng)是否能運行地符合預期。
好了,總結一下。
這篇呢Z哥和你分享了應對老項目的思路,總的有5種:
- 重構
- 重新部署
- 更換平臺
- 重寫
- 絞殺
我建議根據(jù)業(yè)務敏捷、運營效率、客戶洞見、系統(tǒng)本身的韌性和彈性來考慮選擇哪一種。
接下來專門對重寫展開細說了一下,建議遵守三個原則:
- 系統(tǒng)具備演進的能力。
- 憑借度量指標來把握演進的方向。
- 小步快速迭代。
最后分享了3個常用的新老數(shù)據(jù)遷移方案。
- 雙寫
- 異步雙寫+對賬
- 直接用新庫,數(shù)據(jù)惰性遷移