架构评审与技术债管理
架构不是一次性的设计,而是持续演进的过程。架构评审与技术债管理是保障系统长期健康的关键实践。
1. 架构评审方法
ATAM(Architecture Tradeoff Analysis Method)
卡内基梅隆大学提出的结构化评审方法:
Phase 1: 呈现 ATAM
└─ 介绍方法、业务驱动、架构概览
Phase 2: 调查与分析
└─ 识别架构方法
└─ 生成质量属性效用树
└─ 分析架构方法
Phase 3: 测试
└─ 头脑风暴场景
└─ 分析场景
Phase 4: 报告
└─ 风险、非风险、敏感点、权衡点
效用树(Utility Tree)
质量属性
├── 性能
│ ├── 响应时间(优先级:高)
│ ├── 吞吐量(高)
│ └── 可扩展性(中)
├── 可用性
│ ├── 故障恢复(高)
│ └── 数据持久性(高)
├── 安全性
│ ├── 认证(高)
│ └── 数据加密(中)
└── 可维护性
├── 模块化(中)
└── 可测试性(中)
轻量级架构评审(LARS)
快速评审检查清单:
| 检查项 | 问题 |
|---|---|
| 耦合度 | 模块间是否有循环依赖? |
| 职责 | 每个模块是否有单一明确职责? |
| 可扩展性 | 新增功能需要修改多少现有代码? |
| 依赖 | 外部依赖是否有降级方案? |
| 数据 | 数据一致性与事务边界是否清晰? |
| 安全 | 认证/授权/敏感数据是否处理? |
| 监控 | 关键路径是否可观测? |
2. 技术债管理
技术债类型
┌─────────────────────────────────────┐
│ 谨慎债务(Prudent Debt) │
│ 为了抢占市场,有意识承担 │
├─────────────────────────────────────┤
│ 鲁莽债务(Reckless Debt) │
│ 因无知或懒惰产生 │
└─────────────────────────────────────┘
↓ 按可预见性分类
┌─────────────────────────────────────┐
│ 有意的(Deliberate) │
│ "我们知道有问题,但先上线" │
├─────────────────────────────────────┤
│ 无意的(Inadvertent) │
│ "直到出问题才知道设计错了" │
└─────────────────────────────────────┘
技术债量化
1. SonarQube 技术债比率
技术债时间 / 代码总行数 × 100%
2. 代码变更率
频繁修改的代码 = 高债务区域
3. 缺陷密度
某模块 bug 数 / 代码量
4. 重构 ROI
节省维护时间 / 重构投入时间
技术债看板
## 技术债 Backlog
| 优先级 | 债务项 | 影响 | 偿还成本 | 风险 |
|--------|--------|------|----------|------|
| P0 | 单体核心未拆分 | 无法独立部署 | 6人月 | 业务阻塞 |
| P1 | 缺乏单元测试 | 回归成本高 | 3人月 | 故障频发 |
| P2 | 硬编码配置 | 环境切换困难 | 1人月 | 操作风险 |
偿还策略
| 策略 | 说明 | 场景 |
|---|---|---|
| 持续偿还 | 每次迭代预留 20% 时间 | 日常维护 |
| 集中偿还 | 技术债冲刺(Tech Sprint) | 债务累积过多 |
| 绞杀者模式 | 渐进替换旧系统 | 大型遗留系统 |
| 暂停新功能 | 冻结需求,专注还债 | 债务严重影响交付 |
3. 重构时机与策略
Boy Scout Rule
Always leave the code better than you found it.
每次修改代码时,顺手改善周围代码。
重构触发条件
1. 添加功能困难 → "开闭原则"被破坏,需要抽象
2. Bug 反复出现 → 职责不清,需拆分
3. 代码难以理解 → 命名/结构问题,需简化
4. 重复代码 → 提取公共逻辑
5. 性能瓶颈 → 算法/数据结构优化
安全重构
1. 确保有测试覆盖(重构前补充)
2. 小步提交,每次一个变化
3. 使用 IDE 自动化重构(重命名、提取方法)
4. 持续运行测试验证
5. 代码审查
4. 架构防线
| 防线 | 工具/实践 | 目标 |
|---|---|---|
| 编码规范 | SonarQube, ESLint | 防止低质量代码入库 |
| 单元测试 | JUnit, Jest | 保障模块正确性 |
| 代码审查 | PR Review | 知识共享、问题发现 |
| 架构门禁 | ArchUnit | 防止违反架构约束 |
| 集成测试 | CI Pipeline | 验证组件协作 |
| 性能门禁 | 压测对比 | 防止性能退化 |
| 安全扫描 | Snyk, Trivy | 漏洞拦截 |
ArchUnit 示例
@ArchTest
static final ArchRule no_cycles = slices()
.matching("com.example.(*)..")
.should().beFreeOfCycles();
@ArchTest
static final ArchRule controllers_should_not_access_repo =
noClasses()
.that().resideInAPackage("..controller..")
.should().accessClassesThat()
.resideInAPackage("..repository..");
5. 度量与可视化
架构健康度评分
| 维度 | 权重 | 度量指标 |
|---|---|---|
| 代码质量 | 30% | 技术债比率、圈复杂度 |
| 测试覆盖 | 25% | 行覆盖率、分支覆盖率 |
| 可维护性 | 20% | 重复率、注释率 |
| 性能 | 15% | P99 延迟、错误率 |
| 安全 | 10% | 漏洞数、依赖更新时效 |
总结
| 实践 | 频率 | 目的 |
|---|---|---|
| 轻量级架构评审 | 每次重大设计变更 | 提前发现问题 |
| 技术债盘点 | 每季度 | 识别和规划偿还 |
| Boy Scout 重构 | 每次提交 | 持续改进 |
| 架构防线 | 持续 | 防止退化 |
架构健康的系统不是设计出来的,而是通过持续评审、度量和改进维护出来的。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。