架构原则
软件架构是系统的基石,决定了系统的可维护性、可扩展性和长期演进能力。本章介绍软件架构的核心原则和设计方法。
什么是软件架构
软件架构是系统的高层结构,定义了:
- 组件划分:系统由哪些模块组成,各模块的职责边界
- 交互关系:组件之间如何通信和协作
- 设计决策:关键技术选型和约束条件
- 质量属性:如何满足性能、安全、可维护性等非功能需求
text
┌─────────────────────────────────────────────────────────┐
│ 软件架构层次 │
├─────────────────────────────────────────────────────────┤
│ 业务架构 → 业务流程、领域模型、组织结构 │
│ 应用架构 → 服务划分、接口设计、数据流转 │
│ 技术架构 → 技术选型、中间件、基础设施 │
│ 数据架构 → 数据模型、存储方案、数据治理 │
│ 部署架构 → 部署拓扑、容灾方案、运维体系 │
└─────────────────────────────────────────────────────────┘
```text
架构的核心价值在于:**用合理的成本,构建满足当前需求且易于演进的系统**。
## 核心设计原则
### SOLID 原则
SOLID 是面向对象设计的五大原则,同样适用于架构层面:
| 原则 | 名称 | 核心思想 |
|------|------|----------|
| **S** | 单一职责原则 (SRP) | 一个类/模块只负责一个职责 |
| **O** | 开闭原则 (OCP) | 对扩展开放,对修改关闭 |
| **L** | 里氏替换原则 (LSP) | 子类可以替换父类而不影响程序正确性 |
| **I** | 接口隔离原则 (ISP) | 不应强迫依赖不使用的接口 |
| **D** | 依赖倒置原则 (DIP) | 依赖抽象而非具体实现 |
**单一职责原则应用示例**:
```typescript
// 违反 SRP:一个类处理多个职责
class UserService {
createUser() { /* 用户逻辑 */ }
sendEmail() { /* 邮件逻辑 */ }
generateReport() { /* 报表逻辑 */ }
}
// 遵循 SRP:职责分离
class UserService {
createUser() { /* 用户逻辑 */ }
}
class EmailService {
sendEmail() { /* 邮件逻辑 */ }
}
class ReportService {
generateReport() { /* 报表逻辑 */ }
}
```text
**依赖倒置原则应用示例**:
```typescript
// 违反 DIP:高层模块依赖低层实现
class OrderService {
private mysqlRepository = new MySQLRepository();
saveOrder(order: Order) {
this.mysqlRepository.save(order);
}
}
// 遵循 DIP:依赖抽象接口
interface Repository {
save(entity: Entity): void;
}
class OrderService {
constructor(private repository: Repository) {}
saveOrder(order: Order) {
this.repository.save(order);
}
}
```text
### DRY 原则
**Don't Repeat Yourself** - 不要重复自己。系统中的每个知识点应该有单一、明确的表示。
**重复的类型**:
1. **代码重复**:相同的代码逻辑出现在多处
2. **数据重复**:相同的数据存储在多个地方
3. **逻辑重复**:相同的业务规则在多处实现
4. **文档重复**:相同的信息在多处描述
**消除重复的策略**:
```typescript
// 重复代码
function validateEmail(email: string) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validateUserEmail(email: string) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
// 提取公共逻辑
class Validator {
private static EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
static isValidEmail(email: string): boolean {
return this.EMAIL_REGEX.test(email);
}
}
```text
### KISS 原则
**Keep It Simple, Stupid** - 保持简单。简单性是可靠性的前提。
**简单性的价值**:
- 降低理解和维护成本
- 减少出错的可能性
- 提高开发效率
- 便于团队协作
**过度设计的信号**:
- 为未来可能不会发生的需求预先设计
- 过度抽象导致理解困难
- 引入不必要的复杂性
- 配置项多于实际需求
**保持简单的方法**:
```typescript
// 过度设计
interface IUserFactory {
create(): IUser;
}
interface IUserBuilder {
setName(name: string): IUserBuilder;
setEmail(email: string): IUserBuilder;
build(): IUser;
}
class UserDirector {
constructor(private builder: IUserBuilder) {}
constructDefaultUser(): IUser {
return this.builder.setName('default').setEmail('default@example.com').build();
}
}
// 简单直接
class User {
constructor(
public name: string,
public email: string
) {}
}
const user = new User('John', 'john@example.com');
```text
### 其他重要原则
**YAGNI (You Aren't Gonna Need It)**
不要实现当前不需要的功能。等到真正需要时再实现,可以避免:
- 浪费开发时间
- 增加维护负担
- 引入不必要的复杂性
**高内聚低耦合**
- **高内聚**:模块内部元素紧密相关,共同完成单一功能
- **低耦合**:模块之间依赖关系简单,修改一个模块不影响其他模块
```text
高内聚示例:
┌─────────────────────┐
│ OrderModule │
│ ┌───────────────┐ │
│ │ OrderService │ │ ← 订单相关逻辑集中
│ │ OrderRepository│ │
│ │ OrderValidator│ │
│ └───────────────┘ │
└─────────────────────┘
低耦合示例:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Module A │────→│ Interface│←────│ Module B │
└──────────┘ └──────────┘ └──────────┘
(抽象层解耦)
```text
## 架构决策方法
### 架构决策记录 (ADR)
使用 ADR (Architecture Decision Record) 记录重要的架构决策:
```markdown
# ADR-001: 使用 PostgreSQL 作为主数据库
## 状态
已采纳
## 背景
系统需要存储用户数据和订单数据,要求数据一致性和复杂查询能力。
## 决策
选择 PostgreSQL 作为主数据库。
## 理由
1. 支持 ACID 事务,保证数据一致性
2. 支持 JSON 类型,兼顾灵活性
3. 团队有丰富的 PostgreSQL 经验
4. 开源免费,社区活跃
## 后果
- 需要专门的 DBA 进行运维
- 水平扩展相对复杂
- 需要处理连接池管理
```text
### 决策框架
**1. 明确问题**
- 当前面临的具体问题是什么?
- 问题的紧迫程度如何?
- 不解决会有什么影响?
**2. 收集选项**
- 有哪些可行的解决方案?
- 每个方案的优缺点是什么?
- 行业内最佳实践是什么?
**3. 评估权衡**
```text
评估维度:
┌─────────────┬────────┬────────┬────────┐
│ 维度 │ 方案A │ 方案B │ 方案C │
├─────────────┼────────┼────────┼────────┤
│ 开发成本 │ 中 │ 低 │ 高 │
│ 运维成本 │ 低 │ 高 │ 中 │
│ 性能表现 │ 高 │ 中 │ 高 │
│ 可扩展性 │ 高 │ 低 │ 高 │
│ 团队能力匹配 │ 高 │ 中 │ 低 │
└─────────────┴────────┴────────┴────────┘
```text
**4. 做出决策**
- 选择综合最优的方案
- 记录决策理由
- 制定实施计划
**5. 验证和调整**
- 通过原型验证关键假设
- 收集反馈,必要时调整
## 架构演进策略
### 渐进式演进
避免大规模重写,采用渐进式演进策略:
```text
演进路径:
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ 单体应用 │ → │ 模块化 │ → │ 服务化 │ → │ 微服务 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │ │ │
↓ ↓ ↓ ↓
快速迭代 清晰边界 独立部署 独立扩展
```text
### 绞杀者模式
逐步用新系统替换旧系统:
```text
阶段1:新功能在新系统实现
┌─────────────────────────────────┐
│ 负载均衡器 │
└───────────────┬─────────────────┘
┌───────┴───────┐
↓ ↓
┌───────────────┐ ┌───────────────┐
│ 旧系统 │ │ 新系统 │
│ (核心功能) │ │ (新功能) │
└───────────────┘ └───────────────┘
阶段2:逐步迁移核心功能
┌─────────────────────────────────┐
│ 负载均衡器 │
└───────────────┬─────────────────┘
┌───────┴───────┐
↓ ↓
┌───────────────┐ ┌───────────────┐
│ 旧系统 │ │ 新系统 │
│ (剩余功能) │ │ (已迁移功能) │
└───────────────┘ └───────────────┘
阶段3:完全替换
┌─────────────────────────────────┐
│ 负载均衡器 │
└───────────────┬─────────────────┘
↓
┌───────────────┐
│ 新系统 │
│ (全部功能) │
└───────────────┘
```text
### 演进原则
**1. 小步快跑**
- 每次改动控制在可验证范围内
- 频繁发布,快速反馈
- 出问题可快速回滚
**2. 向后兼容**
- 新版本兼容旧版本
- 提供迁移路径和工具
- 设置合理的过渡期
**3. 监控先行**
- 演进前建立监控体系
- 关键指标持续跟踪
- 异常情况及时告警
**4. 数据优先**
- 数据迁移是最复杂的部分
- 保证数据一致性
- 做好数据备份和恢复方案
## 架构评审清单
在做出架构决策或进行架构评审时,可以使用以下清单:
**功能需求**
- [ ] 是否满足所有功能需求?
- [ ] 是否考虑了边界情况?
- [ ] 是否有明确的错误处理策略?
**非功能需求**
- [ ] 性能:是否满足性能要求?
- [ ] 可扩展性:能否应对业务增长?
- [ ] 可用性:是否有容错和恢复机制?
- [ ] 安全性:是否考虑了安全威胁?
**可维护性**
- [ ] 架构是否清晰易懂?
- [ ] 是否遵循团队编码规范?
- [ ] 是否有完善的文档?
**演进能力**
- [ ] 是否易于添加新功能?
- [ ] 是否易于替换组件?
- [ ] 是否有清晰的演进路径?
**成本效益**
- [ ] 开发成本是否合理?
- [ ] 运维成本是否可控?
- [ ] 是否充分利用现有资源?
## 小结
架构原则不是教条,而是指导思想的集合。在实际项目中:
1. **理解原则背后的目的**,而非机械套用
2. **根据实际情况权衡取舍**,没有放之四海而皆准的方案
3. **保持简单**,避免过度设计
4. **记录决策**,便于团队理解和后续演进
5. **持续演进**,架构是动态的,需要随业务发展而调整
好的架构是演出来的,不是设计出来的。从简单开始,根据实际需求逐步演进,才是务实的做法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390