Skip to content
On this page

第4章 应用UML的建模工作流

← 返回《软件方法》

1.4 应用 UML 的建模工作流

1.4.1 概念

我用类图表示建模工作流相关概念如图 1-18。

text
图 1-18 建模工作流相关概念
@startuml
!theme plain
left to right direction
hide empty members
skinparam linetype ortho
class 工作流类型 #E3F2FD {
    - 名称
    - 内容
    - 顺序
}
class 工作流 {
}
class 迭代 {
    - 编号
}
class 项目 {
    - 名称
}
class 方法学 #E3F2FD{
    - 名称
}
class 工件类型 #E3F2FD{
    - 名称
    - 内容
    - 顺序
}
class 表示法 #E3F2FD{
    - 名称
}
class 表示元素 #E3F2FD{
    - 名称
}
class 工件形式 #E3F2FD{
    - 名称
}
class 工件 {
}
工作流类型 "1" -- "0..*" 工作流
工作流 "1" -- "0..*" 迭代
迭代 "1" -- "1" 项目
方法学 "1" -- "0..*" 工件类型
工件类型 "1" -- "0..*" 工件形式
工件类型 "1" -- "0..*" 工作流类型
表示法 "1" -- "0..*" 表示元素
表示元素 "1" -- "0..*" 工件形式
工件形式 "1" -- "0..*" 工件
工件 "*" -- "1" 工作流
@enduml

图 1-18 左侧灰色部分定义了“游戏规则”,右侧则是在“游戏规 则”上“玩游戏”的结果。 显然,只是看这个类图不能很好理解相关概念。我用对象图展示本 书推荐的“游戏规则”如图 1-19。

text
图 1-19 建模工作流相关概念的对象图
@startuml
!theme plain
left to right direction
hide empty members
skinparam linetype ortho

object 方法学 {
  名称 = 《软件方法》
}
object A_业务建模
object B_需求
object C_分析
object D_设计
object 组织价值
object 组织现状流程
object 组织改进流程
object 系统需求概要
object 系统需求规约
object 分析类
object 分析类的交互
object 分析类状态机
object 存储查询
object 类的实现
object 愿景文档
object 业务用例图
object 业务对象类图
object 业务序列图
object 系统用例图
object 系统用例规约
object 分析类图
object 分析序列图
object 分析状态机图
object 关系数据库方案
object 源代码
object 文本
object 用例图
object 类图
object 序列图
object 状态机图
object UML

方法学 --> A_业务建模 : 包含
方法学 --> B_需求 : 包含
方法学 --> C_分析 : 包含
方法学 --> D_设计 : 包含

A_业务建模 --> 组织价值 : 包含
A_业务建模 --> 组织现状流程 : 包含
A_业务建模 --> 组织改进流程 : 包含

B_需求 --> 系统需求概要 : 包含
B_需求 --> 系统需求规约 : 包含

C_分析 --> 分析类 : 包含
C_分析 --> 分析类的交互 : 包含
C_分析 --> 分析类状态机 : 包含

D_设计 --> 存储查询 : 包含
D_设计 --> 类的实现 : 包含

组织价值 --> 愿景文档 : 使用
组织现状流程 --> 业务用例图 : 使用
组织现状流程 --> 业务对象类图 : 使用
组织现状流程 --> 业务序列图 : 使用
组织改进流程 --> 业务用例图 : 使用
组织改进流程 --> 业务对象类图 : 使用
组织改进流程 --> 业务序列图 : 使用

系统需求概要 --> 系统用例图 : 使用
系统需求规约 --> 系统用例规约 : 使用

分析类 --> 分析类图 : 使用
分析类的交互 --> 分析序列图 : 使用
分析类状态机 --> 分析状态机图 : 使用

存储查询 --> 关系数据库方案 : 使用
类的实现 --> 源代码 : 使用

愿景文档 --> 文本 : 使用
业务用例图 --> 用例图 : 使用
业务对象类图 --> 类图 : 使用
业务序列图 --> 序列图 : 使用
系统用例图 --> 用例图 : 使用
系统用例规约 --> 文本 : 使用
分析类图 --> 类图 : 使用
分析序列图 --> 序列图 : 使用
分析状态机图 --> 状态机图 : 使用
关系数据库方案 --> 文本 : 使用
源代码 --> 文本 : 使用

文本 --> UML : 属于
用例图 --> UML : 属于
类图 --> UML : 属于
序列图 --> UML : 属于
状态机图 --> UML : 属于

@enduml

图 1-19 中,除了最左侧的“工作流类型”之外,都是可以变化的。 可以替换“表示元素”。例如,系统用例规约改为用活动图表达, 则图 1-19 的相应部分可以修改。

可以替换“表示法” 。例如,把 UML 换成其他表示法或自创的表 示法,那么图 1-19 左起 3 到 5 列都要修改。

可以替换“方法学”,例如,受“少林功夫+唱歌跳舞”启发,创 造出“浑元形意太极+革命性创造划时代洞见领域驱动设计敏捷精益方 法学”,但仍然使用 UML 表示法,那么图 1-19 左起 2、3 列需要修改。

1.4.2 工具箱

UML 2.5 包含的图形一共有 14 种,如图 1-21 所示的树上的叶结 点。

text
 1-21
@startuml
hide empty members
'uml2.5 版本
class UML图
class 结构图
class 行为图
class 类图
class 组件图
class 对象图
class 扩展机制图
class 组合结构图
class 部署图
class 包图
class 活动图
class 用例图
class 状态机图
class 交互图
class 序列图
class 通信图
class 交互概述图
class 时间图
结构图 --|>  UML图
类图 --|> 结构图
组件图 --|> 结构图
对象图 --|> 结构图
扩展机制图 --|> 结构图
组合结构图 --|> 结构图
部署图 --|> 结构图
包图 --|> 结构图
行为图  --|> UML图
活动图 --|> 行为图
用例图 --|> 行为图
状态机图 --|> 行为图
交互图 --|> 行为图
序列图 --|> 交互图
通信图 --|> 交互图
交互概述图 --|> 交互图
时间图 --|> 交互图
@enduml

经常会有人有意无意地误导,让人以为使用 UML 建模需要画这么 多图,顺势攻击“UML 笨重”。其实,应该把 UML 看作一个工具箱。 工具箱里面有各种工具,建模人员只需要根据当前所开发系统的特点, 从这个工具箱中选择合适的工具就可以,并不需要“完整地”使用 UML。

这和编程语言类似。很多人说“我用 Java”,其实只是用 Java 的 一小部分,而且很长时间内也只会用这一小部分。

经常有学员问:潘老师,能不能给一个案例,完完整整地实施了整 套 UML?这是一种误解,这样的案例不应该有。这相当于问:有没有 一本经典的小说,把字典里所有的单词都用上了?有一些建模工具自带 的案例模型会造成误解,一个模型里把所有的 UML 图都给用上了,但 这是工具厂商出于展示其工具建模能力的目的而提供的,不可当真。

1.4.3 使用 UML 建模的工作流步骤

图 1-19 中“工件形式”一列所列出的图就是本书推荐的在建模工 作流 ABCD 中的 UML 用法,我用活动图进一步表示建模的步骤如图 1-22。本书的内容就是按照图 1-22 的顺序讲述。

text
1-22
@startuml
start
group "A-业务建模" {
    :定位目标组织和愿景;
    :绘制业务用例图;
    :绘制现状业务序列图;
    :绘制改进业务序列图;
}
group "B-需求" {
    :映射系统用例图;
    :书写系统用例规约;
}
group "C-分析"{
    :绘制分析类图;
    :绘制分析序列图;
    :绘制分析状态机图;
}
group "D-设计"{
    :映射数据层;
    :映射业务层;
    :映射表示层;
}
end
@enduml

本书重点使用的 UML 图形只有 4种:用例图、类图、序列图和状态机图。

设计工作流的建模,推荐做法是不用 UML 表达,而是用相应实现平 台的表示法表达,即所谓的“源代码” (目前大多是文本形式)。考虑了具体平台实现的类图、序列图、状 态机图等,其中包含的信息和“源代码”差不多,没有必要花费精力去 画设计工作流的 UML 图再编码,因为这样做没有带来任何增值。

建模过程中,我们写的每一个字,画的每一张图,都应该能带来增 值,否则就没有必要写它或者画它。这一点,本书后面还会不断提到。

更合理的做法是,做好分析工作流,把领域逻辑放进分析模型中, 然后再结合实现平台的特点,定制从分析到设计的有规律的映射套路, 通过建模工具或者人力搬砖把分析按照套路映射到设计。

这时,即使要画设计的类图、序列图等,也只需要挑选典型的类、 典型的用例来展示映射的套路,不需要把分析模型的内容都结合实现平 台画一遍。像 Rhapsody(当前的全名是 IBM Engineering Systems Design Rhapsody)这样的建模工具,可以和各种开发环境集成,配置好后就 可以通过正向工程从类图、状态机图生成可执行的代码。开发人员甚至 可以做到只需要编辑和调试 UML 模型,不需要在编码环境中编辑和调 试。图 1-24 是用 Rhapsody 工具绘制的某个模型(洗碗机)的运行时 状态机图,粉红色标出了当前的状态。类图和状态机图的背后有真实的 C++代码。

当然,Rhapsody 支持的平台和语言只是少数,而且目前很多建模 工具在分析映射设计方面达不到类似 Rhapsody 的水平,但这并不妨 碍我们针对所选择的实现平台来定制映射套路,然后通过人力搬砖来达 到类似目的。

同样,如果需要设计工作流的 UML 图来搞形式主义充场面,可以 通过建模工具对源代码或数据库做逆向工程,生成设计工作流的各种 UML 图。就是用建模工具 UModel 对某个 C#类的某个操 作做逆向工程生成的序列图。可以看到,这张序列图涉及到很多类的协 作。图的右侧放大了一个小片段,勉强让读者能够阅读。

以上提到的定制映射套路、正向逆向工程等内容,本书在设计工作 流的章节再详述。

1.4.4 关于“源代码就是设计”的歪曲和真相

1.4.4.1 Jack Reeves 的文章

1992 年,Jack Reeves 在 “C++ Journal”上发表了一篇名为"What Is Software Design(什么是软件设计)”的文章。

我把 Jack Reeves 文章中的观点列出如下,并附上我的评论。

(1)根据他的观察,软件开发生命周期中,唯一满足工程标准的 软件文档是源代码清单。这是正常的。当时(1992 年),除了源代码所使用的编程语 言之外,软件开发生命周期中其他产出很难谈得上有什么严格的语法和 语义规则。

(2)软件开发的一切都是设计过程的一部分。编码是设计,测试 和调试是设计,平时我们称为“软件设计”的东西也是设计。

——这是要求从“设计”的高度来看编码,不是说代码能编译运 行就行。

(3)C++是很有表达力的软件设计语言。

——要从“设计”的高度来看编码,编程语言要有好的表达力, 例如 C++。毕竟是发表在 C++ Journal 上的文章嘛。

整体来看,Jack Reeves 的文章没有太偏激的观点。即使存在问题, 也是前文提到的普遍缺少 A、B 工作流知识的问题。

1.4.4.2 Robert C. Martin 的修饰

"What Is Software Design”一开始并没有广为流传。 2002 年 , Robert C. Martin 在 他 的 书 “ Agile Software Development, Principles, Patterns, and Practices”第 1 版中附上了 这篇文章,并在前面加了个大标题“The Source Code Is the Design (源代码是设计) ”。 这是 Robert C. Martin 的第一个“小心思” 。

Robert C. Martin 这本书的书名也包含着“小心思”。“Agile Software Development, Principles, Patterns, and Practices”主要 讲的是面向对象设计的一些方法(原理、原则和模式),这些方法并非 Robert C. Martin 首先提出,和“敏捷”提倡的“过程”也没有必然 关系,但 Robert C. Martin 把它们称为“敏捷**”,很容易让开发人员 误解,这些东西是“敏捷”人士提出来的。

最近一些年的领域驱动设计伪创新走的也是这条路线,背后的操盘 者们也是来自同一个圈子。更多评价见后文提到的“染色”。

2007 年,Robert C. Martin 在第 2 版 “Agile Principles, Patterns, and Practices in C#”中,也附上了 Jack Reeves 的文章,但名字改 成了“What Is Software(什么是软件)”

1.4.4.3 中文翻译的误导

Robert C. Martin 书的第 1 版中译本《敏捷软件开发:原则、模 式与实践》中,把“The Source Code Is the Design”翻译为“源代 码就是设计” 。

“是”和“就是”有微妙的差别,“是”表达的是从属关系,“就是”隐含着相等关系。

马铃薯是草本植物:马铃薯∈草本植物

马铃薯就是土豆:马铃薯=土豆

源代码是设计:源代码∈设计或源代码⊂设计

源代码就是设计:源代码=设计

从上面列出的观点(2)可以看出,Reeves 的文章中并没有这个 意思。

文章"What Is Software Design”目前可在以下地址获得:

https://www.developerdotstar.com/mag/articles/PDF/DevDotStar_Reeves_CodeAsDesign.pdf

感兴趣的读者可以去下载阅读。

另外,以上只是说 Reeves 的意思被歪曲了,但没有说 Reeves 本 来的意思就一定是对的。类似这样的观点,往往都存在前文提到的普遍 问题:缺少对 A 和 B 工作流的认识。


关于“source code(源代码,代码)”,有的开发人员也存在误解。

计算机运行的是二进制指令,源代码是程序员需要理解和编辑的最 低形式模型——编辑完这个,后面的事情就可以交给计算机了!

中文翻译“代码”中的“代”字就体现了这个意思,用更方便理解 和编辑的符号来“代替”原来的指令。从这一点看,编码就是一种最低 68 形式的建模工作,源代码也是“模型”。

这个最低形式模型是随着时代的发展不断变化的,

最开始,程序员在纸带或卡片上打孔来表达 0 和 1,这可不是“代 码”了,就是“码”本身。

后来发现这样太累了,于是发明了一些助记符,这就是汇编语言。

有的开发人员凡尔赛,“这些我不太懂唉,我是做底层的,用 C 编码”,可是 C 语言却被归类为“高级语言”,因为类似 C 这样的语 言出现的时候,大多数程序员编辑的是汇编语言,C 相对于汇编来说, 当然很高级。

今天的一名企业应用程序员,需要编辑的可能有 HTML、CSS、 JavaScript、Java、配置脚本、SQL 等,这些就是当前常见的“源代码” 的形式。