14 KiB
14 KiB
🏛️ 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. 只用分散式快取 - 需要額外基礎設施
重要決策記錄
- ADR-001: 三層快取架構
- ADR-002: Repository Pattern 採用
- ADR-003: 領域驅動服務設計
- 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));
}
}
}
🛠️ 重構安全指南
安全重構步驟
- 📋 評估影響: 列出受影響的組件
- 🧪 增加測試: 確保重構前有足夠測試覆蓋
- 🔄 小步重構: 每次只改變一個小部分
- ✅ 驗證功能: 每步都驗證功能正常
- 📊 監控指標: 確保性能沒有退化
重構檢查清單
重構前:
- [ ] 當前功能是否有測試覆蓋?
- [ ] 重構範圍是否定義清楚?
- [ ] 是否有回滾計劃?
重構中:
- [ ] 每個小步驟都能編譯通過?
- [ ] 測試是否持續通過?
- [ ] API 介面是否保持兼容?
重構後:
- [ ] 功能是否完全正常?
- [ ] 性能是否符合預期?
- [ ] 文檔是否更新?
📖 最佳實踐總結
🎯 核心原則
- 依賴倒置: 依賴抽象,不依賴具體
- 單一職責: 每個服務只做一件事
- 介面隔離: 介面精簡,不強迫依賴不需要的方法
- 開放封閉: 對擴展開放,對修改封閉
🚀 實踐建議
- 先介面後實作: 設計 API 時優先考慮介面
- 小步快跑: 頻繁提交小的改進,避免大重構
- 測試先行: 新功能先寫測試,後寫實作
- 持續監控: 定期檢查架構健康度
⚠️ 常見陷阱
- 過度抽象: 不要為了抽象而抽象
- 功能漏出: 業務邏輯洩漏到控制器或基礎設施層
- 依賴混亂: 服務間循環依賴
- 測試缺失: 重構時沒有足夠的測試保護
🎓 團隊執行指南
新成員指導
- 📖 閱讀架構文檔
- 🏗️ 理解分層原則
- 🧪 學習測試模式
- 🔧 熟悉開發工具
日常維護
- 每日: 代碼審查關注架構原則
- 每週: 運行架構健康檢查
- 每月: 評估技術債務和重構需求
- 每季: 架構演進規劃和調整
記住: 好的架構不是一蹴而就的,需要持續的關注和維護。這套治理體系將幫助您在功能增長的同時保持代碼品質!