UML(统一建模语言)6 是表示面向对象设计的实际标准。它在记录设计方面做得很好,但它有一个严重的问题:它的图表不能传达人类需要知道的内容,使得它们难以理解。这就是为什么大多数软件开发人员仅在被迫时才使用 UML。1
例如,图 1 和图 2 中的 UML 图表描绘了传真机中的嵌入式软件。虽然这些图表很吸引人,但它们甚至没有告诉你哪个对象控制其他对象。哪个对象是这台传真机的最高控制器?你不知道。哪个或哪些对象控制 Modem
对象?你不知道。
人们根据控制层级来理解一个组织,例如公司。当面对人员或对象的组织时,通常第一个问题是,“谁在控制这一切?” 令人惊讶的是,UML 没有一个对象控制另一个对象的概念。因此,在每种类型的 UML 图表中,似乎没有哪个对象比其邻居具有更大或更小的控制权。软件设计中控制层级的缺失在以下方面造成了很多危害
• 设计难以理解。不显示层级就像通过在每对相互交互的员工之间画一条线来描绘一家公司。这样的图表将迅速变成无法理解的意大利面条。组织结构图被绘制成控制层级是有原因的:无论公司规模如何,人们都可以很容易地理解它们。
• 因为任何对象都可以以任何期望的方式与任何其他对象交互,所以当人们在设计和实现期间向对象添加功能和交互时,代码结构会滑向无序状态。
• 维护变得更慢且更容易出错,因为学习曲线更陡峭。此外,维护人员可以并且确实可以在任何地方插入黑客代码,导致代码腐烂。
这些问题意味着设计在初始实现和维护期间都容易变得混乱,从而导致更多的错误和延误。
为了有用,描绘软件设计的图表必须以人类能够理解的方式进行交流。软件中的对象组织类似于人类组织,并且几乎毫无例外地,人员组织被描绘成控制层级,最顶层的人员具有最广泛的控制范围。基于这个想法,图 3 是一个简单的 IDAR 图表,它描绘了图 1 和图 2 中显示的同一传真机设计的一部分,但以控制层级的形式表示。
在 IDAR 图表中,框代表对象。如果一个类只有一个实例(最常见的情况),则框用类名标记。连接两个框的箭头表示上层对象命令(并因此控制)下层对象。这样的命令箭头总是向下指。在图 3 中,Fax
对象是最高级别的控制器,它命令 Receive
和 Send
对象,而后者又控制 ImageProc
(图像处理)。命令箭头可以用发送的命令名称标记。例如,Fax
命令 Send
执行 sendFax
。请注意,ImageProc
有两个上级。在人类组织中拥有多个上级是不常见的,但在软件中是常见的(并且是鼓励的),以防止冗余实现。
对象需要以命令以外的更多方式进行通信。例如,它们经常需要交换数据并相互告知事件和结果。在 IDAR 图表中,这种非命令通信被称为通知,并显示为浮动箭头。例如,在图 3 中,Send
通过 done
通知告知 Fax
传输已完成。
命令和通知都只是方法调用。这意味着每个对象中的公共方法分为两组:命令和通知。软件设计人员必须认真思考哪些方法将成为命令,因为它们决定了层级结构。命令和通知都有约束,这些约束将在本文后面精确定义。
关于术语的说明:当你在对象中调用命令(方法)时,你被认为是命令(或向...发送命令)该对象;当你在对象中调用通知时,你被认为是通知(或向...发送通知)该对象。
设计图表应描绘其他显着特征,例如线程、数据流和间接的使用。图 4 中传真机的完整 IDAR 图表例证了其中一些附加功能。
Connect
和 Negotiate
框上方的水平线类似于组织结构图中的水平线:它将下属分组在其经理之下。在 IDAR 图表中,这样的轨道(正如它所称的那样)更通用,因为它表明线上方的所有对象(称为上级或老板)命令线下方的所有对象(称为下属或员工)。在这台传真机中,两个上级(Receive
和 Send
)命令三个下属(Connect
、Negotiate
和 ImageProc
)。
包含线程的对象被称为活动对象,并在其框的每一侧用双竖线表示。此表示法取自 UML。在图 4 中的传真机设计中,Fax
和 ImageProc
是活动的。
间接方法调用用放置在适当箭头尾部的气泡(圆圈)表示。这种间接可以是源代码中的显式,也可以是使用多态继承的隐式。间接通常用于从下属发送到多个上级之一的通知,例如图 4 中从 Connect
发送到 Receive
或 Send
的 connected
通知。
子系统是一个单独的层级结构(一个单独的图表),以子管理器(子系统管理器)作为其最顶层对象。子管理器控制其子系统,并被描绘成细长的六边形。在命令子系统的图表中,仅绘制子管理器。例如,在图 4 中,Printer
和 Scanner
是各自子系统的子管理器,应在单独的图表中显示这些子系统。
虚线箭头表示数据流。通知箭头通常与数据流平行,因为数据流通常使用通知来实现。一个例子是从 Scanner
子系统发送到 ImageProc
的 pixelRow
通知。
请注意,图 4 中某些命令和通知的名称以数字为前缀。这些可选的序列号显示构成操作的动作顺序。在这种情况下,它们显示了发送传真的调用顺序。可以增强此图表的副本以显示接收传真的顺序。这种带注释的图表取代了 UML 中的序列图。它们更容易理解,因为除了顺序之外,你还可以看到哪些操作是命令,哪些操作是响应。
你可能会惊讶地发现,图 4 中的 IDAR 图表与图 1 和图 2 中的 UML 图表是相同的设计。比较这些图表。在 IDAR 图表中,你可以轻松地看到哪些对象控制其他对象,从而揭示此设计的工作原理。
IDAR 图表的 underlying 原则可以用四条规则的形式表达。它们构成了首字母缩略词 IDAR,这些图表因此得名。这些规则是
• 识别 (Identify)。 对象中的每个公共方法都被识别为命令或通知。从其调用者的角度来看,通知仅导入或导出所需的信息。命令可以做任何事情。
• 向下 (Down)。 在绘制对象之间命令调用的图表时,箭头必须向下指。
• 辅助 (Aid)。 命令或通知可能在其调用者未知的情况下,通过执行先前命令操作的部分或全部来辅助其对象。
• 角色 (Role)。 为每个对象和方法编写简短的角色描述,总结其提供的服务,避免任何实现方面的内容(包括辅助)。调用者可能仅依赖于角色描述中声明的内容。
“向下”规则确保每个设计都是由上级和下属(老板和员工)组成的命令层级结构。此规则生成 DAG(有向无环图),因此也称为 DAG 规则。“角色”规则要求每个方法或对象履行其角色,不多也不少,排除意外的副作用。“角色”和“向下”规则共同强制每个设计都成为角色层级结构。“辅助”规则通过允许公共方法秘密地帮助先前命令的职责以及履行自己的角色,为设计人员提供了更大的灵活性。这些规则不适用于横切关注点。2
从公共行为的约束角度思考也很有帮助。命令有一个约束:它们必须在层级结构中向下 (向下规则)。通知也只有一个约束:它们可能只传递信息 (识别规则)。
角色很重要,值得进一步讨论。角色是一种目的、责任或职责。“角色”规则要求每个对象和方法都应有一个角色,可以用几个词概括,最好只包含一个动词。一个例子是“发送传真”。在 IDAR 图表中,最广泛的角色(最大的责任)位于顶部,而最狭隘的角色(最专业的)位于底部。
继承创建了一个层级结构,那么为什么不使用它呢?不幸的是,继承创建了一个类别层级结构,它不如角色层级结构有用。
要了解原因,请查看图 5,该图显示了 CD 播放器的 UML 继承层级结构。DiskMotor
和 LaserMotor
是 Motor
的子类,因此它们属于电机类别。但是,你很少关心它们的类别,因为你需要知道哪些对象控制这些电机。
同样,Laser
、Motor
和 Audio
是 ElectronicDevice
的子类,但这无济于事,因为你需要知道哪些具有更广泛角色的对象命令这些设备。继承层级结构描绘了类别,除了在 GUI 中之外,类别很少有帮助;它没有描绘你需要知道的内容——角色层级结构。
比较 UML 和 IDAR 的一种简单方法是遵循一个操作——例如,发送传真。图 4 中命令和通知上的序列号表明,在用户按下控制面板上的“发送”按钮后,CtlPanel
对象调用 Fax
中的 sendPressed
通知,Fax
显然是整个传真机的主要控制器,它命令 Send
执行 sendFax
。根据其在层级结构中的高位置,你可以看到 Send
处理发送传真的高级方面。它命令 Connect
执行 connect
以连接到接收机器,而 Connect
又命令 Modem
通过 hookUpDn
方法摘机。在 Connect
从 Modem
收到 dialTone
通知后,它命令 Modem
执行 dial
并等待其 answered 通知
。然后,Connect
将 connected
通知发送回 Send
。该图还显示 Send
命令 Scanner
执行 scan
,并且数据(虚线箭头)将从 Scanner
流入 ImageProc
,然后通过 pixelRow
和 xferBulk
通知流入 Modem
。此图揭示了此软件的结构及其工作方式。
图 1、2 和 6 分别是同一传真机设计的 UML 类图、通信图和序列图。通信图(图 2)具有与 IDAR 图表相同的序列号,使比较更容易。
让我们使用 UML 图表来展示如何发送传真。哪些对象具有主要角色?很难说。对象之间哪些交互最重要?很难说。哪些对象是控制器,哪些是工作者?很难说。你能做的最好的事情是在通信图或序列图上按顺序跟踪消息,即使这样也很难确定哪些对象控制其他对象,或者哪些对象具有广泛的角色,哪些对象具有狭隘的角色。UML 未能传达角色或其等级,使得设计难以理解。
IDAR 图表比 UML 具有几个优势,其中两个优势最为突出。
对于开发人员来说,IDAR 图表比 UML 中相应的类图、通信图和序列图更容易理解,原因如下
• IDAR 中的角色层级结构是认知工程中使用的 AH(手段-目的抽象层级结构)7 的广义形式,众所周知,AH 通过为什么-什么-如何三元组来传递理解。这个三元组由一个对象、它的上级和它的下属组成。它提供了以下见解:(1) 对象上级的目的是告诉你对象为什么存在;(2) 对象的角色告诉你对象做什么;(3) 其下属的目的是指示对象如何工作。UML 缺乏 AH,因此它无法告诉你对象为什么存在或如何工作。
• IDAR 图表中的层级结构揭示了哪些对象控制其他对象,以及等效地,哪些对象具有广泛的角色,哪些对象具有狭隘的角色。在图 4 中,很明显 Fax
是顶层控制器,而 Send
和 Receive
是第二层顶层控制器,具有相当广泛的角色。相应的 UML 图表掩盖了这些有益的控制关系和角色广度。
• 每个上级的下属形成一个紧密相关的组,帮助开发人员将功能与对象组关联起来。在图 4 中,很明显 Connect
和 Negotiate
是同一老板下的紧密相关的工作者,而 UML 掩盖了这种紧密的联系。与 UML 不同,IDAR 揭示了工作组。
• 在 IDAR 图表中,命令调用比通知调用更突出,因为它们更重要。UML 掩盖了重要程度。
• 纵观历史,人们选择角色层级结构来表示组织,表明它们是最容易理解的。
• 认知理论专家的研究表明,UML 在可理解性(“认知有效性”)方面存在严重问题。3 具体来说,UML 具有“惊人地高的符号冗余和过载”以及较差的“视觉可辨别性”。IDAR 图表旨在避免这两个问题。
• 其他研究表明,开发人员将软件设计理解为其结构和行为的集成交互作用。1 UML 将结构和行为分成两个或多个单独的图表,降低了理解力,因为开发人员被迫在图表之间来回翻转,试图在心理上整合它们,这“不必要地消耗了开发人员的认知能力”。IDAR 通过将结构和行为合并到一个图表中,消除了这种浪费性的脑力劳动。
IDAR 由此产生的清晰度应缩短学习曲线,减少误解和疏忽,从而提高质量并缩短工期。
UML 中的包可以嵌套,形成层级结构。然而,此层级结构不包含角色,并且每个包内的图表都是网络而不是层级结构。因此,包的层级结构并没有在很大程度上提高可理解性。IDAR 中的子系统没有这些缺点,因此可以充分获得此处详述的可理解性提升。
请注意,公司的组织结构图无论大小,都始终易于理解。由于 IDAR 图表与之相似,因此它们也应该可以扩展到任何大小,并且同样易于理解。
IDAR 图表优于 UML 的第二个重要优势是,它们可以阻止当更改和增强被拼接到代码中时发生的混乱(无序),而很少考虑维护设计的连贯性。以下来自 IDAR 规则的合理约束支持了这一说法
• “识别”规则阻止通知发起操作。在实践中,它阻止开发人员通过散布通知调用来创建意大利面条式代码,因为通知仅允许传递所需的信息。
• “向下”规则阻止下属命令上级。
• “角色”规则阻止意外的副作用,这是一个常见的问题。
UML 没有提供任何这些针对混乱的防御措施。例如,假设你导致传真机中的 Modem
对象告诉 Receive
对象做某事。这将向两个 UML 图表(图 1 和图 2)添加一条线,这条线是不显眼的并且是可以接受的。但是,在图 4 的 IDAR 图表中这样做会违反“向下”规则,因为下属将命令上级。这是 IDAR 阻止的设计衰败的一个例子。
IDAR 图表确实具有以下局限性
• 对象级别。 IDAR 旨在用于对象级别和子系统级别的设计,因此它既不是 ADL(架构描述语言),也不是系统建模语言。对于系统建模,OPM(对象过程方法)1 是一个强有力的竞争者。
• 需要集中控制。 IDAR 依赖于组织为命令层级结构的控制,使其不适用于具有分布式控制的去中心化软件。此类软件的顶层应以另一种方式建模。然而,在某些层面上,去中心化软件的组件可以进行集中控制,并且可以使用像普通软件一样的 IDAR 图表进行设计。
• 不如 UML 富于表现力。 UML 可以描绘比 IDAR 更多的设计视图。例如,IDAR 图表无法描绘状态之间的转换、在处理器上的部署或类之间的泛化。UML 具有用于这些和其他设计方面的图表,应在适当时使用它们。
在诺斯罗普·格鲁曼公司设计、编码和部署了一个重要的程序,该程序使用了 IDAR 图表。该程序负责电路板和系统的校准和测试,正在电子产品的生产线上使用。我们被禁止发布此专有设计,但我们可以说它有 23,000 行 C++ 代码,并且足够复杂,有 38 个类、四个子系统和 10 个线程来处理各种实时事务。这个中等规模的程序不是玩具。
几个人在几年内编写和修改了这个程序,所以它变得有些混乱,甚至不是面向对象的。该程序完全由测试组成,我被要求向其中添加大量非测试功能,使其规模扩大了一倍以上。因此,超过一半的代码代表了新的设计。
对现有代码进行了重构,创建了符合 IDAR 规则的对象。然后,我分阶段设计并添加了新功能。在此过程中,项目中添加了意外的需求,对 IDAR 方法进行了压力测试。IDAR 图表完成了以下工作
• 在整个设计和实现过程中保持清晰度。对象之间的交互非常清晰,避免了对象之间任何潜在的误解问题。
• 轻松适应了对需求的多次更改和添加。层级结构的清晰度使新功能所需的更改应在何处进行变得显而易见。
• 强制执行良好的组织。
• 没有对设计施加过度的约束。这四条规则提供了足够的灵活性,以至于设计不需要为了满足它们而扭曲。
• 使设计更容易,因为规则提供了指导。顶部和底部对象很容易定义,并且定义那些锚对象之间的对象并不困难。这种设计的容易程度令人惊讶,因为施加四条规则预计会使设计更难,而不是更容易。
根据其结果,我们这些熟悉这项工作的人认为,IDAR 图表相对于 UML 的主要优点是其极大的清晰度和对良好组织的强制执行。这个试点计划取得了巨大的成功,管理人员非常满意,他们安排将 IDAR 教给其他软件开发人员。
除了这个试点计划之外,还使用 IDAR 图表创建了许多试验设计,并且IDAR 软件设计方法5 中描述了四个真人大小的应用程序。
角色层级结构对于清晰地描绘任何集中式组织(无论它由人员还是对象组成)的设计似乎至关重要。当今的面向对象编程技术无法表示这种至关重要的层级结构令人惊讶,也许它的缺失是基于不正确的信念而被接受的,即继承层级结构是合适的替代品。
IDAR 图表比 UML 更清晰,主要有两个原因:(1) 它揭示了角色层级结构和这些角色的广度,以及 (2) 三元组(为什么-什么-如何)提供了对对象本质的更深入的见解。UML 无法提供这些。鉴于 IDAR 图表比 UML 更清晰,并且 underlying 它们的四条规则可以抵抗混乱,开发人员在使用 IDAR 图表设计和实现软件时应该会产生更少的错误。结果将是提高质量和及时性。
本文包含足够的信息,使你能够使用 IDAR 图表创建设计。有关更多信息,你可以从 2014 年 IEEE 软件技术会议4 下载演示文稿的幻灯片。此外,请参阅IDAR 软件设计方法5,它不仅详细介绍了这种方法(以及相关主题),还包括本文中提到的四个真人大小的应用程序。
我非常感谢 Jim Ray 对 IDAR 方法的一贯支持。我还想感谢 Jim Wilk 和 Dorothy Kennedy 对这项工作坚定不移的支持。Sammy Messian 管理了使用 IDAR 的试点计划,并因其产生的良好结果而重视它。这四位都是诺斯罗普·格鲁曼公司的经理。
1. Dori, D. 2002. 为什么重大的 UML 改变不太可能。 通讯 45(11): 82-85。
2. Kiczales, G., 等人。1997. 面向切面的编程。第 11 届欧洲面向对象编程会议论文集: 220-242。
3. Moody, D., van Hillegersberg, J. 2009. 评估 UML 的视觉语法:对 UML 图表系列的认知有效性分析。软件语言工程。柏林,海德堡:施普林格出版社:16-34。
4. Overton, M. 2014. 命令图:OOP/OOD 的重大改进。IEEE 软件技术会议; http://conferences.computer.org/stc/2014/index.html 或 http://www.ieee-stc.org。
5. Overton, M. 2014. IDAR 软件设计方法。西雅图,华盛顿州:CreateSpace。
6. Rumbaugh, J., Jacobson, I., Booch, G. 2004. 统一建模语言参考手册,第 2 版。波士顿,马萨诸塞州:Addison-Wesley。
7. Vicente, K. 1999. 认知工作分析。 马瓦,新泽西州:Lawrence Erlbaum Associates: 174-176。
UML 热:诊断和恢复
- Alex E. Bell
承认仅仅是朝着从这种潜在的毁灭性折磨中恢复的第一步。
https://queue.org.cn/detail.cfm?id=1053347
为代码而编码
- Friedrich Steimann 和 Thomas Kühne
模型可以为软件开发提供 DNA 吗?
https://queue.org.cn/detail.cfm?id=1113336
使用代码地图进行软件开发
- Robert DeLine、Gina Venolia 和 Kael Rowan
那些无处不在的手绘代码图会成为过去吗?
https://queue.org.cn/detail.cfm?id=1831329
Mark Overton 是诺斯罗普·格鲁曼公司的软件工程师,致力于软件无线电的各个部分。他之前曾在惠普工作,为一体化打印机的架构和实施做出了贡献,尤其是它们的扫描仪。多年来,他一直是一位发明家,在图像处理方面拥有多项专利,并发表了一种基于子周期生成随机数的新方法。IDAR 图表是他最新的,也许也是最重要的发明。
版权 © 2017 归所有者/作者所有。出版权已授权给 。
最初发表于 Queue vol. 15, no. 2—
在 数字图书馆 中评论本文
Eric Bouwers, Joost Visser, Arie Van Deursen - 获得你所衡量的
软件指标 - 有用的工具还是浪费时间?对于每一位珍视这些软件系统数学抽象的开发人员来说,都有一位开发人员认为软件指标的发明只是为了让项目经理忙碌。软件指标可以是帮助你实现目标的非常强大的工具,但正确使用它们非常重要,因为它们也具有降低项目团队积极性和将开发导向错误方向的能力。
Duncan Johnston-Watt - 在新管理下
在全球竞争日益激烈的环境中,企业面临着降低运营成本的巨大压力。与此同时,他们必须具备应对动荡市场提供的商业机会的敏捷性。
Derek Miers - 最佳实践 (BPM)
正如 BPM(业务流程管理)技术与传统的应用支持方法截然不同一样,BPM 开发的方法也与传统的软件实现技术截然不同。以 CPI(持续流程改进)作为 BPM 的核心 дисциплина,推动公司工作的模型不断发展。事实上,最近的研究表明,公司至少每季度(有时甚至每年八次)微调其基于 BPM 的应用程序。关键是根本没有“完成”的流程;需要多次迭代才能产生高效的解决方案。每个工作的基于 BPM 的流程都只是未来的起点。
James Champy - 人员和流程
当 Mike Hammer 和我在 1992 年出版《公司再造》时,我们理解真正的业务流程变革会对人们产生的影响。我说“真正的”流程变革,是因为管理者们用“再造”这个词来描述任何和所有的公司变革计划。一位被误导的高管告诉我,他的公司不知道如何进行真正的再造;所以它只是裁减了大型部门和业务部门,并期望留下的人会弄清楚如何完成他们的工作。可悲的是,这就是一些公司仍然实践流程再设计的方式:让人们过度劳累和士气低落,而客户体验到糟糕的服务和低劣的质量。