dramaling-vocab-learning/ARCHITECTURE_GOVERNANCE.md

552 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🏛️ DramaLing 架構治理指南
## 🎯 **架構治理目標**
> **核心原則**: 隨著功能增長保持架構清晰,避免技術債務積累
### **治理範圍**
- 🏗️ **架構邊界**: 服務、層次、模組邊界
- 🔗 **依賴管理**: 避免循環依賴和不當耦合
- 📏 **代碼標準**: 統一的編碼規範和模式
- 📊 **品質指標**: 可量化的架構健康度
---
## 🛡️ **架構防護措施**
### **1. 強制性架構規則**
#### **📁 目錄結構規則**
```bash
# ✅ 允許的依賴方向
Controllers → Services/Domain → Services/Infrastructure → Repositories → Data
# ❌ 禁止的依賴
Infrastructure → Domain # 基礎設施不能依賴業務邏輯
Repositories → Services # 數據層不能依賴服務層
Controllers → Repositories # 控制器不能直接訪問數據層
```
#### **🔧 服務命名約定**
```csharp
// ✅ 正確命名
public interface IFlashcardService // I + 業務名 + Service
public class FlashcardService // 業務名 + Service
// ❌ 錯誤命名
public class FlashcardManager // 避免 Manager
public class FlashcardHelper // 避免 Helper
public class FlashcardUtils // 避免 Utils
```
#### **🎯 單一職責驗證**
```csharp
// ✅ 職責清晰
public interface IFlashcardService
{
// 只處理詞卡相關業務邏輯
}
// ❌ 職責混雜
public interface IFlashcardAndUserService
{
// 混合多個業務領域
}
```
### **2. 自動化檢查工具**
#### **依賴分析腳本**
```bash
#!/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"
```
#### **架構測試**
```csharp
// 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 必檢項目**
```markdown
## 🔍 架構審查清單
### 服務設計
- [ ] 服務職責單一且明確
- [ ] 有對應的介面定義
- [ ] 依賴注入正確使用
- [ ] 錯誤處理一致
### 依賴關係
- [ ] 無循環依賴
- [ ] 依賴方向正確 (向上依賴)
- [ ] 無跨層直接依賴
- [ ] 介面隔離原則
### 命名規範
- [ ] 服務命名遵循約定
- [ ] 方法名表達業務意圖
- [ ] 參數和返回類型合理
- [ ] 無魔法數字或字串
### 測試覆蓋
- [ ] 新服務有對應測試
- [ ] 核心業務邏輯有測試
- [ ] 異常情況有測試
- [ ] 測試名稱清晰
```
---
## 📊 **架構健康度指標**
### **可量化指標**
#### **1. 服務複雜度**
```bash
# 服務行數分佈 (理想範圍)
- 小型服務: < 100(70%)
- 中型服務: 100-300 行 (25%)
- 大型服務: > 300(5%)
```
#### **2. 依賴深度**
```bash
# 依賴鏈長度 (理想 < 4 層)
Controller → Service → Repository → DbContext
```
#### **3. 介面覆蓋率**
```bash
# 目標: 90%+ 服務有對應介面
介面覆蓋率 = (介面數量 / 服務數量) × 100%
```
#### **4. 測試覆蓋率**
```bash
# 服務層測試覆蓋率目標
- 單元測試: 80%+
- 集成測試: 60%+
- 端到端測試: 主要業務流程 100%
```
### **定期健康檢查**
#### **每週檢查項目**
```bash
# 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. 新服務創建模板**
#### **服務生成腳本**
```bash
#!/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. 依賴分析工具**
#### **依賴關係可視化**
```python
# 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**
```bash
#!/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 模板**
```markdown
# 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個月)**
```
目標:
- 服務邊界驗證
- 通訊協定定義
- 數據一致性策略
- 部署自動化
```
---
## 🎯 **具體執行方案**
### **📅 每日實踐**
#### **開發者清單**
```markdown
開發新功能前:
- [ ] 確定功能屬於哪個領域 (Learning/Analysis/User)
- [ ] 檢查是否需要新服務或擴展現有服務
- [ ] 設計介面定義 (先介面後實作)
- [ ] 確認依賴關係符合架構原則
提交代碼前:
- [ ] 運行架構檢查腳本
- [ ] 確保新代碼有對應測試
- [ ] 檢查方法複雜度 (< 20行為佳)
- [ ] 驗證命名規範
```
#### **代碼審查要點**
```markdown
審查重點:
- 🎯 **業務邏輯位置**: 是否在正確的服務層?
- 🔗 **依賴方向**: 是否符合分層架構?
- 🧪 **可測試性**: 是否容易寫測試?
- 📏 **複雜度**: 方法是否過於複雜?
- 🏷️ **命名**: 是否表達清晰的業務意圖?
```
### **📊 品質看板**
#### **架構健康度儀表板**
```
🏗️ 架構健康度: 85% ↗️
📦 服務數量: 12 個
🎯 介面覆蓋率: 89% (目標: 90%)
🧪 測試覆蓋率: 73% (目標: 80%)
🔗 依賴違規: 0 個
📏 平均服務大小: 156 行 (良好)
⚠️ 需要關注:
- FlashcardController 過於複雜 (建議重構)
- AudioService 缺少單元測試
```
### **🚨 警報系統**
#### **架構違規警報**
```csharp
// 架構守衛:在 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. **📊 監控指標**: 確保性能沒有退化
### **重構檢查清單**
```markdown
重構前:
- [ ] 當前功能是否有測試覆蓋?
- [ ] 重構範圍是否定義清楚?
- [ ] 是否有回滾計劃?
重構中:
- [ ] 每個小步驟都能編譯通過?
- [ ] 測試是否持續通過?
- [ ] API 介面是否保持兼容?
重構後:
- [ ] 功能是否完全正常?
- [ ] 性能是否符合預期?
- [ ] 文檔是否更新?
```
---
## 📖 **最佳實踐總結**
### **🎯 核心原則**
1. **依賴倒置**: 依賴抽象,不依賴具體
2. **單一職責**: 每個服務只做一件事
3. **介面隔離**: 介面精簡,不強迫依賴不需要的方法
4. **開放封閉**: 對擴展開放,對修改封閉
### **🚀 實踐建議**
1. **先介面後實作**: 設計 API 時優先考慮介面
2. **小步快跑**: 頻繁提交小的改進,避免大重構
3. **測試先行**: 新功能先寫測試,後寫實作
4. **持續監控**: 定期檢查架構健康度
### **⚠️ 常見陷阱**
1. **過度抽象**: 不要為了抽象而抽象
2. **功能漏出**: 業務邏輯洩漏到控制器或基礎設施層
3. **依賴混亂**: 服務間循環依賴
4. **測試缺失**: 重構時沒有足夠的測試保護
---
## 🎓 **團隊執行指南**
### **新成員指導**
1. 📖 閱讀架構文檔
2. 🏗️ 理解分層原則
3. 🧪 學習測試模式
4. 🔧 熟悉開發工具
### **日常維護**
1. **每日**: 代碼審查關注架構原則
2. **每週**: 運行架構健康檢查
3. **每月**: 評估技術債務和重構需求
4. **每季**: 架構演進規劃和調整
---
**記住**: 好的架構不是一蹴而就的,需要持續的關注和維護。這套治理體系將幫助您在功能增長的同時保持代碼品質!