iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0
AI Engineering

AI 寫 Code 之後,我們還需要 Software Architecture 嗎?系列 第 25 篇

Day 25:案例——清楚的介面邊界如何讓一次大範圍重構變得可控

  • 分享至 

  • xImage
  •  

前言:同一種「大範圍換底層實作」,這次結果完全不同

前面用過不只一次「邊界不清楚時,一次改動會波及意外的地方」這類反面案例。今天反過來,用一個正面案例,看清楚的介面邊界替一次「大範圍替換底層實作」的重構,實際上省下了什麼。

今日目標

  • 看一個具體案例:全站幾十處呼叫端,替換底層一個第三方套件時如何保持可控
  • 理解「呼叫端只依賴介面」這件事,在大範圍重構時具體換來什麼
  • 認識「逐一替換、逐一驗證」這種漸進式做法為什麼可行
  • 建立判斷「這次重構風不風險,看的是依賴介面還是依賴具體實作」的習慣

案例:換掉一個用了很久的快取套件

情境是這樣:系統裡有一個快取層,全站有幾十處程式碼會呼叫它——存資料、取資料、清除某個 key。這個快取層底層原本包著一個第三方套件,套件停止維護了,團隊決定換成另一個功能相近、但 API 完全不同的套件。

這種「換掉一個被廣泛使用的底層套件」的重構,聽起來就是那種容易牽一髮動全身的高風險工作。但這次的情況不太一樣:幾十處呼叫端,全部呼叫的都是同一個內部定義的快取介面(例如 get(key)、set(key, value, ttl)、forget(key) 這幾個方法),沒有任何一處呼叫端直接引用底層套件的類別或方法。

為什麼這次不用窮舉「還有沒有漏掉的地方」

在之前的案例裡(沒有清楚邊界的情境),AI 最頭痛的問題是「這個改動的影響範圍到底有多大,我沒辦法窮舉」。這次完全不用面對這個問題:只要確認「所有呼叫端都經過同一個介面」這個前提成立,剩下要做的事就收斂成一件——把介面底下的實作換掉,呼叫端完全不用動。

驗證這個前提本身也很直接:在程式碼庫裡搜尋底層套件的類別名稱,如果只有快取層內部的一個檔案引用到它,前提就成立;如果搜出散落在其他地方的直接引用,那些地方要先處理掉,才能真正安全替換。

用一組對照來看這個差異:

❌ 沒有統一介面,呼叫端各自直接依賴套件:
// 呼叫端 A
$cache = new LegacyCacheClient($config);
$cache->fetch($key);

// 呼叫端 B(另一個模組,直接 new 了另一份實例)
$client = new LegacyCacheClient($otherConfig);
$client->fetch($key);
→ 要換套件,得先靠 grep 找出全部直接引用的地方,
  還要擔心有沒有漏掉、有沒有隱藏在動態呼叫裡的地方

✅ 呼叫端只依賴內部定義的介面:
interface Cache
{
    public function get(string $key): mixed;
    public function set(string $key, mixed $value, int $ttl): void;
    public function forget(string $key): void;
}

// 呼叫端只知道 Cache 介面,不知道底層是什麼套件
class OrderService
{
    public function __construct(private Cache $cache) {}
}
→ 換底層套件只需要改一個實作類別,
  呼叫端的程式碼一行都不用動,也不用逐一排查

介面邊界的價值在這裡具體展現出來:它把「要不要窮舉所有呼叫端」這個問題,變成「只要確認邊界本身乾不乾淨」這個更小的問題。 前者的工作量隨呼叫端數量線性成長,後者是一次性的、跟呼叫端數量無關的檢查。

漸進式替換:不用一次全部換完

因為呼叫端只認介面、不認底層實作,這次重構還多了一個選項:可以讓新舊兩個實作短暫並存,用某種開關(例如一個設定值)決定當下用哪個實作,逐步把流量從舊套件切到新套件,隨時可以切回去。這種漸進式做法在「呼叫端直接依賴具體套件」的情境下幾乎不可行——因為切換的單位會被迫是「全部呼叫端」,沒辦法切一部分。

這正是這個系列反覆講的模式的另一個面貌:AI(或任何人)敢不敢對一個大範圍改動有信心,取決於它需要承擔的查證範圍有多大——介面邊界不是讓查證變得不必要,而是把查證範圍收斂到一個可以被完整檢查的邊界內。

今日思考題

回想你手上系統裡有沒有一個被廣泛使用的底層元件(快取、日誌、外部 API client):如果今天要換掉它的底層實作,你有把握列出所有呼叫端嗎,還是得靠一次一次的 grep 慢慢找?

今日重點回顧

  • 呼叫端只依賴內部定義的介面時,替換底層實作只需要改一個地方,呼叫端完全不用動
  • 「這次重構風不風險」的判斷依據,是呼叫端依賴的是介面還是具體實作
  • 介面邊界讓「窮舉所有呼叫端」這種隨規模線性成長的工作,收斂成「檢查邊界本身乾不乾淨」的一次性工作
  • 邊界乾淨時,大範圍重構可以做成漸進式、可回退的過程,而不是一次到位的賭注

明日預告

明天要看依賴方向規則被忽略時的真實教訓——一次「看起來方便」的捷徑,事後付出了什麼代價。


上一篇
Day 24:案例——架構邊界不清楚時,AI 修好一個 bug 卻引入另一個
下一篇
Day 26:案例——忽略依賴方向規則的教訓,一次「看起來方便」的捷徑
系列文
AI 寫 Code 之後,我們還需要 Software Architecture 嗎? 共 26 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言