先給你一組數字。
在一個多租戶業務管理系統裡,if ($_SESSION['mOrgID'] == "某機構") 這種硬編碼的機構分支,散落在 661 個檔案、共 2319 處,引用了 240 個不同的機構碼、39 個機構群組。
有一行 if 串了 13 個機構 OR 比對。
這就是「客製化氾濫」——每個客戶要一點不一樣的東西,十年累積下來,整個 codebase 佈滿機構分支。這篇談怎麼用 Claude Code 盤點這種氾濫,以及遷移到新框架時怎麼治理。
客製化長什麼樣子
客製化不是集中在某個 plugin 目錄,而是滲透在每個檔案裡。盤點下來有四種形態:
形態一:行內機構分支(最氾濫)
// 散在 661 個檔案、2319 處
if ($_SESSION['mOrgID'] == "ORG-N1") {
// OrganizationC 要這樣顯示
}
// 最誇張的一行(form1a.php):13 個機構 OR
if ($_SESSION['mOrgID'] == "ORG-N1" || $_SESSION['mOrgID'] == "ORG-N2"
|| $_SESSION['mOrgID'] == "ORG-N3" || ... /* 共 13 個 */) {
// 這些機構共用某個特殊邏輯
}
這是最難維護的形態——機構碼直接寫死在 if 裡,沒有任何抽象。改一個共用邏輯,要 grep 出所有相關的 if 分支。
形態二:機構專屬檔案
form1a.php ← 主版
form1aORG-T1HS.php ← 某機構客製版
form1aforA.php ← 另一個客製版
form46_1_form2_ORG-N2.php ← 帶機構碼的客製檔
export_employee_salary_GRP-003.php ← 帶機構群組碼的匯出
form32_ORG-N3.php
檔名直接帶機構碼/群組碼。好處是客製邏輯隔離、不污染主版;壞處是主版改了,這些客製版常常沒跟上(一致性 checker 就是為了抓這個)。
形態三:系統設定驅動
// 比較好的形態:客製化參數存資料庫,不寫死在 code
$setting = query("SELECT * FROM system_setting WHERE OrgID = ?", [$orgID]);
if ($setting['show_special_field']) { ... }
這是最乾淨的——客製化變成資料,不是程式碼。新機構要客製,改設定就好,不用動 code。
形態四:資源檔按機構命名
title_ORG-N1.png ← 各機構的橫幅圖
title_ORG-N2.png
...(數十個)
連 banner 圖片都按機構碼命名。
用 Claude Code 盤點氾濫程度
那組驚人的數字(661 檔 / 2319 處 / 240 機構)不是用猜的,是讓 Claude Code 掃出來的。盤點的 prompt 大致是:
掃整個 codebase,找出所有 $_SESSION['mOrgID'] == "..." 的硬編碼機構分支。
統計:總共幾處、散在幾個檔案、引用了幾個不同的機構碼。
列出機構分支最多的前 10 個檔案。
Claude Code 用 grep 抓 pattern、去重統計,幾分鐘就給出全貌。這種「跨整個 codebase 的量化盤點」是 AI 的強項——人工 grep + 數,要花一整天還容易漏。
盤點的價值:
- 量化技術債:「2319 處」這個數字讓客製化氾濫從「感覺很亂」變成「可衡量的負債」
- 找出熱點:哪幾個檔案機構分支最多(form1a.php 就是重災區)→ 優先處理
- 遷移評估:遷到 Laravel 時,這 2319 處每一處都要決定怎麼搬
遷移時怎麼治理
把這種系統遷到 Laravel,不能把 2319 處 if 原封不動搬過去——那只是把垃圾搬到新家。治理的方向:
策略一:行內 if → 設定驅動
// Before(Legacy):機構碼寫死
if (in_array($orgID, ["ORG-N1", "ORG-N2", "ORG-N3", /* 13 個 */])) {
showSpecialField();
}
// After(Laravel):抽成設定
// config 或 DB:feature_flags.special_field = [list of orgs]
if (OrgFeature::enabled('special_field', $orgID)) {
showSpecialField();
}
把「哪些機構有這個特殊邏輯」從程式碼裡的 if 變成設定裡的清單。新增機構不用改 code。
策略二:機構專屬檔 → strategy pattern
主版 + N 個客製檔 → 一個 interface + 各機構的 implementation。但這要看客製差異大不大——差異小的合併成設定,差異大的(整個版面不同)才值得獨立 class。
策略三:先盤點,分類,再決定
不是每處 if 都要重構。Claude Code 盤點後,把 2319 處分類:
| 類型 | 處理 |
|---|---|
| 顯示差異(標題、欄位顯隱) | 抽成系統設定 |
| 共用邏輯的機構清單(那 13 個 OR) | 抽成 feature flag 清單 |
| 完全不同的版面 | 保留獨立檔/class |
| 已廢棄機構的分支 | 直接刪 |
最有價值的發現往往是「可以刪的」——240 個機構碼裡,有些機構早就不用了,那些分支是死碼。
Claude Code 的角色
| 任務 | 為什麼適合 AI |
|---|---|
| 盤點:掃 2319 處、統計 240 機構 | 跨 codebase 量化,人工做不來 |
| 分類:哪些是顯示差異、哪些是版面差異 | 讀每處 if 的 context 判斷 |
| 找死碼:哪些機構碼已不再使用 | 比對 orginfo 表 vs code 中的機構碼 |
| 重構:if → 設定驅動 | 規則明確的機械式改寫 |
但有一條 AI 做不了:判斷哪些客製化該保留。客製化反映客戶買單的價值——某個機構要這個特殊欄位,是因為他們的業務真的需要。Claude Code 能告訴你「這裡有 2319 處分支」,但「哪些該砍、哪些是業務命脈」還是要人決定。
給其他人的借鑑
如果你維護多租戶/多客戶系統,客製化遲早會氾濫。幾個建議:
- 定期用 AI 盤點:每季讓 Claude Code 掃一次「客製分支有多少、引用幾個客戶」,把技術債量化
- 新客製優先用設定驅動:能存 DB/config 的就別寫死 if,從源頭減少氾濫
- 找死碼:比對「還在用的客戶」vs「code 裡出現的客戶碼」,砍掉廢棄分支
- 遷移前先盤點分類:別把 if 原封搬到新框架,先分類「該抽設定 / 該獨立 / 該刪」
- 保留判斷權:AI 盤點和重構,但「哪些客製是業務命脈」由人決定
結語
客製化氾濫不是「寫爛了」——是業務成功的副作用。每一處機構分支,背後都是一個付錢的客戶要的東西。十年下來累積成 2319 處,是這個系統養活了很多客戶的證明。
但它確實是負債。治理的第一步是看清楚規模——而「掃 661 個檔案、統計 240 個機構碼」這種事,正是 Claude Code 最擅長的。先量化,再分類,再決定哪些抽設定、哪些刪、哪些保留。
遷移到新框架是難得的治理機會:與其把 2319 處 if 原封搬過去,不如趁這次把「機構碼寫死在 code」變成「客製化是可設定的資料」。下個十年的維護者會感謝你。