dramaling-vocab-learning/note/done/ARCHITECTURE_GOVERNANCE.md

14 KiB
Raw Blame History

🏛️ DramaLing 架構治理指南

🎯 架構治理目標

核心原則: 隨著功能增長保持架構清晰,避免技術債務積累

治理範圍

  • 🏗️ 架構邊界: 服務、層次、模組邊界
  • 🔗 依賴管理: 避免循環依賴和不當耦合
  • 📏 代碼標準: 統一的編碼規範和模式
  • 📊 品質指標: 可量化的架構健康度

🛡️ 架構防護措施

1. 強制性架構規則

📁 目錄結構規則

# ✅ 允許的依賴方向
Controllers → Services/Domain → Services/Infrastructure → Repositories → Data

# ❌ 禁止的依賴
Infrastructure → Domain  # 基礎設施不能依賴業務邏輯
Repositories → Services  # 數據層不能依賴服務層
Controllers → Repositories # 控制器不能直接訪問數據層

🔧 服務命名約定

// ✅ 正確命名
public interface IFlashcardService    // I + 業務名 + Service
public class FlashcardService         // 業務名 + Service

// ❌ 錯誤命名
public class FlashcardManager         // 避免 Manager
public class FlashcardHelper          // 避免 Helper
public class FlashcardUtils           // 避免 Utils

🎯 單一職責驗證

// ✅ 職責清晰
public interface IFlashcardService
{
    // 只處理詞卡相關業務邏輯
}

// ❌ 職責混雜
public interface IFlashcardAndUserService
{
    // 混合多個業務領域
}

2. 自動化檢查工具

依賴分析腳本

#!/bin/bash
# architecture-check.sh

echo "🔍 檢查架構規則..."

# 檢查循環依賴
echo "檢查循環依賴..."
find . -name "*.cs" -exec grep -l "using.*Services" {} \; | \
grep -E "(Repositories|Data)" && echo "❌ 發現不當依賴" || echo "✅ 依賴方向正確"

# 檢查過大的服務
echo "檢查服務大小..."
find Services -name "*.cs" -exec wc -l {} + | \
awk '$1 > 300 {print "⚠️ " $2 " 超過300行考慮拆分"}'

# 檢查介面覆蓋率
echo "檢查介面覆蓋率..."
SERVICE_FILES=$(find Services -name "*Service.cs" | wc -l)
INTERFACE_FILES=$(find Services -name "I*Service.cs" | wc -l)
echo "服務介面覆蓋率: $INTERFACE_FILES/$SERVICE_FILES"

架構測試

// Tests/Architecture/ArchitectureTests.cs
[Test]
public void Services_Should_Not_Depend_On_Repositories()
{
    var assembly = typeof(Program).Assembly;
    var serviceTypes = assembly.GetTypes()
        .Where(t => t.Namespace?.Contains("Services") == true)
        .Where(t => !t.Namespace?.Contains("Infrastructure") == true);

    foreach (var serviceType in serviceTypes)
    {
        var dependencies = serviceType.GetConstructors()
            .SelectMany(c => c.GetParameters())
            .Select(p => p.ParameterType);

        var hasBadDependency = dependencies.Any(d =>
            d.Namespace?.Contains("Repositories") == true);

        Assert.IsFalse(hasBadDependency,
            $"Service {serviceType.Name} should not depend on Repository directly");
    }
}

3. 代碼審查清單

每次 PR 必檢項目

## 🔍 架構審查清單

### 服務設計
- [ ] 服務職責單一且明確
- [ ] 有對應的介面定義
- [ ] 依賴注入正確使用
- [ ] 錯誤處理一致

### 依賴關係
- [ ] 無循環依賴
- [ ] 依賴方向正確 (向上依賴)
- [ ] 無跨層直接依賴
- [ ] 介面隔離原則

### 命名規範
- [ ] 服務命名遵循約定
- [ ] 方法名表達業務意圖
- [ ] 參數和返回類型合理
- [ ] 無魔法數字或字串

### 測試覆蓋
- [ ] 新服務有對應測試
- [ ] 核心業務邏輯有測試
- [ ] 異常情況有測試
- [ ] 測試名稱清晰

📊 架構健康度指標

可量化指標

1. 服務複雜度

# 服務行數分佈 (理想範圍)
- 小型服務: < 100(70%)
- 中型服務: 100-300 行 (25%)
- 大型服務: > 300(5%)

2. 依賴深度

# 依賴鏈長度 (理想 < 4 層)
Controller → Service → Repository → DbContext

3. 介面覆蓋率

# 目標: 90%+ 服務有對應介面
介面覆蓋率 = (介面數量 / 服務數量) × 100%

4. 測試覆蓋率

# 服務層測試覆蓋率目標
- 單元測試: 80%+
- 集成測試: 60%+
- 端到端測試: 主要業務流程 100%

定期健康檢查

每週檢查項目

# weekly-architecture-check.sh
#!/bin/bash

echo "📊 週架構健康檢查 - $(date)"
echo "=================================="

# 1. 代碼複雜度
echo "1. 代碼複雜度分析"
find Services -name "*.cs" -exec wc -l {} + | \
awk '{total+=$1; count++} END {print "平均服務大小:", int(total/count), "行"}'

# 2. 依賴關係檢查
echo "2. 依賴關係檢查"
./scripts/check-dependencies.sh

# 3. 測試覆蓋率
echo "3. 測試覆蓋率"
dotnet test --collect:"XPlat Code Coverage" --logger:console

# 4. 性能指標
echo "4. 快取效能檢查"
curl -s http://localhost:5008/api/ai/stats | jq '.data.cacheHitRate'

echo "=================================="

🔧 實用工具和腳本

1. 新服務創建模板

服務生成腳本

#!/bin/bash
# create-service.sh

SERVICE_NAME=$1
DOMAIN=$2

if [ -z "$SERVICE_NAME" ] || [ -z "$DOMAIN" ]; then
    echo "用法: ./create-service.sh FlashcardService Learning"
    exit 1
fi

# 創建介面
cat > "Services/Domain/$DOMAIN/I${SERVICE_NAME}.cs" << EOF
namespace DramaLing.Api.Services.Domain.${DOMAIN};

/// <summary>
/// ${SERVICE_NAME} 服務介面
/// </summary>
public interface I${SERVICE_NAME}
{
    // TODO: 定義業務方法
}
EOF

# 創建實作
cat > "Services/Domain/$DOMAIN/${SERVICE_NAME}.cs" << EOF
namespace DramaLing.Api.Services.Domain.${DOMAIN};

/// <summary>
/// ${SERVICE_NAME} 服務實作
/// </summary>
public class ${SERVICE_NAME} : I${SERVICE_NAME}
{
    private readonly ILogger<${SERVICE_NAME}> _logger;

    public ${SERVICE_NAME}(ILogger<${SERVICE_NAME}> logger)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    // TODO: 實作業務方法
}
EOF

echo "✅ 服務 $SERVICE_NAME 已在 $DOMAIN 領域創建"

2. 依賴分析工具

依賴關係可視化

# dependency-analyzer.py
import os
import re
from graphviz import Digraph

def analyze_dependencies():
    """分析服務依賴關係並生成視覺化圖表"""

    dependencies = {}

    # 掃描所有 C# 文件
    for root, dirs, files in os.walk("Services"):
        for file in files:
            if file.endswith(".cs"):
                with open(os.path.join(root, file), 'r') as f:
                    content = f.read()

                # 提取依賴關係
                service_name = file.replace(".cs", "")
                deps = re.findall(r'private readonly I(\w+Service)', content)
                dependencies[service_name] = deps

    # 生成依賴圖
    dot = Digraph(comment='Service Dependencies')

    for service, deps in dependencies.items():
        dot.node(service)
        for dep in deps:
            dot.edge(service, dep)

    dot.render('architecture/service-dependencies', format='png')
    print("✅ 依賴關係圖已生成: architecture/service-dependencies.png")

if __name__ == "__main__":
    analyze_dependencies()

3. 代碼品質守衛

Git Pre-commit Hook

#!/bin/bash
# .git/hooks/pre-commit

echo "🔍 執行架構檢查..."

# 檢查是否有 TODO 標記
if git diff --cached --name-only | xargs grep -l "TODO.*:" > /dev/null; then
    echo "⚠️ 發現 TODO 標記,請確認是否應該完成"
    git diff --cached --name-only | xargs grep -n "TODO.*:"
fi

# 檢查服務大小
LARGE_FILES=$(git diff --cached --name-only | grep "Service\.cs$" | xargs wc -l | awk '$1 > 300 {print $2}')
if [ ! -z "$LARGE_FILES" ]; then
    echo "❌ 以下服務文件過大 (>300行),請考慮拆分:"
    echo "$LARGE_FILES"
    exit 1
fi

# 檢查命名規範
INVALID_NAMES=$(git diff --cached --name-only | grep -E "(Helper|Utils|Manager)\.cs$")
if [ ! -z "$INVALID_NAMES" ]; then
    echo "❌ 發現不符規範的命名:"
    echo "$INVALID_NAMES"
    echo "建議使用 Service 後綴"
    exit 1
fi

echo "✅ 架構檢查通過"

📚 架構決策記錄 (ADR)

ADR 模板

# ADR-001: 採用三層快取架構

## 狀態
已接受 (2025-09-23)

## 背景
需要降低 AI API 調用成本,提升響應速度

## 決策
採用三層快取架構Memory → Distributed → Database

## 後果
- ✅ 大幅提升性能 (57,200倍)
- ✅ 降低運營成本 (67%)
- ⚠️ 增加系統複雜度
- ⚠️ 快取一致性需要管理

## 替代方案
1. 單層快取 - 性能提升有限
2. 只用分散式快取 - 需要額外基礎設施

重要決策記錄

  1. ADR-001: 三層快取架構
  2. ADR-002: Repository Pattern 採用
  3. ADR-003: 領域驅動服務設計
  4. ADR-004: AI 提供商抽象層

🚦 架構演進策略

Phase 1: 穩定基礎 (當前)

  • 核心架構模式確立
  • 服務邊界定義
  • 快取系統整合
  • 🔄 測試框架建立

Phase 2: 品質提升 (1-2週)

目標:
- 80%+ 服務有介面
- 80%+ 測試覆蓋率
- 架構檢查自動化
- 依賴關係可視化

Phase 3: 監控和治理 (1個月)

目標:
- 實時架構監控
- 技術債務追蹤
- 自動化品質閥門
- 性能基準監控

Phase 4: 微服務準備 (3個月)

目標:
- 服務邊界驗證
- 通訊協定定義
- 數據一致性策略
- 部署自動化

🎯 具體執行方案

📅 每日實踐

開發者清單

開發新功能前:
- [ ] 確定功能屬於哪個領域 (Learning/Analysis/User)
- [ ] 檢查是否需要新服務或擴展現有服務
- [ ] 設計介面定義 (先介面後實作)
- [ ] 確認依賴關係符合架構原則

提交代碼前:
- [ ] 運行架構檢查腳本
- [ ] 確保新代碼有對應測試
- [ ] 檢查方法複雜度 (< 20行為佳)
- [ ] 驗證命名規範

代碼審查要點

審查重點:
- 🎯 **業務邏輯位置**: 是否在正確的服務層?
- 🔗 **依賴方向**: 是否符合分層架構?
- 🧪 **可測試性**: 是否容易寫測試?
- 📏 **複雜度**: 方法是否過於複雜?
- 🏷️ **命名**: 是否表達清晰的業務意圖?

📊 品質看板

架構健康度儀表板

🏗️ 架構健康度: 85% ↗️

📦 服務數量: 12 個
🎯 介面覆蓋率: 89% (目標: 90%)
🧪 測試覆蓋率: 73% (目標: 80%)
🔗 依賴違規: 0 個
📏 平均服務大小: 156 行 (良好)

⚠️ 需要關注:
- FlashcardController 過於複雜 (建議重構)
- AudioService 缺少單元測試

🚨 警報系統

架構違規警報

// 架構守衛:在 CI/CD 中執行
public class ArchitectureGuard
{
    [Test]
    public void Architecture_Should_Follow_Rules()
    {
        var violations = new List<string>();

        // 檢查服務大小
        CheckServiceSize(violations);

        // 檢查依賴方向
        CheckDependencyDirection(violations);

        // 檢查命名規範
        CheckNamingConvention(violations);

        if (violations.Any())
        {
            Assert.Fail("架構違規:\n" + string.Join("\n", violations));
        }
    }
}

🛠️ 重構安全指南

安全重構步驟

  1. 📋 評估影響: 列出受影響的組件
  2. 🧪 增加測試: 確保重構前有足夠測試覆蓋
  3. 🔄 小步重構: 每次只改變一個小部分
  4. 驗證功能: 每步都驗證功能正常
  5. 📊 監控指標: 確保性能沒有退化

重構檢查清單

重構前:
- [ ] 當前功能是否有測試覆蓋?
- [ ] 重構範圍是否定義清楚?
- [ ] 是否有回滾計劃?

重構中:
- [ ] 每個小步驟都能編譯通過?
- [ ] 測試是否持續通過?
- [ ] API 介面是否保持兼容?

重構後:
- [ ] 功能是否完全正常?
- [ ] 性能是否符合預期?
- [ ] 文檔是否更新?

📖 最佳實踐總結

🎯 核心原則

  1. 依賴倒置: 依賴抽象,不依賴具體
  2. 單一職責: 每個服務只做一件事
  3. 介面隔離: 介面精簡,不強迫依賴不需要的方法
  4. 開放封閉: 對擴展開放,對修改封閉

🚀 實踐建議

  1. 先介面後實作: 設計 API 時優先考慮介面
  2. 小步快跑: 頻繁提交小的改進,避免大重構
  3. 測試先行: 新功能先寫測試,後寫實作
  4. 持續監控: 定期檢查架構健康度

⚠️ 常見陷阱

  1. 過度抽象: 不要為了抽象而抽象
  2. 功能漏出: 業務邏輯洩漏到控制器或基礎設施層
  3. 依賴混亂: 服務間循環依賴
  4. 測試缺失: 重構時沒有足夠的測試保護

🎓 團隊執行指南

新成員指導

  1. 📖 閱讀架構文檔
  2. 🏗️ 理解分層原則
  3. 🧪 學習測試模式
  4. 🔧 熟悉開發工具

日常維護

  1. 每日: 代碼審查關注架構原則
  2. 每週: 運行架構健康檢查
  3. 每月: 評估技術債務和重構需求
  4. 每季: 架構演進規劃和調整

記住: 好的架構不是一蹴而就的,需要持續的關注和維護。這套治理體系將幫助您在功能增長的同時保持代碼品質!