Go Adapter Placement via Import Direction¶
概念概覽
核心判斷標準¶
核心知識¶
核心判斷標準¶
adapter 的正確位置由**它依賴誰**決定,而非由它服務誰決定:
- 只依賴 infra/pkg(postgres, redis, luban, S3, config)→ 歸屬該 feature module 自己的目錄
- 依賴其他 feature module → 歸屬
cmd/(composition root),因為只有這層擁有完整依賴圖
為什麼不能把跨模組 adapter 放進 module¶
- 製造 import cycle 風險(A module → B module → A module)
- 單元測試會拉進外部模組的所有依賴,降低隔離性
- 破壞 module 的自包含性
具體案例(MatchRPG_Server)¶
// 應搬進 internal/modules/dungeon/
dungeonGameDataAdapter // 只依賴 luban infra
convertLubanDungeonConfig // helper,同上
convertLubanConditions // helper,同上
// 應搬進 internal/modules/sticker/
pendingStickerGameData // 只依賴 infra
// 留在 cmd/twirpserver/(跨模組)
// 依賴多個 feature module 的 adapter
管理 cmd/ 膨脹的手法¶
按業務領域分檔:adapters_dungeon.go、adapters_reward.go,讓 main.go 只保留 bootstrap 邏輯。
反例與遺留問題¶
sticker 模組現有跨模組 adapter 放在 module 內(歷史不一致),屬於技術債,需獨立 issue 清理,不在本次 main.go 瘦身範圍內。
經驗教訓¶
-
import direction 比「放 cmd/ 還是 module/」更底層,是能在 import cycle 發生前就做出正確決策的思維框架
-
跨模組 adapter 放進 module 的代價在測試時才會顯現(依賴爆炸),但在設計時就應排除
-
歷史不一致的反例(sticker)不應阻止建立新規則,而是另立 issue 逐步對齊
常見陷阱¶
-
以「adapter 服務哪個 module」而非「adapter 依賴哪些 module」決定位置,導致歸類錯誤
-
為保持現有測試通過而不建立新規則,讓技術債持續累積
最佳實踐¶
-
在 PR/設計文件中明文記錄原則:「只依賴 infra/shared pkg 的 adapter 屬於 module;依賴其他 feature module 的 adapter 屬於 composition layer」
-
cmd/ 內跨模組 adapter 用 adapters_
.go 分檔,避免 main.go 膨脹 -
新增 adapter 時先做 import dependency 分析,再決定位置
相關概念¶
- clean-architecture----dangling---
- composition-root----dangling---
- import-cycle-prevention----dangling---
- module-boundary----dangling---
來源 Sessions¶
| 日期 | Session | 貢獻摘要 |
|---|---|---|
| 2026-04-08 | c014ee9c-4558-46a6-9a87-1c574390eeec | 確立以 import direction 為唯一判斷標準的 adapter 定位原則,區分 module-owned vs composition-root adapter。 |