架构分析器技能
概述
架构决定了系统是否可维护、可扩展和可测试。糟糕的架构会隐藏问题直到它们失控,需要大规模重写。在复杂性失控前分析架构。
核心原则: 尽早修复架构问题。修复成本会随时间递增。忽视架构问题会导致成本失控。
何时使用
始终:
- 审查新系统设计
- 重构遗留代码
- 规划重大变更
- 重大重构前
- 当代码变得难以理解时
触发短语:
- "这个设计好吗?"
- "找出架构问题"
- "应该如何组织?"
- "识别耦合问题"
- "改进可维护性"
- "规划重构"
架构分析器功能
组件分析
- 识别组件 - 控制器、服务、仓库、模型等
- 检查职责 - 每个组件做一件事?
- 评估内聚性 - 相关功能是否聚集在一起?
- 评估边界 - 模块边界是否清晰?
依赖分析
- 映射依赖 - 谁依赖谁?
- 发现循环 - 循环依赖?
- 检查方向 - 依赖指向正确方向?
- 测量耦合 - 代码耦合程度?
设计模式分析
- 识别模式 - 使用了哪些设计模式?
- 发现反模式 - 犯了哪些设计错误?
- 检查一致性 - 模式应用是否一致?
- 建议改进 - 如何改进设计?
质量指标
- 复杂度 - 每个组件的复杂程度
- 可测试性 - 是否容易测试?
- 可维护性 - 是否容易修改?
- 可扩展性 - 能否无需重写地增长?
常见架构问题
紧耦合
问题:
- Order服务依赖User服务
- User服务依赖Order服务
- 无法独立测试
- 一个地方的改动影响另一个
后果:
- 开发缓慢(改动连锁反应)
- 测试困难(需要两个服务)
- 无法复用(循环依赖)
上帝对象
问题:
- UserService处理用户、订单、支付、通知(1500行)
- 功能太多
- 难以理解
- 难以修改
后果:
- 测试困难(需要所有依赖)
- 理解困难(逻辑太多)
- 维护困难(处处都要改)
缺少抽象
问题:
- Controller直接查询数据库
- 没有Repository层
- 数据库逻辑与请求处理混合
- 无法脱离数据库测试
后果:
- 测试困难(依赖数据库)
- 数据库变更困难(处处都要改)
- 模拟困难(紧耦合)
循环依赖
问题:
A依赖B
B依赖C
C依赖A(循环!)
后果:
- 无法独立加载模块
- 无法独立测试
- 无法提取复用
验证检查清单
架构质量:
- 每个组件有单一职责
- 组件边界清晰
- 无循环依赖
- 依赖指向正确方向(低层→高层)
- 组件间无紧耦合
- 外部依赖注入(非硬编码)
- 容易独立测试
- 容易理解结构
- 无法解释架构?说明不清晰
如果无法检查所有项: 重构。提取职责。减少耦合。
如何分析架构
第1步:映射组件
app/
├── controllers/ # 请求处理
│ ├── user-controller.js
│ ├── order-controller.js
├── services/ # 业务逻辑
│ ├── user-service.js
│ ├── order-service.js
├── repositories/ # 数据访问
│ ├── user-repo.js
│ ├── order-repo.js
├── models/ # 数据结构
│ ├── user.js
│ ├── order.js
└── utils/ # 工具函数
第2步:识别依赖
- 每个组件是否只依赖下层?
- 依赖是注入还是硬编码?
- 有循环依赖吗?
第3步:评估设计
- 单一职责?(每个做一件事)
- 能独立测试?(依赖可模拟)
- 容易理解?(结构清晰)
- 容易修改?(改动局部化)
第4步:规划重构
- 应该提取什么?
- 应该合并什么?
- 哪些依赖应该反转?
设计模式使用
好模式(使用这些)
- 依赖注入 - 松耦合
- Repository模式 - 分离数据访问
- 服务层 - 业务逻辑隔离
- Observer模式 - 事件处理
- Factory模式 - 对象创建
反模式(避免这些)
- 循环依赖 - 难以测试/使用
- 上帝对象 - 职责过多
- 紧耦合 - 无法独立测试
- 硬编码依赖 - 无法测试
- 缺少抽象 - 实现暴露
遇到困难时
| 问题 | 解决方案 |
|---|---|
| "依赖太多" | 提取职责。创建中间组件。 |
| "无法独立测试" | 依赖紧耦合。使用依赖注入。 |
| "循环依赖" | 打破循环。提取共享功能。 |
| "一个文件行数太多" | 组件职责过多。拆分它们。 |
| "结构难理解" | 边界不清晰。重命名组件。添加文档。 |
反模式(红旗警告)
❌ 万物互依赖
- 服务间相互依赖
- Controller有业务逻辑
- Service直接访问数据库
❌ 上帝对象
- 单个类做多件事
- 数百或数千行代码
- 难以命名(使用"Manager"、"Helper")
❌ 紧耦合
- 无法脱离整个系统测试
- 改动影响各处
- 依赖硬编码,非注入
❌ 无分层
- Controller直接访问数据库
- 业务逻辑到处混合
- 无清晰的关注点分离
❌ 循环依赖
- 无法独立加载模块
- 难以理解数据流
- 难以测试
红旗警告 - 停止并重构
- 组件职责过多
- 模块间循环依赖
- 无法脱离模拟测试
- 无法简单解释架构
- 一处改动影响多处
- "上帝对象"(类做得太多)
- 依赖方向不清晰
- 缺少抽象层
- 以上所有问题:重构。从提取职责开始。
例子:好架构 vs 坏架构
坏架构
UserController直接调用数据库
↓
测试困难(需要数据库)
数据库变更困难(处处都要改)
复用困难(耦合)
理解困难(逻辑混合)
好架构
UserController
↓
UserService(注入)
↓
UserRepository(注入)
↓
数据库
优势:
✓ 容易测试(注入模拟对象)
✓ 容易变更数据库(一处修改)
✓ 容易复用(关注点分离)
✓ 容易理解(层次清晰)
相关技能
- 代码审查 - 审查架构决策
- 依赖分析器 - 发现不必要的依赖
- 安全扫描器 - 检查架构安全
- Git分析 - 理解架构演进