Appearance
第2章 建模工作流
1.2 建模工作流
1.2.1 建模工作流 ABCD
要做好需求和设计,从而低成本制造出好卖的系统,并非喊喊口号 就可以,需要静下心来学习和实践一些必要的建模技能。
软件开发是增量、迭代进行的,每一个迭代周期都需要依次思考这 么几个事情:
A-业务建模(business modeling)——定位需要改进的目标组织以及该组织接下来最需要改进的问题。
B-需求(requirements)——描述为了改进组织的问题,待引入的信息系统必须具有的整体表现。
C-分析(analysis)——提炼为了满足功能需求,待引入的信息系统需要封装的核心域机制。
D-设计(design)——考虑质量需求和设计约束,将核心域机制映射到选定非核心域上实现。
本书将以上 ABCD 称为软件开发的 4 个建模工作流。
软件江湖中各种花里胡哨的用语,不管是真创新还是伪创新,基本 上都可以用上面的 ABCD 来归纳,例如:
产品经理、需求工程师、需求分析师:A+B+部分 C。
业务架构师:可能是 A(此时“业务”的含义是“组织”),也可能 是 C(此时“业务”的含义是“核心域”)。
系统架构师:C+D。常有团队说要改进系统架构,其实他想改进 的是 B-需求。
领域驱动设计:C+D。也有团队声称要学习“领域驱动设计”,其 实想解决的却是 A-业务建模的问题。
中台:C+D
微服务:C+D
设计模式:C+D
……
欢迎读者随时补充更新。
1.2.2 关于用词
“工作流(workflow)”沿用自 RUP(Rational Unified Process) 的早期版本,后来的 RUP 版本改为“科目(discipline)”。
在我看来,“工作流”和“科目”这两个词都不算太好,但目前没 有更合适的选择,暂时先用“工作流”。
4 个工作流的名称“业务建模”、“需求”、 “分析”、“设计”沿用了 以往各个方法学的用语,这些用语也不严谨。
例如, “业务建模”末尾有一个“建模”,其他 3 个却没有,难道 其他 3 个不是建模?如果把其他 3 个也加上尾巴“建模”,就变成批量 刷废话了;如果把“业务建模”的“建模”去掉剩下“业务”,意思已 经不对。
甚至“业务”二字都是模糊用语,这个后文再详述。
更贴切的名称可能是:
A-组织改进 B-系统责任 C-核心域逻辑 D-实现
但再三权衡,还是沿用之前的用语。
如果读者真正理解了 ABCD 的内容,叫什么问题都不大,改成 A- 阿猫、B-阿狗、C-阿鸡、D-阿鸭也无所谓。
阅读到此处,读者可能会发现,本书中的“需求”和“设计”两个 术语有两种用途。
一种用于表达建模得到的结果,例如“需求和设计不是一一对应 的”;另一种用于表达建模的工作流,即“B-需求”工作流和“D-设 计”工作流,例如“我正在做需求”。
希望下面的话能帮助理解:
为了得到需求,需要做的建模工作流有“A-业务建模”和“B-需 求”,为了得到设计,需要做的建模工作流有“C-分析”和 “D-设计”。
另外也说一下本书关于人员的一些用词,其中大多用词含义模糊。 本书在某些场合沿用了这些词汇,但在此说明其含义。
- (1)开发人员
这个用语的含义目前已经模糊。有的人使用时含义很窄,意思等同 于“编码人员” ,有的人使用时含义很宽,泛指软件开发团队中的所有 人(当然,什么叫“软件开发团队”也是模糊的) 。 本书作者在使用“开发人员”一词时,含义是:
软件开发团队中从事 ABCD 工作流中任何一项工作的人员。根据 后文的讲述,所谓“测试”工作也是 ABCD 工作流,所以,测试人员 也属于开发人员。
团队中从事管理工作的角色,不属于开发人员。
- (2)建模人员
“开发”本质上就是建模,“建模人员”一词所涵盖的人员和“开 发人员”相同.
本书作者在描述某人使用 UML 或类似表示法的场景时,可能会使 用“建模人员”一词来称呼该人员。
- (3)程序员
本书作者使用“程序员”时,含义是“实现人员”,即从事 D 工作 流的人员。
- (4)产品经理、架构师
另外,本书可能还会出现“产品经理”、“架构师”等用词,但一般 会出现在描述某个软件开发团队的某个场景时。产品经理一般指从事 AB 工作流的人员,架构师一般指从事 CD 工作流的人员。
本书作者在讲解知识或讨论问题时,会尽量使用严谨的用语,不会 主动使用“产品经理”、“架构师”等含义模糊的用语。
1.2.3 逃不掉的思考
在迭代周期中,如果要追求好的结果,按 A→B→C→D 的顺序来 进行推理是必须的,而且各个开发团队一直都在这样做。我们来看几个 场景: 开发团队甲,所有成员都认真学习《软件方法》和认真做题,引进 了 UML 和建模工具 EA,并按照书中的改进指南改进,最终得到很不 错的结果。
开发团队甲的 A→B→C→D 很容易看出来。 开发团队乙,没听说过《软件方法》,也不用 UML 和 EA,用的是 技术总监自己归纳的一套“软件工程方法学”和符号,也还算行之有效。
开发团队乙的 A→B→C→D 也容易看出来,但形式上和开发团队 甲不同。
开发团队丙,快乐拥抱挂着“敏捷”或“领域驱动设计”名头的伪 创新。这些伪创新投资少,见效快,门槛低,产量大,仪式感十足。开 发团队轻松愉快、热热闹闹地讨论和糊墙。
这里面有 A→B→C→D 吗?也许有一点,但很少,这些热闹只是 装模作样。真正起作用的 A→B→C→D 推理,可能是在编码的时候在 大脑里朦朦胧胧进行的,推理的质量可想而知。
开发团队丁,觉得既然 ABC 我都不会,我也不想装模作样,就一 步到 D,直接编码。
这种情况下,还有 A→B→C→D 吗?有的,和开发团队丙差不多, 真正起作用的 A→B→C→D 推理,是在编码的时候在大脑里朦朦胧胧 进行的,同样,推理的质量可想而知。幸好,省去了伪创新装模作样的 成本。
开发团队戊的故事(纯杜撰,勿对号入座)看起来有点不一样。他 们所在的公司赶上了风口,成了某个领域(例如预制菜)的互联网巨头。 在开发和维护预制菜相关的项目时,开发团队戊的领导下觉得现在的前 端框架 Vue、React 等还差点意思——更有可能是为了自己的简历积 极主动地“觉得”Vue、React 等还差点意思,于是搞了个内部项目, 自研前端框架“闪电五连鞭”。过了几年,也许是风潮过了,也许是历 史使命已经完成,预制菜市场冷却,反倒是“闪电五连鞭”框架误打误 撞,受到全世界开发人员热捧,成为公司的生存支柱。
这里面有 A→B→C→D 吗?看起来像是颠倒了?
再看一个特别的,程序员张三自己做一个东西给自己用。张三只会 用编码工具,也没学过 UML 或类似的知识。
张三这里面还有 A→B→C→D 的推理吗?
最后这两个,答案也是一样的,并没有什么特别,具体留到后文详 述。
总之,每一个软件项目,只要不是故意摆烂,开发团队都会有 A →B→C→D 的推理过程——也许无意识、隐式地做,也许有意识、显 式地做;也许推理过程严谨合理,也许推理过程漏洞百出;也许分成很 多人来做,也许一个人做;推理产物的形式也许是 UML 模型,也许是 其他……
就像一道复杂的数学填空题,答案是 974/2025,如果考生能填对 这个正确答案,他必然在考试过程中的某个时间点做了正确的推理— —毕竟蒙对这样的填空题答案还是挺难的。只要不是故意摆烂,即使 是学渣,也会尝试着去推理。只不过相对于学霸的一击必中,学渣可能 要反反复复“敏捷探索”多次才答对,甚至直到考试结束还没答对。
本书希望教给读者一种严谨和高效的推理方法。当然,要掌握它, 需要付出辛勤和汗水。
1.2.4 不了解 ABCD 的危害
1.2.4.1 思维颠倒
如果软件开发人员对以上的“A-业务建模” 、“B-需求” 、“C-分析” 、 “D-设计”工作流没有概念,就会出现这样的现象:
问一名开发人员“你在做什么”,他可能回答“我在做设计”、“我 在写文档”。 其实,此时他的大脑可能正在思考组织的流程(A-业务建模),或 者在思考系统有什么功能性能(B-需求),或者在思考系统要封装的领 域概念之间的关系(C-分析) ,但他通通回答成“在做设计” 、“在写文 档”。 也就是说,在他的大脑中,软件开发工作被简单地分为“写代码” 和“做设计(写文档)”两部分。如果他没有在“写代码” ,那么通通是 在“做设计(写文档) ”。
那么,他是怎么区分自己在“写代码”还是“做设计(写文档) ” 呢 ? 可 能 是 这 样 区 分 的 : 在 Visual Studio 、 Android Studio 、 Eclipse……中写出来的叫“代码”,在 Word、wiki、Visio、EA……中 写或者画出来的叫“文档”。
这时候如果有人忽悠一句口号:代码就是设计,那就更妙了。因为 本来我就认为“设计”是“代码以外的各种东西”,现在又说“代码就 是设计” ,一推导,不就变成了“代码就是(软件开发的)一切”?
即使没有“代码就是设计”这样的忽悠,开发人员也会把“设计” (注意,此处的“设计”不是本书严格定义的 D 工作流,而是“代码 之外的所有东西”)或“文档”看成“代码”的一种比较概要或比较形 象的表现形式。不同的“设计”或“文档”代表着“代码”的不同视图, 可以让开发人员从不同的视角观察代码。
这样的误解不只“普通”的开发人员会有。Martin Fowler 所著的 UML 畅销书《UML 精粹》,认为 UML 有三种用法:草稿、蓝图和编 程语言,也是把 UML 模型看作是代码的视图——这是错误的。虽然 Martin Fowler 在某些社群的心目中如大神一般存在,但是从 Fowler 写作的其他书籍《重构》、《企业应用架构模式》、《分析模式》等可以知 道,他的研究工作集中在“C-分析”和“D-设计”工作流,较少涉及 “A-业务建模”和“B-需求”工作流。他关于“A-业务建模”和“B- 需求”工作流的言论,应谨慎看待。
更危险的是,把“文档”当作“代码”的视图还会带来思维颠倒: 先拍脑袋编码(快进到 D 工作流) ,然后再从代码(D)来反推 A、B、 C 工作流的内容,导致其他工作流变成徒有形式的装模作样。
以下是几段我经历过的思维颠倒的对话:
★对话一
我:这个不应该是系统的用例(如果读者不理解什么叫“用例”, 就先把它理解为“功能”好了)。 开发人员:是的!我都写好了,运行一下给你看,这个系统确实提 供了这个用例。
系统是否应该有这个用例,应该从“A-业务建模”来推理,通过 愿景、业务序列图等步骤的推理后,觉得应该有,系统就有,不该有就 没有。不能说,我写好了代码,所以就应该有。
★对话二
我:这两个类的关系不应该是泛化,而是关联。
开发人员:是泛化,不信我打开代码给你看(或:逆向工程转出类 图给你看)。
是否泛化关系应该从领域逻辑来判断,领域逻辑不是,那就不是, 代码就不应该那样写。不能先写代码“人是猪的一种”(这肯定能通过 编译器的检查),再用写好的代码来证明“人是猪的一种” 。
★对话三
我:A 聚合(组合)B,这个不太对。
开发人员:对的,你看我代码,A 是聚合根,其他对象调用时要先 找 A,存取数据也是以它作为单元。
同对话二,是否聚合(组合)关系应该从领域逻辑来判断,领域逻 辑不是,那就不是,代码就不应该那样写。
如果了解了 ABCD 工作流的概念,以及在不同工作流中所需要思 考和表达的内容,我们可能就不会再说“我在写文档”这种话了。“我 在写文档”只是表达“我写的东西不是代码” 或者“我正在用文档编 辑工具在工作”。
你在写什么“文档”?“A-业务建模”?“B-需求”?“C-分析”? 我不写,我画图,难道不可以吗?我不写不画,我用语音清楚地表达组 织的流程,难道不可以吗?我用 Word 编码(即 D-设计),难道不可 以吗?我用 C#写需求(即 B-需求) ,难道不可以吗?
更有意义的说法应该是“我在做业务建模”、“我在做需求”……如 果说“文档”二字可以给你带来不可替代的快感,可以说“我在写业务 建模文档”。
1.2.4.2 胡乱应对
开发人员常说要“应对变化”,甚至有的人还喊口号“拥抱变化”, 但是很多人并不清楚要应对的是什么样的变化,也不知道应该怎样正确 地应对变化。
当我们谈到“变化”的时候,真相有可能是下列之一:
- 真相(1):根本没有变化
系统的需求(功能、性能和约束)没有变化,只是之前由于实现人 员的能力问题,导致实现没有满足需求,或者能满足需求但自认为系统 的内部结构不合理。这样的修改不能叫“应对变化”,只能叫“纠错”。
可笑的是,有的人也把这个情况也称为“应对变化”。就像考试有 一道题难度稍高,学渣“敏捷”地算了一下,没算出来,把原来的擦掉, 再来,还是没算出来,于是大喊“变化剧烈!”。
这种情况下,需要关注的工作流是“C-分析”和“D-设计”。
- 真相(2):系统的功能没变,性能和约束变了
例如,响应时间需要缩短,实现平台需要更换等。
应对这样的变化,需要关注的工作流是“D-设计” ,实现的套路要 调整。
- 真相(3):系统功能的合理变化
经过严谨的“A-业务建模”和“B-需求”的推理,认为系统的功 能(用例、步骤、输入输出信息、业务规则……)确实需要变化。
应对这样的变化,需要关注的工作流是“C-分析” 。
注意,这里说的是经过“A-业务建模”和“B-需求”的严谨推理 得出的“合理变化”。系统的功能之所以需要变化,根源在于系统所处 的大环境中的某些东西发生了变化,而这样的变化往往是有其规律的。 通过“C-分析”工作流,调整系统的核心域模型,使其更好地体现核 心域的规律,有助于应对这样的变化。
- 真相(4):系统功能的不合理变化
这就是平时常说的“假需求”。和(1)一样,这其实不是“变化”, 是“错误”。
没有经过严谨的“A-业务建模”和“B-需求”的推理,拍脑袋得 到的所谓“系统功能”,不能改进组织流程,也不满足涉众利益。
这种情况下,关注“C-分析”工作流意义并不大,因为这种变化 缺少规律。 如果我们发现在“C-分析”工作流下功夫对“应变”的改进并不 大,那意味着我们需要关注的工作流应该是“A-业务建模”和“B-需 求”。先学会严谨推理出系统的功能,才能知道真相到底是(3)还是 (4)。
我们用医生给患者看病类比: 真相(1): 医生的诊断没问题,开的处方也没问题,护士或患者执行医嘱时执 行错了。 这不是“变化”,这是“错误” 。如果还把这个叫作“拥抱变化”, 就是无耻了。 真相(2): 输液时,换了另外一种品牌的一次性输液器。 真相(3): 患者病情确实有变化。张三原来只是乙肝,现在是肝癌。 这种变化是有规律的。张三得了乙肝却不注意保养,依然酗酒和熬 夜,很快进展到肝硬化,然后进展到肝癌。 如果充分了解肝脏的工作机制(C-分析),当张三被诊断出乙肝时, 就可以合理应对当时的情况,并预测和提前应对后面可能会发生的变化。 真相(4): 医生诊断错了病情。
张三出现恶心、乏力、食欲减退。村里的道士九叔给他诊断,认为 他被鬼上身了,需要搞一个驱魔仪式。九叔已经精研驱魔理论体系和实 践多年,一手辟邪剑法已经达到传奇王者。
实际上张三是得了乙肝,九叔的传奇王者对此没有帮助。
当然,如果是玩驱魔游戏或 Cosplay,又不一样了。
也许是不了解其中区别,也许是为了掩盖自己的无能,开发人员经 常胡乱应对。
例如,把真相(4)说成真相(3),营造出“需求变化剧烈”的假 象,从而掩盖自己缺少“A-业务建模”和“B-需求”能力的事实。
例如,对真相(3)和真相(4)避而不谈,只谈真相(2),或者 想通过真相(2)的应对方案“D-设计”来应对真相(3)和真相(4), 因为“D-设计”是他唯一熟悉的内容。
一些资料以“领域驱动设计”为名,结果一看内容,所举的例子就 1-2 个“领域”类,然后就开始讨论 Entity、Service、Repository、 DTO、六边形架构……哪里有“领域”?分明说的是“企业应用架构模 式” 、“互联网系统架构模式”。
在各种软件开发技术大会上,也可以看到这样的场景:某电子商务 网站的架构师上台讲了一通,接着某视频网站的架构师上台也讲了一通, 咦,这两人是同事吗,演讲内容如此相似?原来,他们讲的内容都是“D- 设计”的内容。究其原因也许不是不愿意讲,而是讲不出来——该架
构师就会这一点点,连自己所开发系统的核心域都研究得很浅。
1.2.4.3 伪创新泛滥
很多开发人员只有 D 的知识。当岗位发生变化,需要他做 A、B、 C 的工作时,按道理应该去认真学习 A、B、C 的技能才对。
可惜,很多人并不愿意走出自己的舒适区,甚至还会有意无意地把 其他人拉到自己的舒适区。
例如,在和涉众讨论需求时,频频蹦出一些“技术潮词”,目的就 是以自己的“所长”来碾压涉众,从而掩盖自己业务建模(A)和需求 (B)技能的不足。
例如,在讨论核心域的类模型(C)时,动不动就谈到如何实现(D) 或者质疑“会不会有性能问题”(D),从而掩盖自己抽象能力的不足。
于是,各种投其所好的伪创新就登场了。
有的伪创新极力贬低 A、B、C 的重要性,通过“砸烂一切枷锁” 来吸引热血青年。例如,想那么多有啥用,最后不是还得写代码?张嘴 就是 Linus Torvalds 的“Talk is cheap. Show me the code.”。
后来,“发明家”及其追随者慢慢发现砸烂一切是不行的,追随者 的信念开始动摇。于是,伪创新不再贬低 A、B、C,而是从 D 来臆想 A、B、C,得到的 A、B、C“方法学”非常“简单易学”,让只了解 D 的开发人员感觉“很受用”。
例如,深入第一线调研各类涉众的利益很麻烦。有办法,摆一个“现 场客户”在旁边,开发人员就可以心安理得坐在电脑前面编码,有问题 就推给“现场客户”。
例如,认真学习领域知识的各种概念和术语很麻烦。有办法,开发 人员可以按照自己的理解创造一套“通用语言” 。
伪创新往往并不会直接说自己简单易行,而是会说自己很高深。宣 传中往往带有“艺术”、“禅”、“道”等字眼,有意无意地朝宗教、艺术、 玄学方向引导——比起枯燥的数学理论和逻辑推理,这些东西可是太 好下嘴了。还有一个很大的优势,一些媒体人听到“艺术” 、“禅”、 “道” 等字眼就亢奋,自觉地加入到宣传伪创新的队伍中。
开发人员一开始以为很难很深奥,上手一学,发现其实不难!可以 说是:投资少,见效快,产量高,门槛低,而且仪式感十足。最妙的是, 不用走出舒适区辛苦学习,就得到了“方法学”,这可太符合只了解 D 的开发人员的胃口了!开发人员立刻有捡到了便宜的感觉,心中豪气顿 生——不愧是我!别整三岁的,有能耐你整四岁的!
伪创新还会声明“领域驱动设计不是银弹”之类,也是为了进一步 塑造形象。我都诚实地说了我不是满分,所以我前面塑造的 90 分的形 象应该是真的。
关于各个工作流的各种伪创新,本书后面各章节还会进一步讨论。
1.2.5 没有测试工作流?
“测试”可以看作建模的验证过程,所以不能光说“做测试”,要 清楚认识“测试”所验证的内容。
如果“测试”验证的是组织流程中各个系统之间的协作,那就是“A- 业务建模”。
如果“测试”验证的是目标系统的整体表现,那就是“B-需求”。
如果“测试”验证的是目标系统内部各个部件之间的协作,那就是 “C-分析”和“D-设计”。
无论是启发、定义还是验证,如果你思考的内容是某一个工作流的 内容,你就是在做该工作流。在一个迭代周期中,启发、定义和验证往 往是交错进行的。
1.2.6 没有项目管理工作流?
本书关注的范围限于方法学,即 A→B→C→D 的正确推导方法, 至于推导是一个人做的,很多人做的,甚至是猫做的、狗做的、外星人 做的,没有直接关系。
还是用前面的大楼类比。两幢大楼耸立在那里,地震来了,一幢塌 了,另一幢没塌。
直接因素是大楼的结构、所用的材料、所在位置的地质环境等,这 些涉及到艰深的工程力学、流体力学、岩土力学等知识——类似于本 书所研究和阐述的方法。即使大楼是外星人盖的,也要讲这个基本法。
直接原因往往比较难理解,此处要提防,有的人为了掩盖自己的无 能,干脆找比较容易理解的其他原因来把水搅浑。例如,一出事故就嚷 嚷“有人吃回扣了”,就算经过调查没人吃回扣,他也会从工作服的颜 色,工人是否结对洗澡,施工队开会时是否站立等更容易理解的方面来 找原因。
当然,要成功完成一个软件开发项目,还有很多其他工作,例如进 度管理、人力资源管理等,但这些都不属于本书讨论的范围。关于软件 项目管理方面的内容,读者可自行阅读专门的书籍。
1.2.7 人工智能对 ABCD 各工作流的帮助
我认为,当前(2025 年)人工智能对 ABCD 各工作流的帮助如下所示。
| 工作流 | 步骤(图可以换) | 建模难度 | 助力分数(100分) | 说明 |
|---|---|---|---|---|
| A-业务建模 | 愿景 | ++++ | 5 | 揣摩人心,终极问题 |
| 组织价值(业务用例图) | + | 30 | 常见机构 | |
| 组织现状流程(业务序列图) | +++ | 15 | 常见大流程 | |
| 组织改进流程(业务序列图) | ++ | 50 | 现状流程描述得足够精细 | |
| B-需求 | 系统需求概要(系统用例图) | + | 不需要 | 从改进业务序列图搬砖 |
| 系统需求规约(系统用例规约) | ++++ | 15 | 涉及利益,终极问题 | |
| C-分析(OO方法) | 分析类图 | ++++ | 30 | 对初步抽象有帮助,抽象程度不够 |
| 分析状态机图 | ++++ | 10 | 稍微复杂就玩不转 | |
| 分析序列图 | ++ | 10 | 如果前面两个做过了,这个小意思 | |
| D-设计 | 按照选择的实现架构映射 | ++ | 80 | 体力劳动,按照套路搬砖和领域逻辑建模正确与否无关 |
表格中, “步骤”这一列是 ABCD 工作流的细化,“建模难度”这 一列指的是建模人员用目前可得的建模工具建模的思考难度,“助力分 数”这一列描述假设前面的步骤已经解决,要得出下一个步骤的有真正 价值的工件,AI 的帮助有多大?
我们先在这里做这么一个论断,表中的很多内容是接下来的章节才 会讲解的,所以有的地方不理解也不要紧。在后续章节讲解每一个步骤 时,我们还会逐一剖析人工智能对这个步骤带来什么帮助。这样,大家 就可以更好理解为什么有这样一个“助力分数”。