「Repository Pattern 不就是把 SQL 包進一個類別,讓程式碼比較好看嗎?」
如果只看表面,確實像是這樣——資料庫存取邏輯從 Controller 搬進一個叫 XxxRepository 的類別,程式碼是乾淨了一點。但這個系列要問的問題不是「程式碼好不好看」,而是這個分層對 AI 的改動範圍造成了什麼實際影響。Repository 的架構價值,遠遠不只是「把 SQL 包起來」。
裸寫 SQL 有兩個獨立的問題。第一個是「這段 SQL 字串本身安全不安全」——會不會有注入風險、WHERE 子句組得對不對、IN 陣列的 placeholder 有沒有處理好。第二個問題完全不同:如果我要修改「查詢某張表」這件事的邏輯,我要去多少個地方找?
第一個問題可以靠寫得仔細的 SQL 解決,跟有沒有 Repository 無關——一段裸寫但小心組出來的 SQL,一樣可以是安全的。第二個問題,才是 Repository 分層真正在解決的架構問題:它不是讓每一處查詢變得更安全,而是讓「所有查詢同一張表的邏輯」被限制在同一個地方。
這個差異對 AI 重構的意義很直接:AI 修改一段程式碼時,最大的風險不是「這一行寫錯了」,而是「還有別的地方也依賴同一個東西,但 AI 沒看到」。Repository 分層直接把這個風險的搜尋範圍,從「整個程式碼庫」收斂成「一個資料夾」。
❌ 沒有 Repository 分層:
查詢 orders 表的邏輯分散在:
OrderController::index()
OrderController::export()
ReportService::generateDaily()
AdminDashboard::widgets()
每個地方各自組自己的查詢條件、各自處理分頁。
要改「查詢邏輯要排除已刪除的訂單」這條規則,
AI 得先確認自己找到了「所有」查詢 orders 表的地方——
而這件事沒有任何機制強迫它一定找得全。
✅ 有 Repository 分層:
所有查詢 orders 表的邏輯都在 OrderRepository 裡。
要改「排除已刪除的訂單」這條規則,
AI 只需要打開 app/Repositories/OrderRepository.php,
改動範圍是一個檔案,不是整個程式碼庫的搜尋結果。
這正是這個系列要強調的核心:架構不是規範「怎麼寫這段程式碼」,是限制「這個改動能碰到哪裡」。 Repository 分層對 AI 來說,價值不在於它產生的程式碼比較整齊,而在於它把「AI 需要窮舉的搜尋範圍」,從一個沒有邊界的整個程式碼庫,變成一個有明確邊界的資料夾。這件事對人類工程師一樣重要,但對 AI 尤其關鍵——因為 AI 沒有工程師那種「這段邏輯我上次改過,我記得散落在哪裡」的長期記憶,它每次面對的都是一個需要重新搜尋的程式碼庫。
需要澄清一件事:Repository 分層本身不會自動讓程式碼變安全——你還是可以在 Repository 內部寫出有問題的查詢邏輯。它解決的不是「這段程式碼對不對」,而是「當它不對的時候,影響範圍有多大、要花多少力氣才能找齊所有受影響的地方」。 一個有清楚邊界的錯誤,永遠比一個沒有邊界、散落各處的錯誤更容易被發現、被修正。
這也是為什麼「有沒有 Repository 分層」跟「SQL 寫得安不安全」該分開來看——後者是程式碼品質問題,前者是架構問題。一個專案可以兩者都做對,也可能只做對其中一項;把兩者混為一談,會讓人誤以為「加了 Repository 就代表資料存取安全了」,但那其實是兩件不同的事,各自需要各自的紀律去把關。
回想你手上的專案:如果現在要改一條跟某張核心資料表相關的業務規則,你有把握「一次就找齊所有受影響的地方」嗎?如果沒有把握,這個不確定性,是資料庫查詢本身的問題,還是查詢邏輯散落各處、沒有邊界收斂的問題?
明天要往下一層看:當 Repository 內部的方法簽章,型別提示的是一個具體類別、還是一個介面,這個選擇本身其實是一個架構決策,不只是語法細節而已。