From 42659a271a640dd42232acbd2af32d410b794b31 Mon Sep 17 00:00:00 2001 From: OG T Date: Thu, 26 Mar 2026 10:12:43 +0800 Subject: [PATCH] =?UTF-8?q?docs(adr):=20ADR-014=20Dependency=20Governance?= =?UTF-8?q?=20=E4=BE=9D=E8=B3=B4=E6=B2=BB=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 建立前端依賴治理規範文件,.dependency-cruiser.cjs 已參照此 ADR。 內容包含: - Layer Model 四層架構定義 - Feature Isolation 規則說明 - CI 整合配置 (pnpm dep-check) - Severity 分級策略 Co-Authored-By: Claude Opus 4.5 --- docs/adr/ADR-014-dependency-governance.md | 218 ++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 docs/adr/ADR-014-dependency-governance.md diff --git a/docs/adr/ADR-014-dependency-governance.md b/docs/adr/ADR-014-dependency-governance.md new file mode 100644 index 00000000..f4e8ffa7 --- /dev/null +++ b/docs/adr/ADR-014-dependency-governance.md @@ -0,0 +1,218 @@ +# ADR-014: Dependency Governance + +> **狀態**: 已採用 +> **日期**: 2026-03-26 +> **決策者**: CTO + +## 背景 + +AWOOOI 前端專案 (`apps/web`) 隨著功能擴展,元件間的依賴關係日趨複雜: + +1. **Feature 間相互引用**: agent/approval/incident/dashboard 元件互相 import,導致修改一處牽動多處 +2. **分層架構混亂**: ui 層引用 feature 層、hooks 引用 components,違反單向依賴原則 +3. **循環依賴**: A → B → C → A 造成難以追蹤的 bundle 問題 +4. **缺乏自動化檢查**: 僅靠 Code Review 把關,容易遺漏 + +這些問題導致: +- 重構風險高,修改一個元件可能影響多個頁面 +- 測試困難,無法隔離測試單一 feature +- 新人學習曲線陡峭 + +--- + +## 決策 + +採用 **dependency-cruiser** 工具,在 CI 階段自動檢查依賴規則。 + +--- + +## 理由 + +### 為什麼選 dependency-cruiser + +1. **成熟穩定**: npm 週下載量 100K+,持續維護 +2. **規則靈活**: 支援 regex、path match、severity 分級 +3. **CI 友善**: 非零退出碼可阻擋違規 PR +4. **視覺化**: 可產出依賴圖 (dot/svg) +5. **TypeScript 原生支援**: 無需額外配置 + +### 考慮過的替代方案 + +| 方案 | 優點 | 缺點 | +|------|------|------| +| ESLint import/no-restricted-paths | 現有工具鏈 | 規則表達力有限 | +| NX enforce-module-boundaries | 強大 | 需導入 NX 生態系 | +| 手動 Code Review | 零成本 | 不可靠、不可擴展 | + +--- + +## 技術實作 + +### 1. Layer Model (四層架構) + +``` +Layer 0: Pages (app/) +├── 可引用: 所有層 +├── 職責: 路由、佈局、頁面組裝 +│ +Layer 1: Features (components/agent, approval, incident, dashboard) +├── 可引用: Layer 2, Layer 3 +├── 禁止: 互相引用 (agent ↔ approval ↔ incident ↔ dashboard) +├── 職責: 業務邏輯封裝 +│ +Layer 2: Shared (components/shared, layout) +├── 可引用: Layer 3 +├── 禁止: 引用 Layer 1 (下行依賴) +├── 職責: 跨 Feature 共用元件 +│ +Layer 3: Primitives (components/ui, lib/, stores/, hooks/) +├── 可引用: 僅外部套件 +├── 禁止: 引用 components (保持純淨) +├── 職責: 基礎工具、原子元件 +``` + +### 2. 依賴方向 (單向流動) + +``` +Pages (L0) → Features (L1) → Shared (L2) → Primitives (L3) + ↓ 禁止 ↓ 禁止 + 互相引用 反向引用 +``` + +### 3. Feature Isolation 規則 + +每個 Feature 為獨立模組,禁止橫向依賴: + +``` +❌ agent/xxx.tsx → import from 'approval/yyy' +❌ approval/xxx.tsx → import from 'incident/yyy' +❌ incident/xxx.tsx → import from 'dashboard/yyy' + +✅ agent/xxx.tsx → import from 'shared/yyy' +✅ approval/xxx.tsx → import from 'ui/zzz' +``` + +### 4. 配置檔案 (.dependency-cruiser.cjs) + +```javascript +module.exports = { + forbidden: [ + // Feature Isolation (L1 禁止互相引用) + { + name: "feature-isolation-agent", + severity: "error", + from: { path: "apps/web/src/components/agent" }, + to: { path: "apps/web/src/components/(approval|incident|dashboard)" } + }, + // ... 其他 feature 同理 + + // Shared 禁止下行引用 (L2 → L1) + { + name: "shared-no-feature-import", + severity: "error", + from: { path: "apps/web/src/components/shared" }, + to: { path: "apps/web/src/components/(agent|approval|incident|dashboard)" } + }, + + // Primitives 禁止引用 components (L3 保持純淨) + { + name: "hooks-no-component-import", + severity: "warn", + from: { path: "apps/web/src/hooks" }, + to: { path: "apps/web/src/components" } + }, + + // 禁止循環依賴 + { + name: "no-circular", + severity: "error", + from: {}, + to: { circular: true } + }, + + // Components 禁止反向引用 app 層 + { + name: "components-no-app-import", + severity: "error", + from: { path: "apps/web/src/components" }, + to: { path: "apps/web/src/app" } + } + ] +} +``` + +### 5. CI 整合 + +**package.json:** +```json +{ + "scripts": { + "dep-check": "depcruise apps/web/src --config .dependency-cruiser.cjs" + } +} +``` + +**ci.yaml:** +```yaml +- name: Dependency Check + run: pnpm dep-check +``` + +### 6. Severity 分級 + +| Level | 行為 | 使用場景 | +|-------|------|---------| +| `error` | CI 失敗 | Feature Isolation、循環依賴 | +| `warn` | 輸出警告 | L3 引用 components (過渡期) | +| `info` | 僅紀錄 | 監控用 | + +--- + +## 執行方式 + +### Phase 1: 啟用 (本週) + +- [x] `.dependency-cruiser.cjs` 配置完成 +- [x] `pnpm dep-check` script 加入 +- [x] CI workflow 加入 dep-check step +- [x] ADR-014 文件建立 + +### Phase 2: 修復違規 (下週) + +- [ ] 修復現有 Feature Isolation 違規 +- [ ] 修復 Shared → Feature 違規 +- [ ] 警告轉為錯誤 (hooks/stores/lib) + +### Phase 3: 持續維護 + +- [ ] 新 PR 自動檢查 +- [ ] 季度產出依賴圖供架構審查 + +--- + +## 後果 + +### 優點 + +- **架構可維護**: 依賴方向明確,修改影響範圍可預測 +- **自動化檢查**: CI 阻擋違規,不再依賴人工 Review +- **Feature 可獨立開發**: 各 Feature 團隊可平行作業 +- **測試隔離**: 可針對單一 Feature 進行單元測試 + +### 缺點 + +- **初期修復成本**: 需花時間修復現有違規 +- **學習成本**: 開發者需理解 Layer Model + +### 風險 + +- **過度嚴格**: 某些合理的跨 Feature 需求可能被誤擋 + - **緩解**: 使用 `severity: warn` 過渡期,必要時新增白名單 + +--- + +## 參考 + +- [dependency-cruiser 官方文檔](https://github.com/sverweij/dependency-cruiser) +- [Clean Architecture - Dependency Rule](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) +- [NX Module Boundaries](https://nx.dev/core-features/enforce-module-boundaries)