iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
Modern Web

一個活了六年的 Vue 2 後台,升級到 Vue 3 的那兩年系列 第 13

Day 13|共存期間,舊系統的開發量比新系統還多

  • 分享至 

  • xImage
  •  

模組三|遷移執行法與驗收(Day 12–16)

重構最貴的一段,不是寫新系統,是新舊兩套同時活著的那段日子。我們的共存期超過一年。

而共存期間有一個月,我攤開開發量發現:舊系統的改動比新系統還多。

**這不是失控,是那段時間的必然。**今天講為什麼。

為什麼不能挑一天全部切過去

我們的使用者是外部單位,不是內部同事。

這個差別很大。內部系統你可以發個公告說「下週一換新版」,大家罵歸罵還是得用。但外部單位有自己的作業節奏:他們有月結、有旺季、有自己的教育訓練排程。

你不能挑一個週二早上通知所有人「明天換介面」。

所以我們的做法是分批:先請幾個願意當白老鼠的單位過來,確認沒問題後再一批一批請。而每一批之間要留緩衝,因為前一批的問題要先修完。

這樣做的代價很直接:在最後一個單位切換完成之前,舊系統一天都不能關。

分批切換有三個前提

回頭看,這種切法能成立是因為滿足了三件事,缺一個都會很痛:

一、兩套系統指向同一份資料。 使用者今天在新系統改了設定,明天回舊系統要看得到。如果後端是兩套資料,切換就不是「換介面」,是「搬家」,難度差一個數量級。

二、切換是可逆的。 前幾批一定會遇到問題,而你需要能說「沒關係你先回舊的用,我們修好再請你過來」。如果沒有回頭路,第一批出問題就會讓後面所有人拒絕切換,消息傳得比你修 bug 快。

三、有人負責追進度。 「還有誰沒切」這件事必須有人盯,而且要有名單。否則會出現一種很尷尬的狀況:沒有人知道還剩幾個使用者在舊系統上,所以沒有人敢按關機。

第三點聽起來最不技術,但它是整個共存期唯一會「自己拖下去」的環節。

共存不等於「舊的凍結」

這是我原本以為,後來發現完全不是的部分。

我原本的想像是:新系統上線後,舊系統就進入唯讀維護,只修 P0。實際情況完全不是這樣。

舊系統在共存期還在大量開發新功能

我把四個 repo(新舊各兩套)的月度開發量並排看,發現共存期間有一段時間,舊系統的開發量甚至超過同期的新系統。

原因很簡單,而且事後看很明顯:還沒切換過去的使用者,他們的需求還是要做。

業務不會因為「我們正在重構」就停止提需求。而那些需求提出來的時候,提出者用的還是舊系統。

於是同一個功能要做兩次

同一份東西我得做兩份,還得同一個托盤端出去,少一邊就沒有人要換過來

這帶出共存期最實際的成本:

業務提了一個新報表。

舊系統要做,因為八成的使用者還在那邊。
新系統也要做,因為如果新系統缺功能,沒有人會想切過去。

新功能缺一項,你的切換計畫就多卡一個月。 所以共存期的正確策略是兩邊都做,而且要同時上線,不是「新功能只做新系統」。

版本標記說明了一切

這件事有一個很硬的證據,我是翻版本紀錄時才注意到的。

兩個新專案剛開始各自發版,版號和日期都不一樣,這很正常,兩個獨立的專案本來就有自己的節奏。

但從某個時間點之後,它們完全同步了。 同一個版號、同一天發布,一路持續到共存期結束,中間沒有一次例外。

這代表什麼?代表兩套系統被綁在一起出貨了。

而綁在一起的原因,正是前面那條「新功能一定要兩邊都有」:當你要求功能對齊,你就不可能讓其中一邊先發。發版節奏會自動同步,因為它們已經不是兩個專案,是同一個交付的兩個面。

我覺得這個細節很有意思:組織的協作方式,會誠實地印在版本紀錄上。 你不用問任何人,光看發版時間就能推出「這兩個東西是不是被當成一件事在管」。

我們慢慢摸出來的四條規則

這些規則沒有人一開始就寫下來,是撞了幾次之後才清楚的:

一、已切換的域:新系統為主,舊系統只收 P0。
使用者都過來了,舊系統那份程式碼的剩餘壽命是有限的。

二、未切換的域:舊系統照常開發,但新需求要順手記下來。
因為這個需求等一下搬到新系統的時候還要再做一次,記下來可以少一次考古。

三、跨域的共用改動:先在新系統做對的版本,再回頭 patch 舊系統。
順序很重要。舊系統的改動最終會被丟掉,投資在那裡的心力回收率是零。先在新系統想清楚,舊系統那份就只是「翻譯」。

四、新功能一定要兩邊都有。
違反這條,切換計畫就會停擺。

最痛的一層:技術債會往下游流

前面講的都是前端自己能決定的事。這一段講不能決定的。

舊系統有一個「切換後端」的開關

舊系統為了同時對接兩套後端服務,在建置指令裡放了一個參數。加了這個參數,程式碼裡好幾處會用三元運算切換服務名稱與 API 路徑:

// 大致的形狀
const serviceName = USE_NEW_BACKEND ? 'service-b' : 'service-a'
const url = USE_NEW_BACKEND ? '/admin/order/list' : '/order/list'

這是後端也在遷移、但還沒收斂完成留下的痕跡。前端只能接住它。

而這個相容層跟著搬進了新系統

我原本以為重構會順便把這種東西清掉。沒有。

新系統的代理設定裡,至今仍然掛著四個不同的 API 前綴。因為後端到現在也還沒收斂完。

這件事給我的教訓是:

技術債會沿著介面往下游流。前端重構解決不了後端沒收斂的問題,只能先接住它、並且標記清楚。

「標記清楚」是這裡唯一能做的事,至少讓下一個人知道,那四個前綴不是前端的設計,是接住的東西。

終點不是上線,是關機

名單上大部分都劃掉了,剩下那幾行劃完,我才能把這把鎖扣上

整場重構真正的終點,不是「新系統做完」那天。

舊系統的最後三個月,反而很忙

我去看兩個舊系統的最後一次改動,發現一個違反直覺的形狀。

在關機前的最後兩三個月,舊系統的開發量不但沒有下降,還維持在相當高的水位。

為什麼?因為那是切換前的最後功能對齊:把所有「新系統有、舊系統沒有」和「兩邊行為不一致」的地方一次補平。你不能讓最後一批使用者切過去之後才發現少東西。

然後才是斷崖。其中一套系統在最後一個月的開發量,直接掉到前一個月的十分之一以下,接著就沒有了。

那個斷崖,比任何上線公告都準確地標示了「這件事結束了」。

那一刻才是重構完成。 而它距離「新系統第一次上線」,隔了超過一年。

所以如果有人問你重構的進度,最誠實的指標不是「新系統做了幾成」,是「舊系統還差什麼才能關掉」。

前者會一直看起來很順利,後者才是真的。

代價

一、團隊產出效率在共存期是明顯下降的。 同一個需求做兩次、bug 修兩次、驗收兩次。如果你的主管拿共存期的產出數字去比較,會得到「重構之後效率變差了」的結論,這個要提前打預防針。

二、兩套系統的行為會慢慢分岔。 就算你要求「新功能兩邊都做」,實作的人不同、時間不同,細節就會不一樣。使用者切換過來之後回報「跟舊的不一樣」,你才會發現。這類問題我們遇到不少,而且很難用測試防,因為沒有人寫過舊系統的行為規格。

三、共存期會比你估的長。 我們估的是幾個月,實際超過一年。原因不是技術,是每一批使用者切換都要等他們自己的時間表。

帶走什麼

  1. 共存期是重構真正的成本中心。 估算的時候不要只估「寫新系統要多久」,要估「兩套並行要養多久」。
  2. 共存期的舊系統不會凍結。 沒切換的使用者還是會提需求,而你必須做,否則他們更沒有理由切。
  3. 新功能一定要兩邊同步。 新系統缺功能,切換計畫就會卡住,這是自己卡自己。
  4. 改動的順序有價值差異。 跨域的東西先在新系統做對,再回頭補舊系統;反過來做,等於把心力投在即將被丟掉的程式碼上。
  5. 進度要用「舊系統還差什麼才能關掉」來衡量,不要用「新系統完成幾成」。後者永遠看起來很順利。
  6. 接住上游的技術債時,要留下標記。 你清不掉它,但至少可以讓下一個人知道那不是你的設計。

明天 Day 14 講一件遷移期最爽的事:確認某個模組整批不用搬。我會講三種處置方式,以及「怎麼證明真的沒人用」的三個條件,因為這件事只靠 grep 是不夠的。


上一篇
Day 12|同一個團隊做兩次遷移,第二次用了完全相反的策略
下一篇
Day 14|遷移最爽的一刻,是確認某個模組不用搬
系列文
一個活了六年的 Vue 2 後台,升級到 Vue 3 的那兩年14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言