de_DEen_USes_ESfa_IRfr_FRhi_INid_IDjapl_PLpt_PTru_RUvizh_CNzh_TW

最小有效 UML:软件系统建模实用指南

UML 在改善沟通与决策时最为有用,而非沦为文档编写的练习。团队通常并不需要所有类型的 UML 图。在大多数项目中,七种图类型即可构成坚实的基础:

信息图展示了七种核心 UML 图表类型:用例图、活动图、序列图、类图、组件图、部署图和状态机图。

  1. 用例图

  2. 活动图

  3. 序列图

  4. 类图

  5. 组件图

  6. 部署图

  7. 状态机图

这些图共同从互补的视角描述系统:

七种 UML 图表类型,分别展示软件系统的不同视角:目标、行为、交互、结构、架构、操作和生命周期。

  • 目标:用户和外部系统的需求

  • 行为:工作如何在系统中流转

  • 交互:对象与服务如何协作

  • 结构:存在哪些实体与关系

  • 架构:主要软件部分如何组织

  • 运行:系统运行在何处

  • 生命周期:重要对象如何随时间演变

目标并非为每个可能的关注点创建一张图,而是构建最小且连贯的模型集合,以回答利益相关者真正关心的问题。

1. “最小有效 UML”的含义

最小有效 UML 是一种基于四项原则的建模策略:

  • 为决策而建模:创建图表是因为它能澄清需求、设计选择、风险或实现细节。

  • 使用最简单且足够的表示法:避免不必要的符号、装饰和细节。

  • 保持可追溯性:在可行的情况下,将需求与行为、结构、代码、测试和部署相连接。

  • 保持图表的可理解性:包含一切内容的图表往往无法传达任何信息。

有用的模型应有助于回答以下问题:

  • 谁与系统交互?

  • 系统必须提供哪些功能?

  • 哪些步骤构成了业务流程?

  • 哪个对象或服务负责每个操作?

  • 必须表示哪些数据和领域概念?

  • 子系统如何划分?

  • 应用程序、数据库和外部服务部署在何处?

  • 重要实体如何在其生命周期中转换?

如果某个图表无助于回答其中任何一个问题,则可能没有必要。

2. 七图核心

图表 核心问题 主要受众 典型项目阶段
用例 谁需要从系统中获得什么? 客户、分析师、产品负责人 需求
活动 工作流程如何? 分析师、设计师、开发人员、测试人员 需求与流程设计
序列 参与者如何随时间协作? 开发人员、架构师、测试人员 详细设计
类 存在哪些概念、数据和关系? 开发人员、分析师、架构师 领域与软件设计
组件 系统如何划分为主要部分? 架构师、开发人员、运维团队 架构
部署 软件运行在何处? 架构师、DevOps、运维、安全团队 部署与运维
状态机 实体如何随时间变化? 开发人员、分析师、测试人员 生命周期设计

这些图表并非独立存在。它们构成一个链条:

 

用例  ⟶  活动  ⟶  序列  ⟶  类与组件  ⟶  部署

 

状态机图通过描述具有有意义状态的对象的生命周期,贯穿整个链条。

例如,在线订单可以表示如下:

  • 用例:下订单

  • 活动:验证购物车、授权支付、预留库存、确认订单

  • 序列:客户界面调用订单服务、支付服务和库存服务

  • 类: 订单, 订单项, 支付、和 产品

  • 组件:Web 应用、订单服务、支付适配器、库存服务

  • 部署:浏览器、应用集群、数据库、支付提供商

  • 状态机:草稿 → 待支付 → 已支付 → 已发货 → 已送达

3. 用例图:定义系统目标

用例图从外部展示系统。它识别与系统交互的参与者及其追求的目标。

3.1 用例图包含的内容

主要元素包括:

图表展示了六种核心 UML 用例元素:系统边界、参与者、用例、关联、包含关系和扩展关系。

  • 系统边界:定义被建模系统内部的内容

  • 参与者:人员、组织、设备或外部系统

  • 用例:系统提供的目标或服务

  • 关联:参与者与用例之间的连接

  • 包含关系:另一个用例所需的可复用行为

  • 扩展关系:可选或条件性行为

示例:

VPasCode 界面显示了一个在线商店的 UML 用例图,展示了参与者和系统交互。

@startuml
从左到右方向

actor Customer
actor "Payment Provider" as PaymentProvider
actor "Warehouse System" as Warehouse

rectangle "Online Store" {
  usecase "Browse Products" as UC1
  usecase "Place Order" as UC2
  usecase "Authorize Payment" as UC3
  usecase "Fulfill Order" as UC4
}

Customer --> UC1
Customer --> UC2
UC2 ..> UC3 : <<include>>
PaymentProvider --> UC3
Warehouse --> UC4
@enduml

3.2 正确识别参与者

参与者不一定是人类角色。它是任何与系统交互的外部实体。

可能的参与者包括:

  • 客户

  • 支持代理

  • 管理员

  • 支付网关

  • 身份提供商

  • 仓库管理系统

  • 计划任务

  • 移动应用程序

  • 物联网设备

避免根据内部实现细节来命名参与者。“REST 控制器”通常不是参与者。“合作伙伴应用程序”可能是一个参与者。

3.3 将用例命名为目标

良好的用例名称应描述结果:

  • 提交费用报告

  • 批准采购请求

  • 注册新患者

  • 生成发票

  • 重置密码

薄弱的名称描述的是实现机制:

  • 调用 API

  • 运行 SQL 查询

  • 打开表单

  • 调用控制器

一个用例应回答:

参与者希望借助系统实现什么有意义的结果?

3.4 何时使用包含和扩展

使用<<include>>当一个行为总是作为另一个行为的一部分而被需要时。

例如:

  • “下订单”包含“计算总额”

  • “注册账户”包含“验证电子邮件”

使用<<extend>>当行为是可选的或条件性的时。

例如:

  • “下订单”可能被“应用促销折扣”所扩展

  • “登录”可能被“完成多因素认证”所扩展

不要仅仅为了使图表看起来更复杂而使用这些关系。通常,简短的书面场景或活动图更清晰。

3.5 用例图不显示的内容

用例图不用于描述:

  • 详细的用户界面布局

  • 具体的实现类

  • 数据库表

  • 消息顺序

  • 算法逻辑

  • 基础设施拓扑

它们定义范围和目标。其他图表提供细节。

4. 活动图:建模工作流和流程

活动图展示工作如何推进。它们在业务流程、工作流、分支逻辑、并行工作和异常处理方面尤为有效。

4.1 核心元素

活动图通常使用:

  • 初始节点

  • 动作

  • 决策节点

  • 合并节点

  • 分叉与汇合

  • 泳道

  • 终止节点

  • 守卫条件,例如[已批准]或[已拒绝]

示例:

VPasCode 工具显示了订单流程的 PlantUML 代码,以及生成的带有泳道和决策节点的活动图。

@startuml
|客户|
start
:提交订单;

|订单服务|
:验证订单;

if (订单有效?) then (是)
  :计算总额;

  fork
    |支付服务|
    :授权支付;
  fork again
    |库存服务|
    :预留库存;
  end fork

  |订单服务|
  :确认订单;
  stop
else (否)
  :返回验证错误;
  stop
endif
@enduml

4.2 使用泳道展示职责

泳道可明确说明每个动作由哪个角色、系统或组件执行。

有用的泳道可能代表:

  • 客户

  • 客户服务代表

  • 订单服务

  • 支付提供商

  • 仓库

  • 自动调度器

当流程跨越组织或系统边界时,泳道尤其有价值。

4.3 显式建模决策

决策应包含有意义的守卫条件:

[支付已批准]
[支付已拒绝]

避免使用模糊的标签,例如:

[是]
[否]

除非决策问题本身显而易见。

4.4 在必要时展示并行性

当活动并发执行时,分叉和汇合很有用。例如,在订单验证之后:

  • 可能进行支付授权

  • 可能预留库存

  • 可能执行欺诈检查

然而,仅在并行性影响时序、一致性、故障处理或系统设计时才进行建模。不要仅仅为了使图表更复杂而使用并行分支。

4.5 活动图与需求

活动图可以揭示缺失的需求。例如,在建模审批流程时,团队可能会发现一些尚未回答的问题:

  • 如果审批人不可用会发生什么?

  • 请求是否可以被拒绝并重新提交?

  • 升级时限是多少?

  • 是否可以由两人同时审批?

  • 如果下游系统不可用会发生什么?

这使得活动图在实施开始之前非常有用。

5. 序列图:解释随时间推移的协作

序列图展示了参与者在按时间顺序的交互中如何交换消息。它们非常适合详细描述重要场景。

5.1 主要元素

序列图通常包括:

  • 参与者

  • 对象或服务

  • 生命线

  • 消息

  • 返回消息

  • 激活条

  • 条件

  • 循环

  • 替代路径

  • 异步消息

示例:

VPasCode 界面显示了一个订单系统的 UML 序列图,展示了客户、Web 应用和数据库之间的交互。

@startuml
actor Customer
boundary "Web App" as Web
control "Order Service" as Order
control "Payment Service" as Payment
database "Order DB" as DB

Customer -> Web : 提交订单
Web -> Order : createOrder(cart)

Order -> DB : save(order)
DB --> Order : orderId

Order -> Payment : authorize(amount)

alt 支付已批准
  Payment --> Order : approved
  Order -> DB : updateStatus(PAID)
  Order --> Web : confirmation
  Web --> Customer : 显示确认
else 支付被拒绝
  Payment --> Order : declined
  Order -> DB : updateStatus(PAYMENT_FAILED)
  Order --> Web : payment error
  Web --> Customer : 显示错误
end
@enduml

5.2 战略性地选择场景

不要为每个用例都创建序列图。从以下场景开始:

  • 业务关键型

  • 技术风险型

  • 集成密集型

  • 安全敏感型

  • 交易型

  • 难以理解

  • 可能暴露架构问题

典型示例包括:

  • 用户认证

  • 支付处理

  • 文件上传

  • 订单提交

  • 密码重置

  • 事件发布

  • 故障恢复

  • 后台作业执行

5.3 区分同步和异步交互

同步调用意味着发送方等待响应。异步消息允许发送方继续执行。

这种区别会影响:

  • 用户体验

  • 事务边界

  • 错误处理

  • 可扩展性

  • 重试行为

  • 可观测性

始终如一地使用不同的符号,并在注释或附注中解释重要的异步行为。

5.4 建模故障路径

仅显示成功路径的序列图可能会掩盖重大的设计风险。请使用alt, opt、和loop片段来展示:

  • 验证失败

  • 授权失败

  • 超时

  • 重试

  • 部分失败

  • 重复请求

  • 服务不可用

  • 补偿或回滚

例如:

VPasCode PlantUML 序列图展示了客户端、API 和服务之间的交互,其中包含用于超时和重试失败路径的嵌套 alt 块。

@startuml
客户端 -> API : 提交请求

API -> 服务 : 处理请求

alt 服务响应
  服务 --> API : 结果
  API --> 客户端 : 成功
else 超时
  API -> 服务 : 重试请求
  alt 重试成功
    服务 --> API : 结果
    API --> 客户端 : 成功
  else 重试失败
    API --> 客户端 : 临时失败
  end
end
@enduml

5.5 避免过于详细的序列图

当序列图包含每个内部方法调用时,它将变得难以维护。应关注有意义的职责和边界:

  • 用户界面

  • 应用服务

  • 领域对象

  • 仓储

  • 外部服务

  • 消息代理

  • 数据库

详细的实现图在调试期间可能有用,但不应成为主要的架构文档。

6. 类图:描述结构和领域概念

类图展示静态结构。它们可以描述以下任一内容:

  • 概念领域模型

  • 设计级对象模型

  • 面向实现的类结构

这些是不同的抽象层次,不应随意混用。

6.1 概念类图与实现类图

概念模型可能包含:

  • 客户

  • 订单

  • 产品

  • 支付

实现模型可能包含:

  • 订单控制器

  • 订单应用服务

  • 订单仓储

  • 支付网关适配器

两者都是有效的,但它们回答的是不同的问题。

6.2 核心关系

常见关系包括:

  • 关联

  • 聚合

  • 组合

  • 泛化

  • 依赖

  • 实现

请谨慎使用关系。在许多情况下,简单的关联比在聚合与组合之间进行复杂的区分更为清晰。

示例:

VPasCode 界面显示客户、订单和产品类的 PlantUML 代码及其渲染后的类图。

@startuml
class Customer {
  +id: CustomerId
  +name: String
  +email: EmailAddress
}

class Order {
  +id: OrderId
  +status: OrderStatus
  +total(): Money
  +submit()
}

class OrderLine {
  +quantity: int
  +unitPrice: Money
  +lineTotal(): Money
}

class Product {
  +sku: String
  +name: String
}

Customer "1" -- "0..*" Order : places
Order "1" *-- "1..*" OrderLine : contains
OrderLine "*" --> "1" Product : refers to
@enduml

6.3 多重性很重要

多重性用于表达约束:

  • 1 — 恰好一个

  • 0..1 — 可选

  • * — 多个

  • 1..* — 一个或多个

例如:

客户 "1" -- "0..*" 订单

表示每个订单属于一个客户,而一个客户可能拥有零个或多个订单。

6.4 建模职责,而不仅仅是数据字段

类图应有助于说明行为归属何处。具有有意义操作的领域对象通常比仅包含 getter 和 setter 的类集合更具信息量。

例如:

Order.submit()
Order.cancel()
Order.calculateTotal()
Payment.authorize()

具体操作取决于设计方法,但原则是一致的:

将重要的业务职责靠近拥有它们的概念放置。

6.5 避免将类图变成数据库模式

类图并不自动等同于关系模式。除非目的是专门进行持久化设计,否则不要添加所有数据库列。

一个有用的区分是:

  • 领域模型:业务概念和规则

  • 设计模型:软件类及其职责

  • 数据模型:表、键、索引和约束

它们可能相互关联,但不应混淆。

7. 组件图:展示架构边界

组件图描述系统中主要的可替换或可部署部分,以及它们交互的接口。

它们有助于回答以下问题:

  • 主要子系统有哪些?

  • 哪个组件负责某项职责?

  • 每个组件提供什么?

  • 每个组件需要什么?

  • 集成边界在哪里?

  • 哪些依赖是稳定的,哪些是高风险的?

示例:

VPasCode 工具显示 PlantUML 代码,并附带生成的组件图,展示用户设备、云区域和支付提供商之间的交互。

@startuml
component "Web Application" as Web
component "Order Service" as Order
component "Payment Adapter" as Payment
component "Inventory Service" as Inventory
database "Order Database" as DB
cloud "External Payment Provider" as Provider

Web --> Order : REST API
Order --> Payment : Payment interface
Order --> Inventory : Inventory API
Order --> DB : Persistence
Payment --> Provider : Provider API
@enduml

7.1 组件图不是包图

包图将模型元素分组,通常用于组织。组件图描述提供和消耗功能的架构单元。

组件可能是:

  • 一个可部署的服务

  • 一个 Web 应用程序

  • 一个移动应用程序

  • 一个库

  • 一个消息代理

  • 一个外部平台

  • 一个数据库

  • 一个第三方集成

合适的抽象层级取决于架构。

7.2 在能明确契约关系时显示接口

接口使依赖关系更加明确:

VPasCode 界面图显示订单服务依赖于由支付适配器实现的支付网关接口。

@startuml
接口 PaymentGateway

组件“订单服务”作为 Order
组件“支付适配器”作为 Adapter

Order ..> PaymentGateway
Adapter - PaymentGateway
@enduml

这表明订单服务依赖于抽象而非特定提供者。

7.3 使用组件图支持架构决策

当组件图与简短的设计说明配合使用时,其价值会更高:

  • 为何存在此边界?

  • 谁拥有数据?

  • 交互是同步的还是异步的?

  • 当依赖失败时会发生什么?

  • 该组件是否可以独立部署?

  • 它代表什么安全边界?

  • 存在哪些一致性保证?

该图无需包含所有答案,但应引导人们关注重要问题。

8. 部署图:将软件与基础设施连接

部署图展示了软件制品执行的物理或虚拟环境。

它们有助于回答:

  • 每个应用程序运行在哪里?

  • 哪些节点之间进行通信?

  • 数据库位于何处?

  • 哪些服务对外部可访问?

  • 存在哪些网络边界?

  • 系统是如何分布的?

  • 哪些基础设施选择会影响可靠性或性能?

示例:

VPasCode 界面显示 PlantUML 代码及其渲染后的部署图,展示用户设备、云层级和外部服务。

@startuml
节点 "用户设备" 作为 Device {
  构件 "浏览器" 作为 Browser
}

节点 "云区域" 作为 Cloud {
  节点 "Web 层" 作为 WebTier {
    构件 "Web 应用程序" 作为 WebApp
  }

  节点 "应用层" 作为 AppTier {
    构件 "订单服务" 作为 OrderSvc
    构件 "支付适配器" 作为 PaymentSvc
  }

  数据库 "订单数据库" 作为 DB
}

云 "支付提供商" 作为 Provider

Browser --> WebApp : HTTPS
WebApp --> OrderSvc : HTTPS
OrderSvc --> DB : TLS
OrderSvc --> PaymentSvc
PaymentSvc --> Provider : HTTPS
@enduml

8.1 区分节点、构件和环境

  • 一个 节点是执行环境,例如服务器、容器、设备、虚拟机或托管平台。

  • 一个 构件是可部署的软件单元,例如二进制文件、容器镜像、软件包或应用程序。

  • 一个 环境可表示开发、测试、预发布或生产环境。

8.2 包含运营上重要的细节

根据目的不同,部署图可能显示:

  • 负载均衡器

  • 防火墙

  • 网络区域

  • 容器集群

  • 可用区

  • 数据库和副本

  • 缓存

  • 消息代理

  • 对象存储

  • 外部服务

  • 监控和日志系统

不要添加对正在记录的决策没有影响的基础设施细节。

8.3 使用部署图进行风险分析

部署建模可以揭示:

  • 单点故障

  • 暴露的数据库

  • 缺失的网络边界

  • 过度的跨区域流量

  • 缺乏故障转移策略的依赖项

  • 环境之间隔离不足

  • 未加密的连接

  • 不切实际的扩展假设

9. 状态机图:建模生命周期

状态机图描述了实体如何通过在不同状态之间迁移来响应事件。

当对象的行为强烈依赖于其当前状态时,它们非常有用。

常见示例包括:

  • 订单

  • 支付

  • 发货

  • 支持工单

  • 用户账户

  • 工作流请求

  • 订阅

  • 文档

  • 设备

  • 作业执行

示例:

VPasCode 界面显示订单生命周期状态机的 PlantUML 代码及其对应的可视化图。

@startuml
[*] --> Draft

Draft --> PendingPayment : submit
PendingPayment --> Paid : payment approved
PendingPayment --> PaymentFailed : payment declined
PaymentFailed --> PendingPayment : retry payment
Paid --> Processing : begin fulfillment
Processing --> Shipped : dispatch
Shipped --> Delivered : confirm delivery
Paid --> Cancelled : cancel
Processing --> Cancelled : cancel if allowed
Delivered --> [*]
Cancelled --> [*]
@enduml

9.1 仔细定义状态

状态应表示有意义的条件,而不仅仅是动作。

良好的状态:

  • 待审批

  • 已批准

  • 已拒绝

  • 支付失败

  • 已发货

薄弱的状态:

  • 点击按钮

  • 调用服务

  • 运行方法

动作是事件或转换。状态是持续存在的条件。

9.2 包含转换规则

转换可以包含:

  • 事件

  • 守卫条件

  • 动作

例如:

待审批 -- approve [经理已授权] / recordApproval --> 已批准

这使得业务规则可见且可测试。

9.3 使用状态机生成测试用例

每个转换都暗示了测试用例:

  • 有效转换

  • 无效转换

  • 守卫失败

  • 重复事件

  • 超时

  • 重试

  • 取消

  • 恢复

对于订单生命周期,测试可能验证:

  • 草稿订单可以提交

  • 已交付的订单无法取消

  • 支付失败允许重试

  • 已取消的订单无法恢复为已支付状态

10. 七种图表如何协同工作

这些图表应构成一个一致的模型,而不是七幅互不关联的插图。

考虑“提交费用报告”这一功能。

七张 UML 图从用例、活动、序列、类、组件、部署和状态机角度阐释“提交费用报告”功能。

用例

  • 员工提交费用报告

  • 经理审批费用报告

  • 财务人员处理报销

活动

  • 录入费用

  • 附件收据

  • 验证数据

  • 提交报告

  • 路由至经理

  • 批准或拒绝

  • 发送至财务部门

序列

  • 员工界面调用费用服务

  • 费用服务验证报告

  • 收据服务存储附件

  • 工作流服务分配经理

  • 通知服务发送警报

类

  • 员工

  • 费用报告

  • 费用项

  • 收据

  • 审批

  • 报销

组件

  • Web 应用程序

  • 费用服务

  • 收据存储

  • 工作流服务

  • 通知服务

  • 财务集成

部署

  • 浏览器

  • Web 层

  • 应用集群

  • 对象存储

  • 关系型数据库

  • 财务平台

状态机

草稿 → 已提交 → 审核中 → 已批准 → 已报销
                         ↓
                      已拒绝

每张图表都提供不同的视角,而不会重复其他所有图表的内容。

11. 选择创建哪些图表

一个实用的选择过程是询问团队存在何种不确定性。

流程图将七种软件不确定性类型与特定的 UML 图进行匹配,包括用例、活动、序列、类、组件、部署和状态机图。

不确定性 有用的图表
系统范围不明确 用例
业务流程不明确 活动
协作或集成不明确 序列
领域概念不明确 类
架构边界不明确 组件
基础设施或网络拓扑不明确 部署
生命周期规则不明确 状态机

并非每个功能都需要对应的图表。

轻量级决策规则

当满足以下任一条件时,请创建图表:

  • 多个利益相关者对需求的理解存在差异。

  • 某流程具有关键的分支或并行行为。

  • 某场景跨越多个系统边界。

  • 某领域对象具有非平凡的规则。

  • 某架构决策需要传达。

  • 部署拓扑影响可靠性、安全性或性能。

  • 生命周期规则难以用文字说明。

  • 该图表将用于实现、评审、测试或运维的复用。

避免仅因模板要求而创建图表。

12. 详细程度层级

优秀的建模实践会采用多个抽象层级。

上下文层级

展示系统及其主要的外部参与者或系统。

适用于:

  • 范围

  • 利益相关者沟通

  • 系统边界

容器或子系统层级

展示应用程序、服务、数据库及主要集成关系。

适用于:

  • 架构

  • 所有权

  • 部署规划

组件层级

展示内部架构部件及接口。

适用于:

  • 详细设计

  • 依赖审查

  • 团队边界

代码层级

展示类、方法及实现依赖关系。

适用于:

  • 开发人员工作

  • 重构

  • 调试

切勿将所有层级置于同一张图中。上下文图不应包含所有类,类图也不应试图表示整个生产网络。

13. Visual Paradigm UML

Visual Paradigm 非常适合偏好图形化建模和集成文档的团队。

免费 UML 工具

它可用于:

  • 交互式绘制 UML 图

  • 维护模型仓库

  • 将图表与需求关联

  • 建立可追溯关系

  • 生成文档

  • 通过共享建模环境进行协作

  • 生成或逆向工程选定工件

  • 使用导航和组织功能管理大型模型

13.1 优势

图形化 UML 工具在以下情况下特别有用:

  • 分析师和非开发人员需要编辑图表

  • 利益相关者更倾向于可视化操作

  • 项目需要正式的模型组织

  • 可追溯性至关重要

  • 团队维护中央存储库

  • 文档必须一致地生成

13.2 推荐用法

对于受益于以下功能的模型视图,请使用 Visual Paradigm:

  • 交互式布局

  • 丰富的注释

  • 跨图表导航

  • 正式的存储库管理

  • 可追溯性

  • 利益相关者研讨会

不要让工具决定建模策略。首先确定:

  • 该图表支持哪项决策

  • 谁会阅读它

  • 适当的详细程度是什么

  • 如何维护它

  • 模型是否需要连接到需求或代码

13.3 存储库规范

共享模型存储库受益于与源代码控制相同的实践:

  • 建立命名约定

  • 分配主要模型领域的负责人

  • 审查重大变更

  • 避免不必要的重复图表

  • 归档过时的视图

  • 记录重要图表的目的

  • 保持模型元素命名一致

14. VPasCode 与基于文本的建模

VPasCode 支持在 Visual Paradigm 生态系统中采用面向文本的建模方法。这种风格适用于希望图表更像源代码工件的团队。

VPasCode 界面显示 PlantUML 代码,定义图书馆系统类图,其中包含图书、杂志和 DVD 类之间的继承关系。

 

基于文本的图表可以提供:

  • 版本控制兼容性

  • 代码审查

  • 分支与合并

  • 自动生成

  • 可重复构建

  • 更便捷的批量更新

  • 与源代码和文档的紧密关联

基于文本的模型可能如下所示:

actor Customer
usecase "Place Order" as PlaceOrder
Customer --> PlaceOrder

具体语法取决于工具和流程,但更广泛的优势在于图表以可编辑文本的形式表示,而不仅仅是图形文件。

14.1 基于文本的建模何时效果良好

在以下情况下使用基于文本的图表:

  • 开发人员维护模型

  • 图表频繁变更

  • 团队使用 Git 或其他版本控制系统

  • 审查人员希望检查文本变更

  • 图表作为文档的一部分生成

  • 多个分支需要独立演进

14.2 潜在局限性

在以下情况下,基于文本的建模可能不太方便:

  • 业务利益相关者需要直接编辑图表

  • 布局必须手动优化

  • 模型包含丰富的视觉注释

  • 团队不熟悉图表语法

  • 仓库需要复杂的视觉导航

混合方法通常行之有效:针对面向代码的架构使用基于文本的图表,针对面向利益相关者的分析使用图形化工具。

15. PlantUML

PlantUML 是一种流行的基于文本的绘图方法,能够从纯文本生成 UML 及相关架构图表。

示例:

VPasCode 界面左侧显示 PlantUML 语法,右侧显示生成的序列图,展示用户、Web 应用、应用服务和数据库之间的交互。

@startuml
actor User
participant "Web App" as Web
participant "Application Service" as App
database Database

User -> Web : Request
Web -> App : Execute operation
App -> Database : Read/write data
Database --> App : Result
App --> Web : Response
Web --> User : Display result
@enduml

15.1 优势

PlantUML 很有价值,因为图表可以:

  • 与源代码一同存储

  • 在拉取请求中进行审查

  • 自动生成

  • 通过简单的文本编辑进行更新

  • 包含在 Markdown 或文档构建流程中

  • 在不同环境中保持一致性

15.2 组织 PlantUML 文件

一个实用的仓库结构可能如下所示:

docs/
  architecture/
    system-context.puml
    components.puml
    deployment.puml
  workflows/
    place-order.puml
    refund-payment.puml
  domain/
    order-model.puml
    order-lifecycle.puml

使用描述性名称,并按用途而非工具来组织图表。

15.3 将生成的图像排除在单一事实来源之外

在可能的情况下:

  • 存储.puml文件作为权威来源

  • 在文档构建过程中生成 PNG、SVG 或 PDF 文件

  • 避免手动编辑生成的图像

  • 验证图表在自动化环境中能否成功渲染

15.4 使用一致的样式

定义一个小型视觉词汇表:

  • 外部系统使用一种颜色

  • 内部服务使用一种颜色

  • 数据库使用一种颜色

  • 异步消息使用一种符号

  • 接口使用一种命名约定

  • 表示安全边界的一种方法

一致性比装饰更有价值。

16. AI 辅助的 UML 建模

AI 可以加速建模,但应将其视为建模助手,而非权威。

从文本到架构:利用 Visual Paradigm 的生成式 AI 加速 UML 建模 - Visual Paradigm 博客

AI 适用于:

  • 将需求转换为候选用例

  • 提取参与者和目标

  • 提议活动流程

  • 生成 PlantUML

  • 建议序列参与者

  • 识别领域实体

  • 检测缺失的备选路径

  • 审查图表的一致性

  • 从图表生成文档

  • 在图形表示和文本表示之间进行转换

  • 从状态转换生成测试思路

16.1 高效的 AI 工作流程

可靠的工作流程如下:

  1. 提供需求、约束和系统上下文。

  2. 要求 AI 识别假设和歧义。

  3. 生成候选图表。

  4. 根据实际需求审查图表。

  5. 将其与实现和基础设施进行比较。

  6. 纠正不准确或虚构的细节。

  7. 渲染并直观地检查结果。

  8. 获取相关利益相关者的审查意见。

  9. 将批准的模型存储到项目仓库中。

  10. 当系统发生变化时更新它。

16.2 使用约束条件提示 AI

弱提示:

为订购系统创建一个 UML 图。

Visual Paradigm 聊天机器人显示为订购系统生成的 AI UML 类图,阐释客户、订单和支付之间的关系。

更强的提示:

Visual Paradigm 聊天机器人显示为提交订单流程生成的 PlantUML 序列图,包含并行的支付和库存步骤。

为提交订单创建一个 PlantUML 序列图。

参与者:
- 客户
- Web 应用程序
- 订单服务
- 支付提供商
- 库存服务
- 订单数据库

约束条件:
- 订单确认前必须完成支付授权。
- 库存预留可与支付授权并行发生。
- 支付被拒必须使订单状态保持为 PaymentFailed(支付失败)。
- 超时应重试一次。
- 展示成功、被拒和超时的路径。
- 不要虚构此处未列出的服务。

序列图阐释提交订单的工作流程,包含并行的支付和库存步骤,以及授权和超时重试的替代路径。

约束条件表述得越清晰,输出中包含不支持架构的可能性就越小。

16.3 向 AI 寻求批评,而不仅仅是生成

有用的审查提示包括:

  • 哪些需求未被体现?

  • 缺少哪些分支?

  • 该序列图是否与状态机相矛盾?

  • 是否有任何依赖关系未作解释?

  • 是否有职责被分配给了错误的组件?

  • 部署模型是否支持可用性需求?

  • 哪些转换应成为测试用例?

  • 哪些假设需要确认?

16.4 常见的 AI 建模失败

AI 生成的模型可能:

  • 虚构参与者或服务

  • 混淆业务角色与技术组件

  • 添加不受支持的数据库表

  • 假设通信是同步的

  • 省略失败路径

  • 错误表示所有权

  • 错误使用 UML 关系

  • 生成语法正确但语义错误的图表

  • 混合抽象层级

  • 将猜测视为需求

核心原则是:

AI 可以快速生成草稿,但只有领域审查和技术审查才能确定草稿是否真实可靠。

17. 将 UML 与现实进行验证

只有当图表与系统保持一致时,它才具有价值。

17.1 按需求进行验证

检查:

  • 每个重要需求是否都出现在一个或多个模型中?

  • 参与者和目标是否正确?

  • 是否体现了业务规则?

  • 是否包含了异常处理?

  • 在相关之处是否反映了非功能性需求?

17.2 按实现进行验证

检查:

  • 组件边界是否与代码一致?

  • 序列参与者是否存在?

  • 接口和消息是否准确?

  • 类的职责是否现实可行?

  • 异步操作是否被正确表示?

  • 状态转换是否由实现强制执行?

17.3 按操作进行验证

检查:

  • 部署图是否真的可以部署?

  • 网络连接是否现实可行?

  • 是否表示了外部系统?

  • 在重要之处是否包含了数据库、队列、缓存和存储?

  • 故障和扩展假设是否合理?

17.4 跨图验证

查找以下类型的矛盾:

  • 一个用例命名了一个在系统上下文中不存在的参与者

  • 一个序列图调用了架构中未显示的组件

  • 一个状态机允许一个业务规则不支持的转换

  • 一个类图显示为一对多关系,而数据库强制为一对一关系

  • 一个部署图遗漏了序列图所需的服务

  • 一个活动图显示了并行操作,而实现是严格顺序的

跨图的一致性通常比任何单个图的艺术质量更重要。

18. 可追溯性

可追溯性将模型与需求、代码、测试和运行工件联系起来。

一个简单的可追溯性链可能如下:

需求
  → 用例
    → 活动流
      → 序列场景
        → 组件
          → 实现
            → 自动化测试

对于有状态域对象:

业务规则
  → 状态转换
    → 守卫条件
      → 测试用例

可追溯性并不要求将每个元素连接到其他所有元素。应专注于高价值关系:

  • 安全关键行为

  • 监管要求

  • 安全控制

  • 重要集成

  • 复杂业务规则

  • 高风险架构决策

19. 版本控制与模型维护

图是一种文档,当文档未得到维护时,其可靠性就会降低。

19.1 将模型存储在其所描述的工作附近

可能的方法包括:

  • 源代码仓库中的UML文件

  • 架构文档仓库

  • 共享建模仓库

  • 随技术文档发布的生成图

  • 需求与模型元素之间的关联

19.2 结合代码审查图表

对于架构或行为变更,在可行的情况下,应将相关的图表更新与实现纳入同一变更中。

审查人员随后可以评估:

  • 实现是否符合预期设计

  • 设计变更是否已完成

  • 依赖关系是否已发生变化

  • 是否存在新的故障路径

  • 是否已考虑部署影响

19.3 优先使用较少的权威图表

多个相互矛盾的图表比一个不完整的图表更糟糕。应明确每个关注点以哪张图表为权威依据。

例如:

  • 组件图:作为主要服务边界的权威依据

  • 部署图:作为生产拓扑的权威依据

  • 状态机:作为订单生命周期的权威依据

  • 类图:作为领域关系的权威依据

20. 常见建模错误

信息图详细说明八种常见的 UML 建模错误,包括过度复杂化图表、混淆抽象层级以及忽略失败场景。

试图建模一切

更多的图表并不会自动带来更深入的理解。应仅对关键风险和决策进行建模。

混淆抽象层级

切勿将业务角色、编程类、云基础设施和数据库列混入同一张未加区分的图表中。

使用模糊的名称

诸如“处理数据”或“处理请求”之类的名称会掩盖意图。应优先使用能明确标识目标、职责或有意义事件的名称。

遗漏失败行为

仅包含成功路径的模型会引发不切实际的期望。应包含重要的异常、重试、超时和拒绝状态。

将图表视为永久不变

架构是演进的。每张图表都应明确负责人并设定维护预期。

过度使用 UML 关系

简单的关联关系通常优于技术上精确但令人困惑的多种关系类型组合。

使图表难以阅读

使用多个聚焦视图,而非一个庞大的图表。按场景、子系统、生命周期或部署边界对大型模型进行拆分。

让工具驱动设计

工具可以使绘制图表更容易,但它无法决定哪些内容需要建模,也无法判断模型是否正确。

21. 实用的建模工作流

团队可以为某个功能或系统采用以下工作流。

步骤 1:确定范围

创建轻量级上下文视图并识别:

  • 系统边界

  • 主要用户

  • 外部系统

  • 主要目标

步骤 2:识别用例

将用例写成参与者的目标。对相关功能进行分组,并识别最重要的场景。

步骤 3:建模主工作流

使用活动图展示:

  • 正常流程

  • 决策点

  • 职责

  • 并行工作

  • 异常处理

步骤 4:选择关键场景

为那些重要、复杂、高风险或集成密集度的交互创建序列图。

步骤 5:定义领域结构

为这些场景涉及的概念创建概念级或设计级的类图。

步骤 6:建立架构边界

使用组件图展示:

  • 主要模块或服务

  • 接口

  • 依赖关系

  • 所有权

  • 集成点

步骤 7:模型部署

当基础设施、安全性、可扩展性、可用性或运营成为重要考量时,请创建部署图。

步骤 8:模型生命周期

为那些行为取决于状态或允许转换的实体创建状态机图。

步骤 9:验证

将模型与以下内容进行比较:

  • 需求

  • 现有代码

  • 测试

  • 数据结构

  • 基础设施

  • 运营约束

步骤 10:维护

当行为、接口、所有权或部署发生变化时,更新受影响的图表。

22. 典型系统的最小交付物

对于中型应用程序,一个实用的基线可能包括:

  • 一个系统上下文或用例视图

  • 两到五个用于重要业务流程的活动图

  • 两到五个用于关键场景的序列图

  • 一个领域类图

  • 一个组件图

  • 一个生产部署图

  • 关键生命周期实体的状态机图

这不是强制性配额。某些系统可能需要更少的图表,而另一些系统可能需要更多。适当的数量取决于复杂性、风险、团队规模、法规以及误解的成本。

23. 工具选择策略

不同的工具服务于不同的建模需求。

需求 合适的方法
利益相关者研讨会 图形化 UML 工具
正式仓库与可追溯性 可视化建模平台
由开发人员负责维护的架构文档 PlantUML 或 VPasCode
在拉取请求中审查图表 基于文本的图表
快速初稿 AI 辅助生成
高保真运行拓扑 图形化或感知基础设施的建模
长期有效的文档 版本控制的源代码加上自动渲染
探索性建模 白板或轻量级绘图

团队无需为每种情况选择单一工具。如果事实来源和维护责任明确,混合方法也能行之有效。

结论

实用的 UML 策略并非使用所有图表类型,而是选择能阐明系统的最小视图集。

七图核心提供了广泛的覆盖范围:

  • 用例图解释目标与范围。

  • 活动图解释工作流与职责。

  • 序列图解释协作与时序。

  • 类图解释结构与领域概念。

  • 组件图解释架构边界。

  • 部署图解释运行时部署与基础设施。

  • 状态机图解释生命周期规则。

Visual Paradigm 可支持图形化建模、可追溯性及基于仓库的协作。VPasCode 和 PlantUML 使图表更易于与源代码一起进行版本控制、审查、生成和维护。AI 可加速起草、转换和审查,但其输出必须与实际需求、真实实现及运行约束进行核对。

最强大的建模实践是严谨而非穷尽:

  1. 建模关键决策、风险与行为。

  2. 选择最能回答问题的图表类型。

  3. 确保每个图表专注于一个抽象层级。

  4. 通过一致的命名和可追溯性连接相关图表。

  5. 根据需求、代码、测试和部署验证模型。

  6. 将图表作为可维护的项目工件进行存储和审查。

  7. 移除不再提供价值的图表。

有效的 UML 并非以生成的图表数量来衡量,而是看模型是否帮助人们以更高的信心构建、测试、运行和修改系统。

参考资料

  1. VPasCode:基于 PlantUML、Mermaid 和 Graphviz 的 AI 辅助图表即代码: 官方指南,涵盖 VPasCode 的文本到图表引擎、语法最佳实践以及 AI 辅助修改工作流。
  2. 从“绘图杂务”到“表达”:AI 聊天机器人概述: 解释 Visual Paradigm 的 AI 聊天机器人如何将自然语言转换为符合标准的 UML 及其他图表。
  3. 利用 NotesKeep 知识库增强 Visual Paradigm AI 聊天机器人: 展示如何将 NotesKeep 仓库连接为知识库,以支持 AI 驱动的图表生成和需求综合。
  4. 用 Visual Paradigm 革新您的 Mac UML 建模体验: 概述 Visual Paradigm 在 macOS 上对 UML 2.x 的支持、代码工程及模型可追溯性。
  5. Visual Paradigm 18.1 推出 AI VPP 聊天机器人: 发布 AI VPP 聊天机器人,允许用户通过自然语言查询 .vpp 项目文件。
  6. VPasCode 计划与定价: VPasCode 免费版的定价及与 Visual Paradigm Online/桌面版集成的功能对比。
  7. 欢迎使用 Visual Paradigm VPasCode:图表即代码的变革: 介绍图表即代码工作流以及 PlantUML、Mermaid 和 Graphviz 的统一渲染环境。
  8. Visual Paradigm VPasCode 中的原生 AI 图表生成: 详细介绍 VPasCode 的嵌入式 AI,它可在编辑器内直接生成和修改 PlantUML/Mermaid/Graphviz 图表。