Files
awoooi/docs/adr/ADR-014-dependency-governance.md
OG T 42659a271a docs(adr): ADR-014 Dependency Governance 依賴治理
建立前端依賴治理規範文件,.dependency-cruiser.cjs 已參照此 ADR。

內容包含:
- Layer Model 四層架構定義
- Feature Isolation 規則說明
- CI 整合配置 (pnpm dep-check)
- Severity 分級策略

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-26 10:12:43 +08:00

5.7 KiB
Raw Blame History

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)

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:

{
  "scripts": {
    "dep-check": "depcruise apps/web/src --config .dependency-cruiser.cjs"
  }
}

ci.yaml:

- name: Dependency Check
  run: pnpm dep-check

6. Severity 分級

Level 行為 使用場景
error CI 失敗 Feature Isolation、循環依賴
warn 輸出警告 L3 引用 components (過渡期)
info 僅紀錄 監控用

執行方式

Phase 1: 啟用 (本週)

  • .dependency-cruiser.cjs 配置完成
  • pnpm dep-check script 加入
  • CI workflow 加入 dep-check step
  • ADR-014 文件建立

Phase 2: 修復違規 (下週)

  • 修復現有 Feature Isolation 違規
  • 修復 Shared → Feature 違規
  • 警告轉為錯誤 (hooks/stores/lib)

Phase 3: 持續維護

  • 新 PR 自動檢查
  • 季度產出依賴圖供架構審查

後果

優點

  • 架構可維護: 依賴方向明確,修改影響範圍可預測
  • 自動化檢查: CI 阻擋違規,不再依賴人工 Review
  • Feature 可獨立開發: 各 Feature 團隊可平行作業
  • 測試隔離: 可針對單一 Feature 進行單元測試

缺點

  • 初期修復成本: 需花時間修復現有違規
  • 學習成本: 開發者需理解 Layer Model

風險

  • 過度嚴格: 某些合理的跨 Feature 需求可能被誤擋
    • 緩解: 使用 severity: warn 過渡期,必要時新增白名單

參考