《领域驱动设计:软件核心复杂性应对之道(修订版)》—第2章 2.4节文档和图

  1. 云栖社区>
  2. 博客>
  3. 正文

《领域驱动设计:软件核心复杂性应对之道(修订版)》—第2章 2.4节文档和图

异步社区 2017-05-02 10:47:00 浏览1138
展开阅读全文

本节书摘来自异步社区《领域驱动设计:软件核心复杂性应对之道(修订版)》一书中的第2章,第2.4节文档和图,作者【美】埃里克•埃文斯(Eric Evans), 马利伟 , 万龙,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.4 文档和图
每当我参加讨论软件设计的会议时,如果不在白板或画板上画图,我就很难讨论下去。我画的大部分是UML图,主要以类图和对象交互图为主。

有些人天生是视觉动物,图可以帮助人们掌握某些类型的信息。UML图在传达对象之间的关系上真是游刃有余,而且也很擅长表现交互。但它们却无法给出这些对象的概念定义。在会议中,我会一边画图一边用语言来丰富它们的意义,或者在与其他参与者讨论时进行解释。

简单、非正式的UML图能够维系整个讨论。绘制一幅包含当前问题最关键的3~5个对象的图,这样每个人都可以集中注意力。所有人就对象关系会达成一致的认识,更重要的是,他们将使用相同的对象名称。如此,口头讨论会更加高效。当人们尝试不同的想法时,图也随之改变,草图在某种程度上可以反映讨论的变化,这是讨论中真正重要的部分。毕竟,UML就是统一建模语言。

当人们必须通过UML图表示整个模型或设计时,麻烦也随之而来。很多对象模型图在某些方面过于细致,同时在某些方面又有很多遗漏。说它们过于细致是因为人们认为必须将所有要编码的对象都放到建模工具中。而细节过多的结果是“只见树木,不见森林”。

尽管存在所有这些细节,但属性和关系只是对象模型的一部分。这些对象的行为以及这些对象上的约束就不那么容易表示了。对象交互图可以阐明设计中的一些复杂之处,但却无法用这种方式来展示大量的交互,就是工作量太大了,既要制作图,还要学习这些图。而且交互图也只能暗示出模型的目的。要想把约束和断言包括进来,需要在UML图中使用文本,这些文本用括号括起来,插入到图中。

35
操作名称可能会暗示出对象的行为职责,对象交互图(或序列图)中也会隐含地展示出这些职责,但无法直接表述。因此,这项任务就要靠补充文本或对话来完成。换言之,UML图无法传达模型的两个最重要的方面,一个方面是模型所表示的概念的意义,另一方面是对象应该做哪些事情。但是,这并不是大问题,因为通过仔细地使用语言(英语、西班牙语或其他任何一种语言)就可以很好地完成这项任务。

UML也不是一种十分令人满意的编程语言。我从未见过有人使用建模工具的代码生成功能达到了预期目的。如果UML的能力无法满足需要,通常人们就不得不忽略模型最关键的部分,因为有些规则并不适合用线框图来表示。当然,代码生成器也无法使用上面所说的那些文本注释。如果确实能使用UML这样的绘图语言来编写可执行程序,那么UML图就会退化为程序本身的另一种视图,这样,“模型”的真正含义就丢失了。如果使用UML作为实现语言,则仍然需要利用其他手段来表达模型的确切含义。

图是一种沟通和解释手段,它们可以促进头脑风暴。简洁的小图能够很好地实现这些目标,而涵盖整个对象模型的综合性大图反而失去了沟通或解释能力,因为它们将读者淹没在大量细节之中,加之这些图也缺乏目的性。鉴于此,我们应避免使用包罗万象的对象模型图,甚至不能使用包含所有细节的UML数据存储库。相反,应使用简化的图,图中只包含对象模型的重要概 念——这些部分对于理解设计至关重要。本书中的图都是我在项目中使用过比较典型的图。它们很简单,而且具有很强的解释能力,在澄清一些要点时,还使用了一些非标准的符号。它们显示了设计约束,但它们不是面面俱到的设计规范。它们只体现了思想纲要。

36
设计的重要细节应该在代码中体现出来。良好的实现应该是透明的,清楚地展示其背后的模型(下一章及本书其他许多章节的主题就是阐述如何做到这一点)。互为补充的图和文档能够引导人们将注意力放在核心要点上。自然语言的讨论可以填补含义上的细微差别。这就是为什么我喜欢把典型的UML使用方法颠倒过来的原因。通常的用法是以图为主,辅以文本注释;而我更愿意以文本为主,用精心挑选的简化图作为说明。

务必要记住模型不是图。图的目的是帮助表达和解释模型。代码可以充当设计细节的存储库。书写良好的Java代码与UML具有同样的表达能力。经过仔细选择和构造的图可以帮助人们集中注意力,并起到指导作用,当然前提条件是不能强制用图来表示全部模型或设计,因为这样会削弱图的清晰表达的能力。

2.4.1 书面设计文档
口头交流可以解释代码的含义,因此可作为代码精确性和细节的补充。虽然交谈对于将人们与模型联系起来是至关重要的,但书面文档也是必不可少的,任何规模的团队都需要它来提供稳定和共享的交流。但要想编写出能够帮助团队开发出好软件的书面文档却是一个不小的挑战。

一旦文档的形式变得一成不变,往往会从项目进展流程中脱离出来。它会跟不上代码或项目语言的演变。

书面文档有很多编写方法。本书第四部分将介绍几种满足特定需要的具体文档,但不会列出项目需要使用的所有文档,而是给出两条用于评估文档的总体原则。

文档应作为代码和口头交流的补充
每种敏捷过程在编写文档方面都有自己的理念。极限编程主张完全不使用(多余的)设计文档,而让代码解释自己。实际运行的代码不会说谎,而其他文档则不然。运行代码所产生的行为是明确的。

37
极限编程只关注对程序及可执行测试起作用的因素。由于为代码添加的注释并不影响程序的行为,因此它们往往无法与当前代码及其模型保持同步。外部文档和图也不会影响程序的行为,因此它们也无法保持同步。另一方面,口头交流和临时在白板上画的图不会长久保留而产生混淆。依赖代码作为交流媒介可以促使开发人员保持代码的整洁和透明。

然而,将代码作为设计文档也有局限性。它可能会把读代码的人淹没在细节中。尽管代码的行为是非常明确的,但这并不意味着其行为是显而易见的。而且行为背后的意义可能难以表达。换言之,只用代码做文档与使用大而全的UML图面临着差不多相同的基本问题。当然,团队进行大量的口头交流能够为代码提供上下文和指导,但是,口头交流很短暂,而且范围很小。此外,开发人员并不是唯一需要理解模型的人。

文档不应再重复表示代码已经明确表达出的内容。代码已经含有各个细节,它本身就是一种精确的程序行为说明。

其他文档应该着重说明含义,以便使人们能够深入理解大尺度结构,并将注意力集中在核心元素上。当编程语言无法直接明了地实现概念时,文档可以澄清设计意图。我们应该把书面文档作为代码和口头讨论的补充。

文档应当鲜活并保持最新
我在为模型编写书面文档时,会仔细选择一个小的模型子集来画图,然后让文字放置在这些图周围。我用文字定义类及其职责,并且像自然语言那样把它们限定在一个语义上下文中。而图显示了在将概念形式化和简化为对象模型的过程中所做的一些选择。这些图可以随意一些,甚至是手绘的。手绘图除了节省工作量,也让人们一看就知道它们是不正式、临时的。这些优点都非常有利于交流,因为它们适用于我们的模型思想。

38
设计文档的最大价值在于解释模型的概念,帮助在代码的细节中指引方向,或许还可以帮助人们深入了解模型预期的使用风格。根据不同的团队理念,整个设计文档可能会十分简单,如只是贴在墙上的一组草图,也可能会非常详尽。

文档必须深入到各种项目活动中去。判断是否做到这一点的最简单方法,是观察文档与Ubiquitous Language之间的交互。文档是用人们(当前)在项目上讲的语言编写的吗?它是用嵌入到代码中的语言编写的吗?

注意听Ubiquitous Language,观察它是如何变化的。如果设计文档中使用的术语不再出现在讨论和代码中,那么文档就没有起到它的作用。或许是文档太大或太复杂了,或许是它没有关注足够重要的主题。人们要么不阅读文档,要么觉得它索然无味。如果文档对Ubiquitous Language没有影响,那么一定是出问题了。

相反,我们会注意到Ubiquitous Language随着文档渐渐过时而自然地改变。显然,要么人们不再关心文档,要么认为它不重要而不再去更新它。这时可以将它作为历史文件安全地归档,如果继续使用这样的文档可能会产生混淆并损害项目。如果文档不再担负重要的作用,那么纯粹靠意志和纪律保持其更新就是浪费精力。

Ubiquitous Language可以使其他文档(如需求规格说明)更简洁和明确。当领域模型反映了与业务最相关的知识时,应用程序的需求成为该模型内部的场景,而Ubiquitous Language可直接用Model-Driven Design(模型驱动设计)的方式描述此类场景(参见第3章)。结果就是规格说明的编写更简单,因为它们不必传达模型背后隐含的业务知识。

39
通过将文档减至最少,并且主要用它来补充代码和口头交流,就可以避免文档与项目脱节。根据Ubiquitous Language及其演变来选择那些需要保持更新并与项目活动紧密交互的文档。

2.4.2 完全依赖可执行代码的情况
现在,我们来考查一下XP社区和其他一些人为何选择几乎完全依赖可执行代码及其测试。本书主要讨论了如何通过Model-Driven Design使代码表达出设计的含义(参见第3章)。良好的代码具有很强的表达能力,但它所传递的信息不能确保是准确的。一段代码所产生的实际行为是不会改变的。但是,方法名称可能会有歧义、会产生误导或者因为已经过时而无法表示方法的本质含义。测试中的断言是严格的,但变量和代码组织方式所表达出来的意思未必严格。好的编程风格会尽力使这种联系直接化,但其仍然主要靠开发人员的自律。编码时需要一丝不苟的态度,只有这样才能编写出“言行全部正确”的代码。

消除这些差异是诸如声明式设计(参见第10章)这样的方法的最大优点,在这类方法中,程序元素用途的陈述决定了它在程序中的实际行为。从UML生成程序的部分动机就来源于此,虽然目前看来这通常不会得到好的结果。

尽管代码可能会产生误导,但它仍然比其他文档更基础。要想利用当前的标准技术使代码所传达的消息与它的行为和意图保持一致,需要纪律和思考设计的特定方式(第三部分将详细讨论这些问题)。要有效地交流,代码必须基于在编写需求时所使用的同一种语言,也就是开发人员之间、开发人员与领域专家之间进行讨论时所使用的语言。

网友评论

登录后评论
0/500
评论