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

第2章 交流与语言的使用
领域驱动设计:软件核心复杂性应对之道(修订版)
领域模型可成为软件项目通用语言的核心。该模型是一组得自于项目人员头脑中的概念,以及反映了领域深层含义的术语和关系。这些术语和相互关系提供了模型语言的语义,虽然语言是为领域量身定制的,但就技术开发而言,其依然足够精确。正是这条至关重要的纽带,将模型与开发活动结合在一起,并使模型与代码紧密绑定。

这种基于模型的交流并不局限于UML(统一建模语言)图。为了最有效地使用模型,需要充分利用各种交流手段。基于模型的交流提高了书面文档的效用,也提高了敏捷过程中再度强调的非正式图表和交谈的效用。它还通过代码本身及对应的测试促进了交流。

在项目中,语言的使用很微妙,但却至关重要……

23
2.1 模式:Ubiquitous Language
首先写下一个句子,

然后将它分成小段,

再将它们打乱并重新排序。

仿佛是巧合一样,

短语的顺序对意思完全没有影响。
——Lewis Carroll, “Poeta Fit, Non Nascitur”

要想创建一种灵活的、蕴含丰富知识的设计,需要一种通用的、共享的团队语言,以及对语言不断的试验——然而,软件项目上很少出现这样的试验。

未标题-1

虽然领域专家对软件开发的技术术语所知有限,但他们能熟练使用自己领域的术语——可能还具有各种不同的风格。另一方面,开发人员可能会用一些描述性的、功能性的术语来理解和讨论系统,而这些术语并不具备领域专家的语言所要传达的意思。或者,开发人员可能会创建一些用于支持设计的抽象,但领域专家无法理解这些抽象。负责处理问题不同部分的开发人员可能会开发出各自不同的设计概念以及描述领域的方式。

由于语言上存在鸿沟,领域专家们只能模糊地描述他们想要的东西。开发人员虽然努力去理解一个自己不熟悉的领域,但也只能形成模糊的认识。虽然少数团队成员会设法掌握这两种语言,但他们会变成信息流的瓶颈,并且他们的翻译也不准确。

在一个没有公共语言的项目上,开发人员不得不为领域专家做翻译。而领域专家需要充当开发人员与其他领域专家之间的翻译。甚至开发人员之间还需要互相翻译。这些翻译使模型概念变得混淆,而这会导致有害的代码重构。这种间接的沟通掩盖了分裂的形成——不同的团队成员使用不同的术语而尚不自知。由于软件的各个部分不能够浑然一体,因此这就导致无法开发出可靠的软件(参见第14章)。翻译工作导致各类促进深入理解模型的知识和想法无法结合到一起。

24
如果语言支离破碎,项目必将遭遇严重问题。领域专家使用他们自己的术语,而技术团队所使用的语言则经过调整,以便从设计角度讨论领域。

日常讨论所使用的术语与代码(软件项目的最重要产品)中使用的术语不一致。甚至同一个人在讲话和写东西时使用的语言也不一致,这导致的后果是,对领域的深刻表述常常稍纵即逝,根本无法记录到代码或文档中。

翻译使得沟通不畅,并削弱了知识消化。

然而任何一方的语言都不能成为公共语言,因为它们无法满足所有的需求。

所有翻译的开销,连带着误解的风险,成本实在太高了。项目需要一种公共语言,这种语言要比所有语言的最小公分母健壮得多。通过团队的一致努力,领域模型可以成为这种公共语言的核心,同时将团队沟通与软件实现紧密联系到一起。该语言将存在于团队工作中的方方面面。

Ubiquitous Language(通用语言)的词汇包括类和主要操作的名称。语言中的术语,有些用来讨论模型中已经明确的规则,还有一些则来自施加于模型上的高级组织原则(如第14章和第16章要讨论的Context Map和大型结构)。最后,团队常常应用于领域模型的模式名称也使这种语言更为丰富。

模型之间的关系成为所有语言都具有的组合规则。词和短语的意义反映了模型的语义。

开发人员应该使用基于模型的语言来描述系统中的工件、任务和功能。这个模型应该为开发人员和领域专家提供一种用于相互交流的语言,而且领域专家还应该使用这种语言来讨论需求、开发计划和特性。语言使用得越普遍,理解进行得就越顺畅。

至少,我们应该将它作为目标。但最初,模型可能不太好,因此无法很好地履行这些职责。它可能不会像领域的专业术语那样具有丰富的语义。但我们又不能直接使用那些术语,因为它们有歧义和矛盾。模型可能缺乏开发人员在代码中所创建的更为微妙和灵活的特性,这要么是因为开发人员认为模型不必具备这些特性,要么是因为编码风格是过程式的,只能隐含地表达领域概念。

25
尽管模型和基于模型的语言之间的次序像是循环论证,但是,能够产生更有用模型的知识消化过程依赖于团队投身于基于模型的语言。持续使用Ubiquitous Language可以暴露模型中存在的缺点,这样团队就可以尝试并替换不恰当的术语或组合。当在语言中发现缺失时,新的词语将被引入到讨论中。这些语言上的更改也会在领域模型中引起相应的更改,并促使团队更新类图并重命名代码中的类和方法,当术语的意义改变时,甚至会导致行为也发生改变。

通过在实现的过程中使用这种语言,开发人员能够指出不准确和矛盾之处,并和领域专家一起找到有效的替代方案。

当然,为了解释和给出更广泛的上下文,领域专家的语言会超出Ubiquitous Language的范围。但在模型应对的范围内,他们应该使用Ubiquitous Language,并在发现不合适、不完整或错误之处后要引起注意。通过大量使用基于模型的语言,并且不达流畅绝不罢休,我们可以逐步得到一个完整的、易于理解的模型,它由简单元素组成,并通过组合这些简单元素表达复杂的概念。

因此:

将模型作为语言的支柱。确保团队在内部的所有交流中以及代码中坚持使用这种语言。在画图、写东西,特别是讲话时也要使用这种语言。

通过尝试不同的表示方法(它们反映了备选模型)来消除难点。然后重构代码,重新命名类、方法和模块,以便与新模型保持一致。解决交谈中的术语混淆问题,就像我们对普通词汇形成一致的理解一样。

26
要认识到,Ubiquitous Language的更改就是对模型的更改。

领域专家应该抵制不合适或无法充分表达领域理解的术语或结构,开发人员应该密切关注那些将会妨碍设计的有歧义和不一致的地方。

有了Ubiquitous Language,模型就不仅仅是一个设计工件了。它成为开发人员和领域专家共同完成的每项工作中不可或缺的部分。语言以动态形式传递知识。使用这种语言进行讨论能够呈现图和代码背后的真实含义。

未标题-1

我们在这里讨论的Ubiquitous Language假设只有一个模型在起作用。第14章将讨论不同模型(和语言)的共存,以及如何防止模型分裂。

Ubiquitous Language是那些以非代码形式呈现的设计的主要载体,这些包括把整个系统组织在一起的大尺度结构(参见第16章)、定义了不同系统和模型之间关系的限界上下文(参见第14章),以及在模型和设计中使用的其他模式。

示例 制定货运路线

下面这两段对话有着微妙但重要的差别。在每个对话场景中,注意观察讲话者有多少内容是谈论软件的业务功能,有多少内容是从技术上谈论软件的工作机理的。用户和开发人员用的是同一种语言吗?它的表达是否丰富,足以应对应用程序功能的讨论?

■场景1:最小化的领域抽象■


用户:那么,当更改清关(customs clearance)地点时①,需要重新制定整个路线计划啰。

开发人员:是的。我们将从货运表(shipment table)中删除所有与该货物id相关联的行,然后将出发地、目的地和新的清关地点传递给Routing Service,它会重新填充货运表。Cargo中必须设立一个布尔值,用于指示货运表中是否有数据。

用户:删除行?好,就按你说的做。但是,如果先前根本没有指定清关地点,也需要这么做吗?

开发人员:是的,无论何时更改了出发地、目的地或清关地点(或是第一次输入),都将检查是否已经有货运数据,如果有,则删除它们,然后由Routing Service重新生成数据。

用户:当然,如果原有的清关数据碰巧是正确的,我们就不需要这样做了。

开发人员:哦,没问题。但让Routing Service每次重新加载或卸载数据会更容易些。

用户:是的,但为新航线制定所有支持计划的工作量很大,因此,除非非改不可,我们一般不想更改航线。
28
开发人员:哦,好的,当第一次输入清关地点时,我们需要查询表格,找到以前的清关地点,然后与新的清关地点进行比较,从而判断是否需要重做。

用户:这个处理不必考虑出发地和目的地,因为航线在此总要变更。

开发人员:好的,我明白了。
■场景2:用领域模型进行讨论 ■


用户:那么,当更改清关地点时,需要重新制定整个路线计划啰。

开发人员:是的。当更改Route Specification(路线说明)的任意属性时,都将删除原有的Itinerary(航线),并要求Routing Service(路线服务)基于新的Route Specification生成一个新的Itinerary。

用户:如果先前根本没有指定清关地点,也需要这么做吗?

开发人员:是的,无论何时更改了Route Spec的任何属性,都将重新生成Itinerary。这也包括第一次输入某些属性。
29
用户:当然,如果原有的清关数据碰巧是正确的,我们就不需要这样做了。

开发人员:哦,没问题。但让Routing Service每次重新生成一个Itinerary会更容易些。

用户:是的,但为新航线制定所有支持计划的工作量很大,因此,除非非改不可,我们一般不想更改路线。

开发人员:哦。那么需要在Route Specification添加一些功能。这样,当更改Route Specification中的属性时,查看Itinerary是否仍满足Specification。如果不满足,则需要由Routing Service重新生成Itinerary。

用户:这一点不必考虑出发地和目的地,因为Itinerary在此总是要变更的。

开发人员:好的,但每次只做比较就简单多了。只有当不满足Route Specification时,才重新生成Itinerary。

第二段对话表达了领域专家的更多意图。在这两段对话中,用户都使用了“itinerary”这个词,但在第二段中它是一个对象,这使得双方可以更准确、具体地进行讨论。他们明确讨论了“route specification”,而不是每次都通过属性和过程来描述它。

这两段对话有意使用了相似的结构。实际上,第一段对话显得更啰嗦,对话双方需要不断对应用程序的特性和表达不清的地方进行解释。第二段对话使用了基于领域模型的术语,因此讨论更简洁。

《领域驱动设计:软件核心复杂性应对之道(修订版)》—第2章 2.1节模式:Ubiquitous Language...相关推荐

  1. 领域驱动设计:软件核心复杂性应对之道_人人都可以领域驱动设计(一)

    最近几年,领域驱动设计(Domain-Driven Design,DDD)这个术语越来越多地出现在软件工程师的视野里.对DDD不熟悉的人可能会觉得它是软件领域里的一个新的概念,但是实际上,Eric E ...

  2. 解读《领域驱动设计 软件核心复杂性应对之道》(一)

    最近学习了两遍<领域驱动设计 软件核心复杂性应对之道>.这本书是2000年出头由一个老外写的.然后经过了国人翻译. 2000年出头,技术架构还没有现在这么多好用的工具,也没有云原生的概念. ...

  3. 领域驱动设计 软件核心复杂性应对之道_DDD - 领域驱动设计对软件复杂度的应对(上)...

    不管是因为规模与结构制造的理解力障碍,还是因为变化带来的预测能力问题,最终的决定因素还是因为需求.Eric Evans 认为"很多应用程序最主要的复杂性并不在技术上,而是来自领域本身.用户的 ...

  4. 《领域驱动设计-软件核心复杂性应对之道》阅读笔记(二)

    第二部分 模型驱动设计的构造块 第4章 分离领域 4.1模式:LAYERED ARCHITECTURE 在面向对象的程序中,常常会在业务对象中直接写入用户界面.数据库访问等支持代码.而一些业务逻辑则会 ...

  5. 领域驱动设计_软件核心复杂性应对之道

    领域驱动设计_软件核心复杂性应对之道 转载于:https://www.cnblogs.com/MarvinGeng/archive/2013/02/21/2920968.html

  6. 领域驱动设计:软件核心复杂性应对之道

    http://vdisk.weibo.com/s/AbB5G02cEZ-Zo 转载于:https://www.cnblogs.com/dyh-air/p/7774955.html

  7. DDD 洋葱架构才是 yyds!阿里大牛手记(DDD)领域驱动设计应对之道

    虽然身为架构师,设计一个高质量的架构依然是复杂与困难的. 简单来说,动用大量的资源只为了一套优质的三高架构并不正确,而是该在了解当前业务现状的情况下,创造出灵活.可维护.健硕能成长的. 就拿近两年程序 ...

  8. DDD洋葱架构才是 yyds,阿里架构师手记(DDD)领域驱动设计应对之道

    虽然身为架构师,设计一个高质量的架构依然是复杂与困难的. 简单来说,动用大量的资源只为了一套优质的三高架构并不正确,而是该在了解当前业务现状的情况下,创造出灵活.可维护.健硕能成长的. 就拿近两年程序 ...

  9. python 全栈开发,Day116(可迭代对象,type创建动态类,偏函数,面向对象的封装,获取外键数据,组合搜索,领域驱动设计(DDD))...

    昨日内容回顾 1. 三个类 ChangeList,封装列表页面需要的所有数据.StarkConfig,生成URL和视图对应关系 + 默认配置 AdminSite,用于保存 数据库类 和 处理该类的对象 ...

最新文章

  1. android bundle传递list对象集合,如何从android中的firebase中检索List对象
  2. UGUI全面实践教程
  3. 开启 J2EE(七)— Model1、Model2和三层架构的演变
  4. pandas 处理时间戳数据
  5. mysql max connects_mysql max_connections 总是 4190
  6. python计算某年某月多少天_Python编程实现输入某年某月某日计算出这一天是该年第几天的方法...
  7. 前端学习(3302):类组件父组件和子组件createRef
  8. 考研复试考java_2019考研复试经验帖:过来人谈5件“小事”
  9. Linux命令基本格式(详解版)
  10. UTF-8 Everywhere
  11. 获取目录文件.bat
  12. 父子/父孙传参(Provide/inject方式)
  13. 前端自动化构建工具之webpack入门——简单入门
  14. [翻译]Hystrix wiki–How it Works
  15. hyperledger的个人分享
  16. win7_32下编译FFmpeg
  17. mapper的更多细节,日志配置、核心文件的配置等
  18. matlab取整函数与取余函数
  19. cad页面布局快捷键_cad布局窗口快捷键
  20. Linux 系统字体安装

热门文章

  1. linux uvc 支持的设备,摄像头是否支持uvc
  2. 用于生成随机数的python标准库模块是_17 Python 标准库之 random 模块 - Python 进阶应用教程...
  3. 电脑卡顿不流畅怎么解决_使命召唤17画面卡顿怎么办-使命召唤17画面卡顿解决方法...
  4. mysql8.11安装_MySQL-mysql 8.0.11安装教程
  5. oracle中间件微信公众号,对TP5.1中间件融合微信公众号代码的优化
  6. h5打开麦克风权限录音_MAC录屏没有声音?如何在苹果电脑MACBOOK上录音录屏
  7. Jenkins+Pipeline+Docker部署SpringBoot项目到远程服务器
  8. 如何将代码优雅的放在WORD文档中?
  9. 对于来自范兵提供光电检测带模块解析
  10. 如何实现远程控制你的电脑? 网穿软件