我看到张逸老师在最近的一些文章中喜欢提"老"字,例如:
"我充分借鉴了事件风暴这种新方法,却又未完全抛弃UML这种老方法"
"若有可能,我还希望再加上一个ICONIX方法,虽然它已经垂垂老矣,但该方法蕴含的一些设计思想仍有值得借鉴之处"
张逸老师的关注点从编码拓展到软件开发的全部工作流,值得称赞。不过每个工作流有各自的技能需要学习,是自己的感悟还罢了,如果要传授技艺给他人,更需要高标准严要求才对。
所以,我就用建模思维剖析张逸老师近期发表的一些内容,供大家参考。
就先从张逸老师上面这两句话开始吧。
一、不是什么都叫"方法"
上面这两句话,张逸老师对各种概念一律以"方法"称呼之。其实UML是"Unified Modeling Language",是"语言",或者"表示法"(Notation)。
ICONIX则是Doug Rosenberg等人提出的一种使用UML的建模过程(Process)。我们先来看2001年的著作:
图1 摘自Rosenberg, D., Scott, K., Applying Use Case Driven Object Modeling with UML: An Annotated e-Commerce Example. Addison Wesley (2001)
再来看2007年的著作:
图2 摘自Rosenberg, D., Stephens, M., Use Case Driven Object Modeling with UML: Theory and Practice. Apress (2007)
关于方法、过程和工具的定义,可以参照被广泛使用的教材"Software Engineering: A Practitioner's Approach",2014出了第8版。
图3 摘自Pressman R., Maxim B., Software Engineering: A Practitioner's Approach 8th Edition. SEM (2014)
我于2008年写的《四十年软件工程故事》(http://www.umlchina.com/book/se40.htm)也可以参考。
为什么对这些不当用词如此重视,我在《为什么要对术语"吹毛求疵"》一文(http://www.umlchina.com/qa/Content/906.htm)中阐述了我的观点:
我们听到有人像上面的姨妈表哥一样说话时,我们心里知道,这可不是什么习惯用语不同,而是说话的人是外行。因为我们是内行,我们比姨妈表哥们更知道一些概念之间的区别。
同理,如果我们真的弄懂了软件开发中的一些重要概念,当有人在我们面前说"功能模块"、"用户需求"、"设计阶段"等术语时,我们心里就知道了,这不是什么习惯问题,而是这个人在某些方面是个外行。
二、关于"老"
人们对事物的认识会不断深入,所以,已有的知识有的会被继承,有的会被淘汰。但是要注意,之所以某些知识会被淘汰,是因为人们针对这方面的知识有了更深刻的认识,而不是因为法律规定这个知识只有"**年**权",到时间就要强行作废。几百年前的数学、物理知识,大部分我们今天不还在继续学习和使用吗?
图4 摘自《*城镇国有土地使用权出让和转让暂行条例》
既然张逸老师说"UML"、"ICONIX"老、垂垂老矣,那我请问张逸老师,能否具体说说看UML、ICONIX到底有哪些缺点,看看能不能说到位?但愿不是为了强调自己的"新"而随口一说。
我不认为UML这个建模语言是完美的,也不认为ICONIX这个过程的做法有多好。我甚至认为经过将近20年的积累,对于建模和UML的下一步改进,我的认识也许比起很多国外的人士更深刻。我还相信我在《软件方法》中提倡的过程比ICONIX(以及其他一些类似过程)要更高效实用。
不过,绝大多数软件开发人员基本上是"赤手空拳",根本没有达到被UML的不完美和ICONIX的不足绊倒的地步。事实上,就算有人不使用UML里的图,能熟练使用数据流图和实体关系图建模,或者把能把ICONIX那几招用熟,我觉得他就已经高出周围的人一大截了。
NBA的格林可能清楚詹姆斯有啥缺点,但这对业余球员来说有多少参考价值?
癌症的化疗、放疗有局限性和副作用,是需要有更好的治疗手段,但方向应该是更精细的免疫治疗,而不是拿几味中药凑一凑得出来的"癌必灵"。
三、"痛点"离"问题域"还有多远
图5 摘自张逸文章《领域驱动战略设计暨微服务设计工作坊》
"域"是一个面积或范围较大的概念,"点"是面积或范围很小或近似于零的概念,两者不能等同。
也许张逸老师要表述的意思是:通过痛点来判断哪一块领域需要建模。就像在人体按下痛点来判断哪一块区域需要深入研究。这样的表述更容易理解一些。
即使换了表述,也还是不准确,因为从"痛点"到领域模型,还有一段距离。"头痛"的问题未必在头。
先列举一些建模知识点,更详细内容请参见《软件方法》。
★序列图消息的含义: A指向B,意思是"A请求B做某事"。例如图6中,患者请求门诊收费挂号员办理挂号。如果发消息的是人,接收消息的是非人智能系统,意思符合"A用B来做某事"也可以。 ★业务工人(Business Worker):组织内的人员,即人脑智能系统。 ★业务实体(Business Entity):组织内的非人智能系统。 ★业务流程信息化改进 模式一:物流变信息流 模式二:改善信息流转 模式三:封装领域逻辑 |
通过下面例子来说明问题。某医院现在有个"痛点":输液反应的投诉比往年多了。
这个"痛点"和需要改进的范围不是一一对应的。
【可能原因一】
有人组团碰瓷。
【改进方案】
1.1 引进一批记忆力好的高级保安(业务工人)盯牢每一个患者,发现可疑人员报警,如图6。
图6 改进方案1.1,引进业务工人
1.2 如果一定要"信息化改进",可以应用改进模式三"封装领域逻辑",引进一套人物特征识别系统(业务实体),把"监控人物特征"的逻辑从高级保安的大脑转移到人物特征识别系统,并争取和*部门的业务实体对接。一旦检测到碰瓷党到来,直接报警并通知挂号员,如图7。
图7 改进方案1.2,业务实体替换业务工人
由图7可以映射出"人物特征识别系统"的用例图,也就是用例级别的需求,如图8。补充上用例的涉众利益、路径、步骤、补充约束,就得到完整的系统用例规约,即以用例为组织形式的需求规约。
图8 人物特征识别系统的用例图
可能有的人会问,这个系统应该还有其他用例吧?例如有个人用这个系统来设置一下规则?可能有,也可能没有(读者可以想一想,为什么可能没有?)。不过再有100个也不影响,因为每次迭代只需要关注最重要的用例,永远都在路上。
如果某个已有的非人智能系统已经提供了这个用例,评估过后觉得确实满足需求的约定,那事情到此为止,不用操心后面的分析设计工作流了。
如果没有现成的可用,还是要做,那就开始分析工作流。
只要构造出来的系统履行了需求的约定,按照哪种分析设计方法学来构造系统都可以。如果用面向对象分析设计方法学来构造系统,我们假设系统由"对象"这样一种东西构成。在分析工作流,系统中的对象在一个虚的"对象空间"中运行。这个空间不是内存,也不是硬盘,只是人脑中的一个逻辑空间。
可能的分析类图如下:
图9 人物特征识别系统的分析类图(不熟悉这个领域的逻辑,仅属猜测)
【可能原因二】
中国逐渐进入老龄社会,老年输液患者的人数越来越多。
【改进方案】
2.1 不改进,主管部门理解就行。
2.2 在内部下密令,医生开医嘱时,留心看一眼HIS系统里的患者资料。针对老年患者开医嘱时,尽量不要有输液内容,如图10。
图10 改进方案2.2-让医生(业务工人)判断是否老年患者
2.3 如果一定要"信息化改进",可以应用改进模式三"封装领域逻辑",在现有HIS系统里添加一些逻辑,医生在给老年患者开医嘱时,HIS系统提醒一下,如图11。
图11 改进方案2.3-HIS判断是否老年患者
HIS系统已有的用例"开医嘱"中,会多一些步骤(判断是否老年患者、提醒医生……)和补充约束(判断老年患者规则)。HIS系统内部可以不增加新的类,可以在原有"患者"类上增加一个操作"判断是否老年患者",在原有"医生界面"类上增加一个操作"提醒医生有老年患者"。
【可能原因三】
医院采购部门人员和厂家勾结,为了获取回扣而购买劣质药品和器械。
【改进方案】
3.1 改进采购流程。例如集中采购权,由采购办主任把关审查。
图12 改进方案3.1-采购办主任把关
3.2 如果一定要"信息化改进",可以应用改进模式一"物流变为信息流",改为通过信息系统传递采购申请,取消各部门采购人员的责任;应用改进模式三"封装领域逻辑",将采购办主任大脑里的审查逻辑封装一部分到HIS系统中,如图13。
图13 改进方案3.2-通过HIS系统传递信息,由HIS系统封装领域逻辑
从图13可以看出,HIS系统多了两个用例:
图14 HIS系统多了两个用例
要实现这两个用例,可能的类图如下:
图15 HIS系统可能需要增加和修改的类
【可能原因四】
护士职业技能或职业素养存在问题,例如对患者宣讲不到位,无菌操作不到位,没有根据患者差异调节输液速度等。
【改进方案】
4.1 加强培训,加强监督,加大奖惩力度。例如,增加暗访人员:
图16 改进方案4.1-增加暗访人员
4.2 如果一定要"信息化改进",可以把业务工人"暗访员"替换成业务实体"监控系统",事后安排监督员观看录像并评价。
图17 改进方案4.2-引进监控系统代替暗访人员
在市场上购买通用的监控系统应该可以满足需求。
4.3 更进一步的信息化改进,可以把护士这个业务工人去掉,用业务实体"超级输液机"和"无人运药小车"代替。
图18 改进方案4.3-引进超级输液机和无人运药小车
从图18可以映射出"超级输液机"的用例:
图19 超级输液机的用例
可能的类图如下:
图20 超级输液机的类图
由上可见,针对一个"痛点",可以有很多改进的可能。不同的可能中,是否需要引进信息系统,引进新的信息系统还是在原有信息系统上改进,又有不同的选择。不管是哪一种选择,推导的思路是清晰的。
四、内外不分,对问题域(Problem Domain)的误用
图21 摘自张逸文章《领域驱动战略设计暨微服务设计工作坊》
当我们说起"功能"的时候,研究对象一般是系统。对于组织,一般说"组织的服务",对于类,一般说"类的操作"。所以,"功能"属于"需求"的范畴(所以有术语:功能需求),描述系统作为一个整体为其他系统提供的服务。
针对图21,首先要说的是,功能不是What,是"做某事"。可以是"下单"(可能是系统用例级别),也可以是"计算运费"(步骤级别)。
按照张逸老师的观点,问题域是功能,其他则属于解决方案域。如果用我之前所举案例的最后一种情况"超级输液机"套上去,是不是应该如下图?
图22 按照张逸观点划分的"问题域"和"解决方案域"
说到"问题域",估计2000年前后学习面向对象分析设计的开发人员会想到杨芙清、邵维忠写的《面向对象的系统分析》(1998年,清华大学出版社)。当时,开发人员学习OOAD的资料并不多,这本书是当时很好的学习资料,书中说到"问题域"时,给出的都是如图22下半部的类图。当然,作者写书的时候(不是出版的时候)UML标准还没出现,书中用的是Peter Coad提倡的表示法。
《面向对象的系统分析》我手边没有,所以无法贴图,不过杨邵跟随的是Peter Coad和Edward Yourdon的思想,我们可以贴出Coad/Yourdon著作里的截图:
图23 摘自Coad, P., Yourdon, E., Object-Oriented Analysis, Second Edition. Yourdon Press, Inc. (1991)
从图23可见,书中用于描述Problem Domain的是类和属性。
顺便把Coad/Yourdon著作里的"What"也贴一下:
图24 摘自Coad, P., Yourdon, E., Object-Oriented Analysis, Second Edition. Yourdon Press, Inc. (1991)
可能有的读者会觉得上面的贴图说服力不大,因为书的名字就叫"Object-Oriented Analysis",内容聚焦于分析工作流,你咋知道其他书里Problem Domain主要说的不是需求哩?
我们再来看软件需求领域比较有名的著作,Karl Wiegers等所著的"Software Requirements"。书中很少提到 "Problem Domain",正文第一次提到"Problem Domain"的截图如下:
图25 摘自Wiegers, K., Beatty, J., Software Requirements, Third Edition. Microsoft Press(2013)
图25说的是数据字典,更接近于类的概念而不是系统功能的概念。
再看之前的ICONIX书,正文第一次提到"Problem Domain"的截图如下:
图26 摘自Rosenberg, D., Stephens, M., Use Case Driven Object Modeling with UML: Theory and Practice. Apress (2007)
同样涉及整个开发过程而且比Rosenberg等人的书更流行的,应该是Craig Larman的书。我们也来看看Larman的书,正文第一次提到"Problem Domain"的截图如下:
图27 摘自Larman, C., Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development, Third Edition. Prentice Hall (2004)
最后来看Eric Evans的书。书中使用"Problem Domain"也比较少。正文第一次提到"Problem Domain"的截图如下:
图28 摘自Evans, E., Domain-Driven Design: Tackling Complexity in the Heart of Software Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley (2003)
图28说的是非对象范型下的领域模型,说的还是系统内的核心机制-分析,而不是需求。
说了那么多,我的观点是:说系统功能属于问题域是可以的,但不能说问题域指的就是系统功能,而把系统内部的核心域机制(例如分析类、分析状态机)排除在问题域之外。
我更担心的是,张逸老师可能犯了内外不分、需求和分析不分的错误。具体如何,没有更进一步信息不便猜测,大家可以看看我以下的文字有没有参考价值。
我先说一下我对软件建模工作流的划分:
A-业务建模——定位需要改进的目标组织(人群或机构)以及该组织接下来最需要改进的问题。
B-需求——描述为了改进组织的问题,所引入的信息系统必须具有的表现。
C-分析——提炼为了满足功能需求,所引入的信息系统需要封装的核心域机制。
D-设计——考虑质量需求和设计约束,将核心域机制映射到选定非核心域上实现。
以上四个工作流的名称使用了传统术语,也有一定的模糊性(特别是业务建模)。更贴切的名称是组织建模、需求建模、核心域建模、实现。如果您觉得业务建模、需求、分析、设计不好,直呼ABCD或改成阿猪、阿狗、阿鸡、阿鸭也无所谓。关键是要了解划分的依据:一个是研究范围,一个是研究内容。如图29。
针对这些工作流的思考,其实就是建模。任何一个软件项目,这些思考都是逃不掉的,也就是说,我们一直在建模,只不过很多人习惯于无意识地做,运气时好时坏,速度时快时慢,有的人能够有意识地做,让汗水不白流。
思考的结果,可以用口头表达,也可以用文本、其他表示法或自造符号来表达。用UML来表达,目前是一种不坏的做法。如果用UML表达,推荐的用法如图29。可以看到,工作流D可以不需要用UML表达。
图29 各工作流思考内容和推荐表达
再说一下核心域和非核心域的概念。一个软件系统封装了若干领域的知识,其中一个领域的知识代表了系统的核心竞争力,是系统和其他系统区分的关键所在。这个领域称为"核心域",其他领域称为"非核心域"。更通俗的说法是"业务"和"技术",但使用"核心域"和"非核心域"更严谨。核心域不一定是物流、医疗、金融等非计算机领域,也可以是计算机和软件领域。
问题域就是这里说的核心域。
图30展示了不同系统的核心域和非核心域概念:
图30 不同系统的核心域、非核心域概念
在软件开发中,业务建模和需求工作流致力于解决"系统好卖"的问题,分析和设计工作流致力于解决"降低开发成本"的问题。二者不能也不应直接映射。
以常见的"系统"人体举例。人体的基本功能有走路、跳跃、吃饭等,但是思考人体内部结构时,不能从外部直接映射到内部,得到人体由"走路模块"、"跳跃模块"、"吃饭模块"组成,这样会导致大量的冗余。人体的"模块"是五官四肢和内脏,还有最关键的——"大脑"。不管是走路、跳跃还是吃饭或者将来发展出更多的"功能",都应该尽可能复用这些已有的"模块"来协作完成。
还是以"超级输液机"为例。如果从需求直接映射到分析设计,会得到很多无价值的类,如下图:
图31 假面向对象抽象
没有基本的面向对象抽象思维的开发人员,即使使用面向对象的编程语言来编码,也只是直接把系统的某个功能加上or或er作为类名称,然后在这个××or或××er类的操作里写面向过程的代码。这样做表面上似乎是面向对象了,实际上是换汤不换药,没有得到面向对象的好处。想想也是理所当然的,根本没有付出思考,问题怎么会自己消失?
如果从分析设计出发来定义需求,会得到一堆假的"需求",典型的就是"××管理"。就以张逸老师文章里的一张图为例:
图32 摘自张逸文章《领域驱动战略设计暨微服务设计工作坊》
这些"××管理"怎么来的?希望不是自内而外得来——先设想以后数据库里有客户表,所以推导出系统有用例"客户管理"……。
系统的需求应该从外面,即组织的流程来映射,可参见本文前面提供的业务序列图。
再说一个现实生活的类比,希望对理解前面的内容有帮助。
面馆厨师擅长用若干种原料(组件)灵活组合出许多吃法(用例)卖给不同的顾客。同样是以面粉、肉、菜、蛋为主原料,面馆可以提供馒头、包子、花卷、烧饼、饺子、馄饨、锅贴、烧麦、春卷、油条、发糕……拉面、刀削面、擀面、擦面、哨子面、扯面、油泼面、担担面、拌面、焖面、面疙瘩、揪面片、手擀面、拉条子、炒面……臊子面、沙茶面、茄丁面、酸菜面、鸡蛋面、虾仁面、牛肉面……
我去面馆就餐,点了一碗馄饨,过了一会,老板端来一碗饺子。我说,"老板,这是饺子,不是馄饨!"老板肯定不能嘲笑我,"笨,饺子和馄饨98%是一样的,都是面粉和肉菜的组合,制作工艺也差不多,你就将就着吃吧!"。要是这样我会扭头就走,因为隔壁还有面馆(这个最关键!)。
老板可以把饺子端回后厨,经过快速分解,重新组合,几分钟之后饺子变成了馄饨,然后又端出来给我。我并不了解馄饨哪里来的,只要味道比隔壁的好,价格又公道,我就吃呗。
当然,绝大多数的面馆没有把已经煮好的饺子分解再组合快速变馄饨的黑科技,多半是用新的原料重新快速做一份馄饨。
但软件开发的原料复制起来并不需要钱啊!
五、需求、分析……是阶段吗
……
有的读者反馈"不一定非得按照你说的吧,有自己的方法不行吗"
答:
(1)不懂得我说的这些知识,糊里糊涂地做事。
(2)懂得我说的这些知识,仔细思考过后还是决定按照自己原有的风格做事。
这两者不一样。只要读者您不是第(1)种,本文的目的就达到了。
来而不往非礼也。我写的《软件方法》以及三年之内的公众号文章(当然也包括本文),也欢迎张逸老师和各位读者批评指正。
★《软件方法(上)》第2版,自行到书店购买,亚马逊Kindle版:https://www.amazon.cn/dp/B07DFR2313,勘误:http://www.umlchina.com/book/errata2ed.html。
★《软件方法(下)》目前公开内容,http://www.umlchina.com/book/softmeth0809.pdf。
您在阅读《软件方法》时如果发现错误,欢迎通过下面提供的微信、QQ或邮箱告知。如果作者认为有道理,决定在下一次发布时根据您的意见修改,将付给您5.12元报酬,并在书的前言中说明您的贡献。报酬通过微信或支付宝支付。每个错误只支付最先指出者。
书中有很多自测题,建议在把自测题做对后,判断书中确实可能有错,再向作者提出。
微信:umlchina2,QQ和QQ邮箱:1493943028