我们正在深入探讨软件工程中的两个核心环节:系统架构设计和建模设计。这两者紧密相连,但关注点不同。系统架构设计关注高层结构、组件划分、技术选型等;建模设计则更具体,关注系统内部的结构和行为如何用模型表达。
由于之前已经讨论了系统工程、软件工程、架构组织、设计模式、建模语言和UML的关系,现在我们将更具体地聚焦于系统架构设计和建模设计。
一、系统架构设计
系统架构设计是软件工程中的一个关键阶段,它定义了系统的结构、组件、组件之间的关系、以及它们如何协作以满足需求。架构设计的目标是创建一个蓝图,该蓝图可以指导开发团队,并确保系统满足功能和非功能需求(如性能、可扩展性、可靠性等)。
核心机制和原理:
-
分解与抽象:将复杂系统分解为更小、更易管理的部分(模块或组件),并为每个部分提供清晰的抽象。
-
关注点分离:将不同的关注点(如业务逻辑、数据持久化、用户界面)分离到不同的组件中,以提高可维护性和可扩展性。
-
架构风格/模式:使用经过验证的架构风格(如分层架构、微服务架构、事件驱动架构等)作为基础,以解决特定类型的问题。
-
决策权衡:在多个可能的架构方案之间进行权衡,考虑成本、时间、技术、团队技能等因素。
二、建模设计
建模设计是使用模型来表示系统的各个方面,以便于理解、沟通和验证设计。模型可以是结构性的(如类图、组件图),也可以是行为性的(如时序图、状态图)。建模设计通常在架构设计之后,但在具体实现之前进行,它帮助开发团队可视化设计,并发现潜在问题。
核心机制和原理:
-
可视化:通过图形化的方式表示复杂的设计,使抽象概念更具体。
-
多视角:从不同视角(静态结构、动态行为、部署等)建模系统,以全面理解系统。
-
标准化:使用标准化的建模语言(如UML)确保团队成员之间的有效沟通。
-
迭代和细化:模型不是一成不变的,随着需求的变化和设计的深入,模型需要不断迭代和细化。
三、实例:在线支付系统(续)
我们继续使用在线支付系统的例子,来说明系统架构设计和建模设计的具体应用。
- 系统架构设计实例:
假设我们决定采用微服务架构风格,将系统分解为多个服务:
-
用户服务:管理用户信息和认证。
-
账户服务:管理用户账户和余额。
-
支付服务:处理支付交易。
-
风控服务:评估交易风险。
-
通知服务:发送交易通知。
每个服务都是独立的,可以独立开发、部署和扩展。服务之间通过REST API或消息队列进行通信。
架构设计决策:
-
数据管理:每个服务拥有自己的数据库,确保服务之间的松耦合。
-
通信机制:同步通信使用REST,异步通信使用消息队列(如Kafka)。
-
服务发现:使用服务注册与发现机制(如Consul)来管理服务实例。
-
配置管理:使用配置中心(如Spring Cloud Config)统一管理配置。
-
容错:使用熔断器(如Hystrix)防止服务雪崩。
- 建模设计实例:
我们使用UML来建模支付服务的关键部分。
a. 类图:表示支付服务的静态结构。
+----------------+ +----------------+ +----------------+
| Payment | | Payment | | Payment |
| Service | | Controller | | Repository |
+----------------+ +----------------+ +----------------+
| -repo: Payment | | -service: | | +save(): void |
| Repository | | PaymentService| | +findById(): |
+----------------+ +----------------+ | Payment |
| +process(): | | +processPay(): | +----------------+
| PaymentResult| | ResponseEntity|
+----------------+ +----------------+
+----------------+ +----------------+
| Payment | | Payment |
| Processor | | Validator |
+----------------+ +----------------+
| +execute(): | | +validate(): |
| void | | boolean |
+----------------+ +----------------+
b. 时序图:表示支付过程的动态行为。
参与者:用户、支付控制器、支付服务、风控服务、账户服务、通知服务。
步骤:
- 用户提交支付请求。
- 支付控制器接收请求,调用支付服务。
- 支付服务调用风控服务进行风险评估。
- 风控服务返回风险评估结果。
- 支付服务调用账户服务扣款。
- 账户服务返回扣款结果。
- 支付服务更新支付状态,并调用通知服务发送通知。
- 通知服务发送通知给用户。
- 支付服务返回支付结果给支付控制器,最后返回给用户。
c. 组件图:表示支付服务与其他服务的关系。
[支付服务] ---> [风控服务]
| |
| |
v v
[账户服务] [通知服务]
d. 部署图:表示系统如何部署到硬件或云环境。
[Web服务器] ---> [支付服务实例1]
| [支付服务实例2]
| [支付服务实例3]
|
v
[数据库集群] [消息队列集群]
四、概述总结
系统架构设计和建模设计是软件工程中不可或缺的部分。系统架构设计提供了高层次的蓝图,而建模设计则提供了更详细的可视化表示。两者结合,帮助团队构建出符合需求、可维护、可扩展的软件系统。
在实际项目中,架构设计和建模设计往往是迭代进行的。初始的架构设计可能会在建模过程中发现问题,进而调整架构。同时,建模设计也会随着实现的深入而不断细化。
最后,需要注意的是,建模设计不是为了产生大量的文档,而是为了帮助团队沟通和理解。在敏捷开发中,我们提倡“刚刚好”的建模,即建模只要满足当前沟通和设计的需求即可,避免过度设计。
软件工程之系统架构设计与建模设计
下面将深入解析软件工程中的两大核心环节:系统架构设计和建模设计,通过完整的实例展示它们如何协同工作。
一、系统架构设计
1.1 架构设计的层次体系
系统架构设计是一个多层次、多视角的决策过程:
业务架构 → 应用架构 → 数据架构 → 技术架构 → 部署架构
↓ ↓ ↓ ↓ ↓
价值流 功能模块 数据模型 技术选型 基础设施
1.2 架构设计的基本原则
核心原则(以ACID记忆):
- A (Abstraction) - 抽象:隐藏复杂性,暴露必要接口
- C (Cohesion) - 内聚:相关功能集中,无关功能分离
- I (Isolation) - 隔离:故障隔离、变更隔离、安全隔离
- D (Decomposition) - 分解:将大问题拆解为可管理的小问题
1.3 现代架构设计方法论
1.3.1 领域驱动设计
- 战略设计:限界上下文、上下文映射、通用语言
- 战术设计:实体、值对象、聚合、仓储、领域服务
1.3.2 清洁架构
外部接口层 → 应用服务层 → 领域层 → 基础设施层
(控制器) (用例协调) (业务规则) (实现细节)
1.3.3 六边形架构(端口-适配器)
┌─────────────────────┐
│ 应用核心 │
│ (领域模型+用例) │
└─────────┬───────────┘
│
┌─────────┐ ┌────┴────┐ ┌─────────┐
│ 驱动适配 │←──│ 端口 │──→│ 驱动适配 │
│ (HTTP等) │ │ │ │ (DB等) │
└─────────┘ └─────────┘ └─────────┘
1.4 架构决策记录
ADR模板示例:
# ADR 001: 微服务通信机制选择
## 状态
已采纳
## 上下文
系统需要处理高并发支付请求,服务间需要高效通信。
## 决策
采用 **同步REST + 异步事件驱动** 混合模式:
- 关键路径(支付处理)使用gRPC同步调用
- 非关键路径(通知、日志)使用Kafka异步事件
## 后果
**正面**:关键路径低延迟,非关键路径解耦
**负面**:增加技术复杂度,需要维护两种通信机制
二、建模设计
2.1 建模的四个维度
┌─────────────────────────────────────────┐
│ 结构建模 (静态) │
│ • 类图、组件图、部署图、对象图 │
├─────────────────────────────────────────┤
│ 行为建模 (动态) │
│ • 用例图、活动图、状态机图、时序图 │
├─────────────────────────────────────────┤
│ 交互建模 (协作) │
│ • 通信图、交互概览图、时序图 │
├─────────────────────────────────────────┤
│ 约束建模 (规则) │
│ • OCL(对象约束语言)、业务规则 │
└─────────────────────────────────────────┘
2.2 建模驱动的开发流程
2.3 实战:电商订单系统建模
2.3.1 领域模型(类图)
// 领域模型的核心抽象
@AggregateRoot
class Order {
private OrderId id;
private CustomerId customerId;
private List<OrderItem> items;
private OrderStatus status;
private Address shippingAddress;
private PaymentInfo paymentInfo;
public void placeOrder() {
// 领域逻辑:验证库存、计算总额、创建订单
validate();
calculateTotal();
this.status = OrderStatus.CREATED;
DomainEvents.publish(new OrderPlacedEvent(this));
}
public void cancel() {
// 业务规则:只有特定状态的订单可以取消
if (!status.canCancel()) {
throw new IllegalStateException("订单无法取消");
}
this.status = OrderStatus.CANCELLED;
DomainEvents.publish(new OrderCancelledEvent(this));
}
}
@ValueObject
class OrderItem {
private ProductId productId;
private int quantity;
private Money unitPrice;
public Money calculateSubtotal() {
return unitPrice.multiply(quantity);
}
}
2.3.2 用例建模
@startuml
left to right direction
actor 顾客 as Customer
actor 商家 as Merchant
actor 系统管理员 as Admin
rectangle "电商系统" {
usecase "浏览商品" as UC1
usecase "下单购买" as UC2
usecase "支付订单" as UC3
usecase "查看订单状态" as UC4
usecase "取消订单" as UC5
usecase "管理商品库存" as UC6
usecase "处理退款" as UC7
}
Customer --> UC1
Customer --> UC2
Customer --> UC3
Customer --> UC4
Customer --> UC5
Merchant --> UC6
Merchant --> UC7
Admin --> UC6
Admin --> UC7
UC2 .> UC3 : include
UC5 .> UC7 : extend <<如果已支付>>
@enduml
2.3.3 状态机建模
@startuml
state Order {
[*] --> CREATED : 创建订单
CREATED --> PAYMENT_PENDING : 提交订单
PAYMENT_PENDING --> PAID : 支付成功
PAYMENT_PENDING --> CANCELLED : 取消订单
PAID --> PROCESSING : 开始处理
PROCESSING --> SHIPPED : 发货
SHIPPED --> DELIVERED : 签收
PAID --> REFUNDING : 申请退款
REFUNDING --> REFUNDED : 退款完成
REFUNDING --> PAID : 退款驳回
DELIVERED --> COMPLETED : 完成
COMPLETED --> [*]
CANCELLED --> [*]
REFUNDED --> [*]
note right of CREATED
订单已创建但未提交
可修改商品和数量
end note
note right of PAYMENT_PENDING
等待用户支付
15分钟超时自动取消
end note
}
@enduml
2.3.4 时序图:下单流程
@startuml
participant Customer as C
participant "Order Service" as OS
participant "Inventory Service" as IS
participant "Payment Service" as PS
participant "Notification Service" as NS
activate C
C -> OS: 1. 提交订单\n(商品ID, 数量, 地址)
activate OS
OS -> IS: 2. 检查库存\n(商品ID, 数量)
activate IS
IS --> OS: 3. 库存充足
deactivate IS
OS -> OS: 4. 创建订单记录
OS -> PS: 5. 创建支付记录\n(订单ID, 金额)
activate PS
PS --> OS: 6. 支付记录创建成功\n(支付ID)
deactivate PS
OS --> C: 7. 订单创建成功\n跳转到支付页面
deactivate OS
C -> PS: 8. 发起支付\n(支付ID)
activate PS
PS -> PS: 9. 调用第三方支付网关
PS --> C: 10. 支付成功
deactivate PS
PS -> OS: 11. 支付成功事件
activate OS
OS -> OS: 12. 更新订单状态为已支付
OS -> NS: 13. 发送订单确认通知
activate NS
NS --> OS: 14. 通知发送成功
deactivate NS
deactivate OS
@enduml
三、架构设计与建模的协同
3.1 从模型到架构的转换
转换规则示例:
领域模型 → 架构组件
─────────────────────────────────────────
聚合根 (Aggregate Root) → 微服务边界
实体 (Entity) → 服务内部领域对象
值对象 (Value Object) → 不可变DTO
领域服务 (Domain Service) → 应用服务层
仓储接口 (Repository) → 基础设施层实现
领域事件 (Domain Event) → 消息队列事件
3.2 C4模型:完整的架构描述框架
层次1:系统上下文图
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 顾客 │────│ 电商系统 │────│ 支付网关 │
└─────────────┘ └─────────────┘ └─────────────┘
│
│
┌─────────────┐
│ 物流系统 │
└─────────────┘
层次2:容器图(应用架构)
电商系统容器:
- Web应用 (React + Nginx)
- API网关 (Spring Cloud Gateway)
- 订单服务 (Java/Spring Boot)
- 商品服务 (Go)
- 用户服务 (Python/Django)
- 消息队列 (Apache Kafka)
- 数据库集群 (PostgreSQL + Redis)
层次3:组件图(服务内部)
@startuml
package "订单服务" {
[订单控制器] as Controller
[订单应用服务] as AppService
[订单领域服务] as DomainService
[订单聚合] as Aggregate
[订单仓储接口] as RepositoryInterface
[数据库适配器] as DBAdapter
}
Controller -> AppService : 委托请求
AppService -> DomainService : 调用领域逻辑
AppService -> Aggregate : 操作聚合
AppService -> RepositoryInterface : 持久化
RepositoryInterface <- DBAdapter : 实现接口
@enduml
层次4:代码图(类级别)
// 基于组件的代码结构
src/main/java/com/example/orderservice/
├── OrderApplication.java # 应用启动类
├── adapter/ # 适配器层
│ ├── web/ # Web适配器
│ │ ├── OrderController.java
│ │ └── OrderDTO.java
│ └── persistence/ # 持久化适配器
│ ├── OrderRepositoryImpl.java
│ └── OrderJpaEntity.java
├── application/ # 应用服务层
│ ├── OrderApplicationService.java
│ └── PlaceOrderCommand.java
├── domain/ # 领域层
│ ├── model/ # 领域模型
│ │ ├── Order.java
│ │ ├── OrderId.java
│ │ └── OrderItem.java
│ ├── service/ # 领域服务
│ │ └── OrderValidator.java
│ └── event/ # 领域事件
│ └── OrderPlacedEvent.java
└── infrastructure/ # 基础设施层(可选)
└── messaging/ # 消息基础设施
└── KafkaEventPublisher.java
3.3 架构关键决策框架
决策矩阵示例:
| 决策项 | 选项A | 选项B | 选项C | 选择理由 |
|---|---|---|---|---|
| 服务通信 | REST | gRPC | 消息队列 | 选择混合:关键路径gRPC,非关键消息队列 |
| 数据存储 | SQL | NoSQL | 混合 | 选择混合:交易数据SQL,商品缓存NoSQL |
| 部署策略 | 虚拟机 | 容器 | Serverless | 选择容器:平衡控制力和弹性 |
| 监控方案 | 日志中心 | 链路追踪 | 指标监控 | 全选:三位一体的可观测性 |
四、现代架构模式实例
4.1 事件溯源与CQRS架构
// 事件溯源的核心实现
class OrderAggregate {
private List<DomainEvent> changes = new ArrayList<>();
private OrderState state;
public void placeOrder(PlaceOrderCommand command) {
// 1. 业务规则验证
validate(command);
// 2. 生成领域事件
OrderPlacedEvent event = new OrderPlacedEvent(
command.getOrderId(),
command.getItems(),
command.getCustomerId()
);
// 3. 应用事件到当前状态
apply(event);
// 4. 记录未提交的事件
changes.add(event);
}
private void apply(OrderPlacedEvent event) {
// 根据事件重建聚合状态
this.state = OrderState.recreateFrom(event);
}
// 从事件流重建聚合
public static OrderAggregate recreateFrom(List<DomainEvent> events) {
OrderAggregate aggregate = new OrderAggregate();
events.forEach(aggregate::apply);
return aggregate;
}
}
// CQRS:命令端和查询端分离
// 命令端(写模型)
@Service
class OrderCommandService {
public OrderId handle(PlaceOrderCommand command) {
OrderAggregate aggregate = loadAggregate(command.getOrderId());
aggregate.placeOrder(command);
saveAggregate(aggregate); // 保存事件到事件存储
publishEvents(aggregate.getChanges()); // 发布事件
return command.getOrderId();
}
}
// 查询端(读模型)
@Service
class OrderQueryService {
// 专门优化的查询方法
public OrderView getOrderView(OrderId orderId) {
return orderViewRepository.findById(orderId);
}
public List<OrderSummary> searchOrders(OrderSearchCriteria criteria) {
return orderSummaryRepository.search(criteria);
}
}
// 事件处理器:更新读模型
@Component
class OrderViewUpdater {
@EventListener
public void on(OrderPlacedEvent event) {
// 更新物化视图
orderViewRepository.updateFromEvent(event);
orderSummaryRepository.updateFromEvent(event);
}
}
4.2 六边形架构实现
// 端口定义(领域层)
interface OrderRepositoryPort {
Order findById(OrderId id);
void save(Order order);
}
interface PaymentServicePort {
PaymentResult processPayment(PaymentRequest request);
}
interface NotificationPort {
void sendOrderConfirmation(OrderConfirmedEvent event);
}
// 领域层(内部)
@Service
class OrderService {
private final OrderRepositoryPort orderRepository;
private final PaymentServicePort paymentService;
private final NotificationPort notificationPort;
public Order processOrder(OrderRequest request) {
// 1. 创建订单(领域逻辑)
Order order = Order.create(request);
// 2. 持久化
orderRepository.save(order);
// 3. 处理支付(通过端口)
PaymentResult result = paymentService.processPayment(
new PaymentRequest(order.getId(), order.getTotalAmount())
);
if (result.isSuccess()) {
order.confirm();
orderRepository.save(order);
// 4. 发送通知
notificationPort.sendOrderConfirmation(
new OrderConfirmedEvent(order.getId())
);
}
return order;
}
}
// 适配器实现(基础设施层)
@Repository
class OrderRepositoryAdapter implements OrderRepositoryPort {
private final JpaOrderRepository jpaRepository;
@Override
public Order findById(OrderId id) {
OrderEntity entity = jpaRepository.findById(id.getValue())
.orElseThrow(() -> new OrderNotFoundException(id));
return mapToDomain(entity);
}
@Override
public void save(Order order) {
OrderEntity entity = mapToEntity(order);
jpaRepository.save(entity);
}
}
@Component
class PaymentServiceAdapter implements PaymentServicePort {
private final ThirdPartyPaymentClient client;
@Override
public PaymentResult processPayment(PaymentRequest request) {
// 调用第三方支付API
ThirdPartyPaymentResponse response = client.charge(
request.getOrderId().toString(),
request.getAmount()
);
return mapToDomainResult(response);
}
}
// 驱动适配器(Web层)
@RestController
@RequestMapping("/orders")
class OrderController {
private final OrderService orderService;
@PostMapping
public ResponseEntity<OrderResponse> createOrder(@RequestBody CreateOrderRequest request) {
Order order = orderService.processOrder(
mapToDomainRequest(request)
);
return ResponseEntity.ok(mapToResponse(order));
}
}
五、架构质量属性设计
5.1 质量属性场景分析
可伸缩性:
场景: "黑色星期五期间,订单量增长10倍"
刺激源: 大量用户同时下单
环境: 正常运营,促销期间
响应: 系统在5秒内处理请求,成功率>99.9%
架构策略:
- 水平扩展: 自动伸缩订单服务实例
- 缓存: Redis缓存商品信息和库存
- 异步处理: 非关键操作通过消息队列异步处理
可用性:
场景: "数据库主节点故障"
刺激源: 硬件故障
环境: 生产环境,正常工作时间
响应: 30秒内自动切换到备用节点,服务中断<1分钟
架构策略:
- 多活部署: 数据库主从复制,跨可用区部署
- 健康检查: 定期检查服务状态
- 熔断机制: 失败服务快速熔断,防止雪崩
安全性:
场景: "防止支付信息泄露"
刺激源: 恶意攻击者尝试SQL注入
环境: 生产环境
响应: 攻击被阻止,无数据泄露,管理员收到告警
架构策略:
- 输入验证: 所有输入参数严格验证
- 参数化查询: 防止SQL注入
- 加密存储: 敏感数据加密存储
- 审计日志: 记录所有数据访问
5.2 架构权衡分析
# 架构权衡分析的量化示例
class ArchitectureTradeoffAnalyzer:
def analyze(self, requirements):
"""分析不同架构方案在不同质量属性上的表现"""
schemes = {
'monolithic': self._evaluate_monolithic(requirements),
'microservices': self._evaluate_microservices(requirements),
'event_driven': self._evaluate_event_driven(requirements)
}
# 使用加权评分法
weights = {
'performance': 0.3,
'scalability': 0.25,
'maintainability': 0.2,
'reliability': 0.15,
'cost': 0.1
}
scores = {}
for scheme, attributes in schemes.items():
total = sum(attributes[attr] * weights[attr]
for attr in weights)
scores[scheme] = total
return sorted(scores.items(), key=lambda x: x[1], reverse=True)
def _evaluate_microservices(self, req):
return {
'performance': 7, # 网络延迟影响
'scalability': 9, # 独立扩展性好
'maintainability': 8, # 模块清晰
'reliability': 7, # 故障隔离但依赖网络
'cost': 6 # 基础设施成本高
}
六、架构演进与治理
6.1 架构演进策略
6.2 架构治理框架
架构治理委员会:
职责:
- 审批架构决策记录(ADR)
- 评审重大架构变更
- 制定架构标准和规范
- 监督架构合规性
架构原则:
- 标准化原则: 服务接口、错误处理、日志格式标准化
- 自治原则: 服务独立开发、部署、扩展
- 容错原则: 设计时考虑故障,实现优雅降级
- 可观测原则: 所有服务必须提供指标、日志、追踪
技术雷达:
采纳:
- Kubernetes: 容器编排标准
- gRPC: 服务间通信
- GraphQL: 客户端数据查询
试验:
- Service Mesh: Istio
- Serverless: Knative
评估:
- WebAssembly: 边缘计算
淘汰:
- SOAP: 传统Web服务
- EJB: 重量级Java组件
总结
系统架构设计与建模设计是软件工程的两大支柱:
-
架构设计关注 “为什么这样组织” —— 从业务目标、质量属性、技术约束出发,做出高层次的结构性决策。
-
建模设计关注 “如何精确表达” —— 使用标准化的语言和图表,精确描述系统的静态结构和动态行为。
核心实践建议:
- 始于业务,终于价值:架构和建模都是为了支持业务目标
- 演进优于完美:从简单开始,随着复杂度增长逐步演进
- 文档即代码:架构决策、模型图都应该纳入版本控制
- 持续验证:通过原型、度量、用户反馈持续验证架构有效性
- 团队共识:架构决策需要团队理解和认同
架构和建模不是一次性的活动,而是贯穿软件生命周期的持续过程。优秀的软件工程师需要在这两个维度上都具备扎实的能力,才能在复杂系统的设计与构建中游刃有余。

被折叠的 条评论
为什么被折叠?



