我曾經答應自己,從這週開始要改寫一些輕鬆點的主題。結果到了週一,我的 JSNation 之旅正式落幕,而我突然意識到,我竟然還沒寫一篇關於自己演講的文章。既然一切都還歷歷在目,那就開始吧!

至於 JSNation 本身,我的感受有點複雜。我被選進線上場次,雖然主辦方專業得令人驚嘆,但那種感覺終究還是跟親臨現場不同。你知道的,我本來可以在阿姆斯特丹跟 Wes Bos 一起喝啤酒,結果卻是在廚房裡一邊看自己的演講,一邊回 Teams 訊息。😄 不過,這仍然是很棒的體驗。誰知道呢?也許有一天,我的專業能力,或者說我的名氣等級 😅,會成長到讓我有機會親自到阿姆斯特丹演講。

我在研討會上的 20 分鐘成名時刻

話雖如此,我今年晚些時候或許還是會去那座美麗的城市,不過先別說得太早。😉

回到主題。我的演講題目是 「重寫還是重構?如何安全地將舊有應用程式遷移到現代框架」。我相信我是最適合談這個主題的人。為什麼?因為在我的職涯中,我遷移過很多前端應用程式,各種組合都有:舊版 Angular 到現代 Angular、ASP.NET MVC 5 到 Vue、使用 class component 的 React 到現代 React,諸如此類。

原因很簡單。若某家公司急需做遷移,突然收到一份履歷,而那人剛好已經做過一次這種事,通常他們都會非常樂意錄用——即使薪資比市場價高一點。😄 我大致上就是這樣成為前端遷移專家的,所以我對這件事確實有不少話想說。

但為什麼一定要遷移?

在討論策略之前,我們得先回答一個更根本的問題:為什麼一開始就要遷移?

我常常從利害關係人那邊聽到這個問題,特別是非技術背景的產品負責人。既然應用程式能正常運作,為什麼要去動它?開發人員只是追逐潮流、想把新鮮技術寫進履歷,對吧?

我的回答通常很簡單,也很誠實。

你們很了解我。我不是任何特定框架的死忠粉絲。對我來說,它們只是工具,就像槌子一樣。但當我在打造某樣東西時,我寧可用一把結實可靠的槌子,也不想用一把生鏽、零件還缺東缺西的。😉🔨⛏️🪓🔧🪛

不過,遷移不只是開發者體驗的問題。說到底,它關乎你的產品能不能存活。尤其是在今天,技術演進比以往更快,而 AI 又把一切推得更快。

以資安為例。當某個函式庫已經過時,沒人再維護它時,安全性修補就不會再來了。漏洞報告開始一片紅。歷史上沒有任何一位產品負責人會說:「好啊,我們為了多幾個功能,犧牲資安!」至少我希望沒有 😅

也別忘了現代工具鏈。光是 Vite 的建置就能帶來巨大差異。現代應用程式就是比較快,而更快的應用程式就是更好的應用程式。

還有很多其他原因,但最重要的是這一點:

你越晚遷移,遷移就會變得越困難、也越昂貴。

好吧好吧,我想遷移。但要怎麼做?

有趣的是,LLM 的出現並沒有從根本上改變遷移策略。它們跟 AI 還沒普及之前其實差不多。工作有時會變快,有時不會,但底層做法並沒有改變。

遷移策略大概有多少,資深工程師就有多少種說法,但實務上大致可以分成兩類:

重寫(Big Bang 策略)

把整個應用程式全部重寫;或者,在前端領域常見的情況是,直接把一個非常古老的技術堆疊升級到框架的最新版本。

重構(扼殺者模式)

一邊持續交付新功能,一邊逐步把應用程式一塊一塊重寫。

那麼,哪一種比較好?

老實說,沒必要為這件事發動聖戰。大多數情況下,專案的現實條件會替你做決定。

如果你的應用程式相對小、團隊經驗豐富、文件也算完整,而且你能接受暫停幾週或幾個月的新功能開發,那麼重寫可能是完全合理的選擇。

另一方面,如果你面對的是一個龐大專案,團隊裡有很多初階工程師,或是對技術不熟的人,而且文件幾乎不存在——那麼漸進式重構大概就是你唯一實際可行的方案。

當然,還有很多其他因素要考慮。先快速整理如下:

因素 重寫(Big Bang) 重構(扼殺者)
應用程式規模 小型或中型 大型
功能開發 可暫停 必須持續
文件 良好 不佳
團隊經驗 高 混合
風險承受度 較高 較低
首次看到成果的時間 較短 較長
遷移期間的複雜度 較低 較高
遷移永無止境的風險 低 高

Big Bang——沒有聽起來那麼可怕

讓我先簡單介紹這兩種方法,先從 Big Bang 開始。

我得承認——我其實滿喜歡這種策略。沒錯,很多書籍和文章都把它描述成很高風險,有時甚至說它是一種反模式。而且如果我們談的是一個二十年歷史、沒人敢碰的 Java 單體系統,那他們說得沒錯。

但很多前端應用程式其實都還算年輕、規模也不大。在這種情況下,Big Bang 反而可能更快也更便宜。

完整重寫在現在其實已經比較少見。不過,大型升級仍然很常見,例如從 Angular 7 升級到具備 Signals 的現代 Angular,或是從舊版、使用 class component 的 React 升級到使用 hooks 的現代 React。

這些專案仍然需要大量工作,也要花很多時間翻找舊程式碼,但你通常會比扼殺者模式更快抵達終點。

我不打算在這裡細講規劃階段、遷移腳本、codemod,或我實際用過哪些工具。這些細節會因專案而異,放在一篇通用文章裡也不太有意義。

不過,有些事情幾乎在每一次遷移中都會以驚人的一致性出現。😉

真實案例:從 Angular 7 一次性升級到最新版 Angular

這裡有個有趣的例子。有時候我們會想,某個團隊到底怎麼能讓應用程式多年不升級。其實這比想像中容易,尤其當沒有人實際在維護它,因為產品處於維運模式,而且好幾年都沒有太大變化時。

這次的情況就是如此。

後來某一天,利害關係人決定大幅擴充這個應用程式,並新增好幾個功能。我說服他們升級到最新版 Angular,主要是基於資安考量——系統裡存放的是重要資料。

簡單來說,四位開發者花了四個月把它升到最新版本。而且結果比我原先預期的還難很多。

首先,很容易低估問題的範圍。從外面看起來很簡單:「就升級 Angular 而已。」

但真正的問題通常不是框架本身,而是它周邊的生態系。

例如,我們主要的元件函式庫在 12 到 13 版之間引入了重大的語法變更。你可以想像有多少地方需要更新!當然,AI 可以幫忙,但如果某個很有企圖心的 UI 工程師決定改 CSS 類別名稱、改元件結構,AI 也救不了你——最後還是得手動修。

有些第三方函式庫早就停止維護了。這裡有件事值得記住:

如果某個函式庫多年沒更新,作者看起來也早就忘了它的存在,而且它在 Node 18 上甚至已經無法編譯,那它不是「可用的程式碼」,而是一顆定時炸彈。

沒錯,我們也有很多端對端測試。結果其中不少都因為元件函式庫的變更而炸掉了。😄 所以就算是自動化測試,也不一定能救你。

另一個重要教訓是:務必要為熱修補建立穩健的分支策略。先假設事情一定會出錯。因為最後,它大概真的會出錯。

遷移像冰山一樣呈現

幸好,這次遷移成功了。

建置時間大幅改善。打包體積明顯縮小。新版版面也比舊版好看得多,所以連最抗拒技術變動的利害關係人都印象深刻。

而且也許最重要的是,這個應用程式已經為未來升級做好準備。甚至連 QA 團隊——一開始很討厭我們——最後也承認,定期升級遠比每七年才升級一次要好得多 🤣

漸進式遷移——魚與熊掌兼得

不過,有時你的應用程式實在太大,無法採用 Big Bang,或者你根本不能停止交付新功能。在這種情況下,漸進式遷移就成了唯一實際可行的選項。

這種一步一步的重構通常會透過 扼殺者模式 來實作。當然還有其他方法,但我個人很喜歡這個模式,因為它優雅、相對簡單,而且經過世界上幾家最大科技公司的實戰驗證。

那麼,扼殺者模式到底是什麼?

看看下面這張漂亮的圖吧,這是我親自在 draw.io 裡手工做出來的。😄

漂亮的扼殺者模式圖解

如你所見,你一開始先有一個舊有應用程式。然後在旁邊建立一個新應用程式。接著在前面放一個反向代理,由它決定哪些路由要導向哪一個應用程式。

從那裡開始,你就一個畫面一個畫面、一條路由一條路由地遷移。隨著時間過去,舊有應用程式會越來越小,直到最後——希望如此——只剩下新系統,然後你就可以終於把舊應用程式和反向代理都移除掉。

在這種情境下,兩個應用程式應該共用登入驗證和後端,但不要共用前端程式碼。

而且如果你非得讓兩個應用程式互相溝通,我會強烈建議你使用像自訂 DOM 事件這種簡單的方法,而不是所謂的「暫時性」轉接器。

因為我們都知道在軟體工程裡,「暫時性」是什麼意思。永遠。 😅 而且不知不覺間,那些轉接器就會變成全新的舊技術包袱。

真實案例:用扼殺者模式把 Backbone 遷移到 Vue

這是一個很舊的 Backbone 應用程式——我得承認,它其實寫得非常好。不過,它還是 Backbone。😄

這個應用程式不算大,所以理論上 Big Bang 也是可行的。但當時我們是一間新創公司,有一天我們聽到那句著名的話:「各位,我們剛賣出了一個還不存在的功能。你們有三個月的時間交付。祝你們好運!」

我當下的反應是:「哈哈哈,真有趣。要我用 Backbone 做這個,絕對不可能。」 幸好,我們的利害關係人很聰明,最後同意採用扼殺者遷移。

我的團隊只有我,還有……兩位初階 Java 開發者。老實說,我發誓他們應該是人生第一次聽到「TypeScript」這個詞。

幸好他們很有企圖心,也學得很快。嗯,其實他們也沒什麼別的選擇。😄 這也是這種策略的另一個優點:初階開發者可以在過程中學習。

我另外建立了一個新的 Vue 應用程式。公司裡有很多人本來就會 Vue,所以選它很合理。

我先把登入畫面遷移過去,當作概念驗證。接著我們開始處理客戶已經付費購買的那個新功能。😉

接下來的一年,我們就一個畫面一個畫面地把整個應用程式遷移過去。

扼殺者模式像絞殺榕一樣呈現

最後,Backbone 完全消失了。而且在整個過程中,我們完全沒有停機。客戶甚至沒注意到遷移正在發生。

跟前一個例子一樣,打包體積明顯變小,建置時間也大幅改善。

不過,扼殺者模式也不是只有陽光和彩虹。

首先是時間因素。遷移過程會拖很久。在我們這個相對小的應用程式裡,還是整整花了一年。

還有遷移永無止境的風險。你大概知道我在說什麼。截止日期一個接一個。新功能一直進來。過一陣子之後,你甚至會開始半懇求半哀求你的產品負責人,拜託挪幾個 story points 給遷移工作。

而且很遺憾,完全不碰到舊程式碼是不可能的。機率是零。相信我,開發者都討厭這件事。我聽過像這樣的話:「Sylwia,妳為什麼要把事情搞得這麼複雜?現在我們得同時懂兩套技術堆疊!」

所以不管你選哪一種策略,你大概都會變成團隊的替罪羊。至少在遷移進行中的時候是這樣。

但等一切結束、打包體積砍半、漏洞報告不再一片紅、客戶也不再抱怨時,你又會突然變成公司的英雄。😄


最後幾句話

遷移舊有應用程式,很像買一棟老房子。房子快要塌掉不是你的錯,但把它修好就是你的責任。你可以花幾週時間一次全部翻新,也可以先搬進去,再一間一間慢慢整理。

唯一真正糟糕的策略,就是什麼都不做。遲早你還是得遷移——只是到時候,你是因為發生了生產環境事故才被迫遷移。😉

那麼,你會怎麼整理你的舊有應用程式?

免責聲明

以上描述的故事都沒有真的發生。或者有可能真的發生了?😉

身為專業人士,以及一個受 NDA 約束的人,我刻意把多個遷移故事混合在一起,確保不會辨識出任何特定公司或專案。這並不特別困難,因為過了一段時間之後,所有遷移看起來都會驚人地相似。😄


如果你喜歡我的文章,也可以在 LinkedIn 追蹤我。


原文出處:https://dev.to/sylwia-lask/who-here-has-worked-with-legacy-the-longer-you-wait-the-worse-it-gets-58bk


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
boluoji
📝17   💬3   ❤️6
351
🥈
站長阿川
📝5   💬2   ❤️1
213
🥉
mike
1
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登