給成熟工程師的決策樹

每個工程團隊最終都會面對同樣戲劇性的一句話。

我們應該直接重寫這套系統。

這句話通常出現在發生 bug、錯過截止日期,或是在閱讀某個看起來像是在停電時寫出來的檔案而感到情緒耗竭的時刻。

重寫感覺乾淨,重構感覺負責任。

前者聽起來英勇,後者聽起來像洗衣服。

但這個決策不是關於情緒,而是關於風險、經濟與時間。

讓我們像大人一樣一步步來討論。


第一個問題

系統是否能運作

不需要完美。不需要優雅。不需要讓你感到驕傲。

只要它能運作。

如果系統穩定、持續產生價值,且客戶每天都依賴它,那你面對的就不是技術問題,而是營收引擎。

重寫營收引擎不是勇敢,而是開刀。

當系統能運作但使用起來痛苦時,選擇重構。

當系統根本無法滿足目前或未來的需求時,選擇重寫。

如果它能運作而你只是討厭它的風格,那就關掉分頁、喝杯水吧。


第二個問題

問題是結構性還是局部性

局部問題指的是醜陋的函式、混亂的模組、過長的檔案、命名不佳、重複的邏輯。

結構性問題則是錯誤的領域模型、破碎的抽象、錯誤的架構邊界、無法滿足的擴展限制。

重構能很好地修復局部問題。

只有當架構本身阻礙進展時,重寫才有正當性。

如果可以逐塊改進而不中斷交付,那就重構。

如果每次小改動都會造成混亂,因為基礎本身就有問題,那你可能需要重寫。

請誠實面對:大多數問題都是局部的。


第三個問題

你是否完全理解目前的系統

這正是大多數重寫專案悄然死亡的原因。

如果目前的系統令人困惑,那種困惑往往包含了無人記錄的商業規則。

遺留程式碼通常是生產事故的化石紀錄。

如果你在尚未完全理解行為的情況下進行重寫,你不會創造出更乾淨的系統,而是一個回歸產生器。

如果答案是否定的,也就是你尚未深入理解,那第一步不是重寫。

第一步是學習。

在學習的同時進行重構。加入測試、記錄行為、縮小不確定性。

只有當你能清楚向他人解釋舊系統時,才考慮重寫。


第四個問題

交付速度是否允許放慢

重寫會消耗專注力。它會創造平行宇宙。你必須同時維護新舊兩套系統。

如果公司無法承受數月內功能交付速度變慢,那重寫只是幻想。

重構允許漸進式進展。你可以在持續出貨的同時改善系統。

如果業務需要動能,那就重構。

如果業務有意投資平台重置,且所有人都理解其成本,那重寫可以是策略性選擇。

但這必須是商業決策,而不是開發者的情緒波動。


第五個問題

測試是否足以保護你

重構仰賴安全網。

如果你沒有有意義的測試,重構會感覺危險,而重寫會顯得誘人。

但這裡有個令人不舒服的事實。

沒有測試的重寫只是在更高的賭桌上賭博。

如果你今天無法自信地修改系統,那你也不會神奇地從零開始重建時變得自信。

先投資於測試。

一旦安全網存在,決策就會變得更清楚。


第六個問題

痛苦是持續增加還是穩定

有些程式碼很醜,但很穩定。它默默完成工作。

其他系統則每季都變得更慢、更難修改、更脆弱。

如果變更成本正在複利增長,那你面對的是架構債。

在這種情況下,持續修補可能比重新開始更昂貴。

如果成本平穩且可預測,通常透過重構逐步改善就足夠了。

請測量變更成本,不要猜測。


實用決策樹

以下是簡化版本。

系統是否能運作並產生價值

那就優先重構

架構是否阻礙關鍵的未來目標

考慮重寫

你是否深入理解目前的行為

先學習並重構

業務是否能容忍交付速度變慢

重構

測試是否足夠強大

在做任何劇烈改變前先強化測試

變更成本是否正在複利增長

重寫可能是策略性選擇

注意到什麼了嗎?

重寫只會在通過數道關卡後才出現。

這是刻意的設計。


情緒陷阱

重寫感覺很有生產力,因為它能立即消除摩擦。

你開啟新資料夾。檔案乾淨。抽象純粹。你感覺自己像建築師,而不是修理工。

但軟體不是一幅畫。它是嵌入現實的不斷演化系統。

舊程式碼曾經歷過生產流量。它包含了保護你免於重蹈覆轍的疤痕組織。

重構尊重那段歷史。

重寫則抹除它。

有時抹除是必要的。但更多時候只是自我。


更健康的模式

與其思考「重構或重寫」,不如用分層思考。

先用測試穩定現有系統。

慢慢抽離邊界。

在介面後方替換模組。

用新元件絞殺舊元件。

久而久之,系統會在沒有戲劇性重寫事件的情況下變成新的。

業務永遠不會感受到重置,工程師也不會凍結進度。

這比較不戲劇化,但也比較不會造成災難。


令人不舒服的結論

大多數團隊並不需要重寫。

他們需要的是紀律。

他們需要測試、更清楚的邊界、更小的 pull request,以及耐心。

重寫是罕見的策略性行動。

重構則是日常工程工作。

如果你發現自己想要重寫,請再問自己最後一個問題。

我是在解決結構性限制
還是試圖逃避自己尚未理解的複雜性?

答案將決定你是正在做工程師該做的事,
還是只是在情緒性地重構自己的感受。