领域驱动设计(2)通用语言
对通用语言的需要
通过前一章的案例,我们认识到由软件专家和领域专家通力合作开发出一个领域的模型是绝对需要的,但是,那种方法通常会由于一些基础交流的障碍而存在难点。
开发人员满脑子都是类、方法、算法、模式,总是想将实际生活中的概念和程序工件做对应。他们希望看到要建立哪些对象类,要如何对对象类之间的关系建模。
他们会按照继承、多态、面向对象的编程等方式去思考,会随时随地这样交谈,这对他们来说这太正常不过了,开发人员就是开发人员。
但是领域专家通常对这一无所知。他们对软件类库、框架、持久化甚至数据库没有什么概念。他们只了解他们特有的专业技能。
在空中交通监控样例中,领域专家知道飞机、路线、海拔、经度、纬度,知道飞机偏离了正常路线,知道飞机的发射。
他们用他们自己的术语讨论这些事情,有时这对于外行来说很难直接理解。
为克服这种交流方式的不同,在建立模型时,我们必须通过沟通来交换对模型和模型中涉及到的元素的想法,应该如何连接它们,哪些是有关的,哪些不是?
在这种层次上的交流对一个成功的项目而言是极为重要的。
如果一个人说了什么事情,其他的人不能理解,或者更糟的是错误理解成其他事情,又有什么机会来保证项目成功呢?
在讨论模型和定义模型时,我们确实需要讲同一种语言。那么是哪种语言呢?开发人员的语言?领域专家的语言?介乎两者之间的语言?
领域驱动设计的一个核心的原则是使用一种基于模型的语言。因为模型是软件满足领域的共同点,它很适合作为这种通用语言的构造基础。
使用模型作为语言的核心骨架。要求团队在进行所有的交流是都使用一致的语言,在代码中也是这样。在共享知识和推敲模型时,团队会使用演讲、文字和图形。
这儿需要确保团队使用的语言在所有的交流形式中看上去都是一致的。因为这个原因,这种语言被称为“通用语言(Ubiquitous Language)”。
通用语言连接起设计中的所有的部分,建立了设计团队良好工作的前提。可能会花费数周乃至数月的时间才能让一个大规模项目的设计成型。
团队成员会发现一些初始的概念是不正确的或者不合适宜,或者发现一些需要考虑并放进总体设计中的新的设计元素。
没有了通用语言,所有的这一切都是不可能的。
这种语言的形成可不是一日之功,它需要做出艰苦卓绝的工作并关注很多方面的内容,才能确保语言的核心元素被发现。
我们需要发现定义领域和模型的那些关键性概念,发现描述它们的相应的用词,并开始使用它们。
它们当中的一些可能很容易被发现,但有些却不能。
通过尝试反映其他可选模型的其他的表述方式,可以消除这个难点。
然后重构代码、重命名类、方法和模型以适应新的模型。
使用我们能够正常理解的普通词汇,化解交谈所使用术语之间的混乱。
领域专家会反对用那些很笨拙的或者不适当的字眼或者结构来传达对领域的理解。
如果领域专家不能理解模型或者语言中的某种内容,那么就如同是说这种内容存在某种错误。
从另一方面讲,开发人员应该留意那些与他们试图呈现在设计中的内容存在二义性或者不一致的部分。
创建通用语言
我们应该如何开始去构建一种语言?看一个假想的软件开发人员和领域专家之间关于空中交通监控项目的对话吧。需要留意粗体的那些词。
开发人员:我们想监控空中交通,应该从哪里开始?
专家:让我们从最基础的开始吧。所有的交通由飞机组成。每架飞机从一个出发点起飞,并在一个目的地点着陆。
开发人员:很容易嘛。在飞行时,飞机会按照驾驶员的意愿选择任何空中线路吗?是不是等于说他们可以决定他们能走哪条路,只要他们能到达终点?
专家:哦不。驾驶员会收到一条他们应该遵照的飞行路线。并且他们必须尽可能地跟那条飞行路线吻合。
开发人员:我会把这条路线考虑成空中的3D 线路。如果我们使用笛卡尔系统坐标,那么一条飞行路线会被简化成一系列3D的点。
专家:我可不这么认为。我们不会这样看待飞行路线的。飞行路线实际上是飞机预期的空中线路在地面上的映射。
飞行路线会穿过一系列地面上的点,而这些点我们可以用经度和纬度来决定。
开发人员:哦,那我们可以称每一个这样的点为一个方位,因为它是地球表面上的一个固定的点。
我们将使用一系列2D 的点来描述线路。顺便说一句,出发点和终点都属于方位。
我们不再会将它们考虑成其他不同的概念。
飞行路线到达终点就如同它到达其他的方位一样。
飞机必须遵照飞行路线,但这是否意味着它可以按照自己的意愿选择飞行高度?
专家:不。飞机在一个特定的时刻的海拔高度也会在飞行计划中有规定。
开发人员:飞行计划?那是什么意思?
专家:在离开机场之前,驾驶员会接到一个详细的飞行计划,包括所有关于这次飞行的信息:飞行路线、巡航高度、巡航速度和飞机的类型甚至机组成员的信息等。
开发人员:噢,飞行计划看起来相当的重要。我们可得把它加到模型中。
开发人员:好多了。当我看到这副图时,我会了解到很多事情。
在监控空中交通时,我们其实并不对飞机本身感兴趣,不管它是白色的还是蓝色的,也不管它是“波音”的还是“空客”的。
我们对它们的“飞行(flight)”感兴趣。这才是我们实际上要跟踪和度量的东西。
我认为我们应该对模型做出改变以保证其正确性。
注意这个团队是如何围绕他们的初始模型讨论空中交通监控领域的,他们逐渐用粗体的词汇建立了一种语言。
也要注意那种语言是如何变更模型的。
然而,在实际生活中像这样的对话太冗长了,人们经常间接地讨论事情,或者深入到非常细节的部分,或者会选择错误的概念。
这会让语言的产生过程非常艰难。
为了解决这点,所有的团队成员应该都意识到需要建立一种通用的语言,并应保持专注核心的部分,在任何需要之时使用这种语言。
我们应该尽可能少地在这种场景中使用我们自己的行话,应该使用通用语言,因为它能帮助我们更清晰更精确地交流。
强烈建议开发人员把这些模型中的主要概念实现到代码中。
可以为Route 写一个类,而另一个应该是Fix。
Fix 类应该从2DPoint 类继承,或者应该包含一个2DPoint 对象作为它的主要的属性。
那依赖于其他的因素,我们会在以后讨论它们。
通过为模型概念建立对应的类,我们在模型和代码之间以及在语言和代码之间做映射。
这非常有帮助,它会让代码更可读,让模型得到完美实现。
代码表现模型会让项目得益,如果代码没有得到适当地设计,在模型变大或代码中发生了变化时,会导致意料之外的结果。
我们已经看到了语言是如何在整个团队中被共享的,也看到了它是如何帮助我们构建知识和创建模型的。
我们应如何使用这些语言呢,只是语言交谈吗?我们已经用图了,还有其他用法吗?文档吗?
有人会说UML很适合用来构建模型,它也真是一种很好的记录关键概念(如类)和表现它们之间的关系的工具。
你可以在画板上画下4到5 个类,写下它们的名字,画出它们自己的关系。
对每个人来说都可以很容易地掌握你的想法,一个某种想法的图形化展现方式很容易被人理解。
每个人立即共享到关于特定主题的相同的愿景,基于此的沟通因此变得简单。
当有新的想法出现时,会修改图以反映概念的变化。
UML图在只涉及少量元素时很有帮助。但UML会像雨后的的蘑菇那样快速增长。
当你的数以百计的类充斥在一张像密西西比河那样的长纸上时,你应该怎么办?
即使是对软件专家而言,它也很难阅读,就更不用说领域专家了。
当它变大时,就会很难理解,一个中等规模项目的类图也会如此。
同时,UML 擅长表现类,它们的属性和相互之间的关系。
但类的行为和约束并不容易表现。为此UML求助于文字,将它们作为注释放在图上。
所以UML不能传达一个模型很重要的两个方面:它所要表现的概念的意义和对象准备做什么。
但那依然很好,因为我们可以增加其他的沟通工具来做这些。
我们可以使用文档。一个明智的沟通模型的方式是创建一些小的图,让每副小图包含模型的一个子集。
这些图会包含若干类以及它们之间的关系。这样就很好地包括了所涉及到的概念中一部分。
然后我们可以向图中添加文本。
文本将解释图所不能表现的行为和约束。每个这样的片断都试图解释领域中的一个重要的方面,类似于一个聚光灯那样只聚焦领域的一个部分。
这些文档甚至有可能是手绘的,因为这传递了一种感觉:它们是临时的,可能不久就要发生变化。
这种感觉是对的,因为模型从一开始到它达到比较稳定的状态会发生很多次变化。
努力去创建一个反映整体模型的大图可能会很有诱惑力,但是,大部分时间像这样的图很有可能不能组合在一起。
此外,即使你成功地制成了这样的统一的大图,它也会非常混乱,并不能传递比小图的集合更好的理解。
冗长的文档,会让我们花费很多的时间来书写它们,有可能在完成之前它们就已经作废了。
文档必须跟模型同步。陈旧的文档、使用了错误的语言、或者不能如实反映模型,都是没有什么用的。应尽可能的避免这样文档。
也可能使用代码来交流,这个方法被XP 社区广泛倡导。优良的代码也具有很好的可交流性。
尽管用方法表现行为是清楚的,但方法体也能跟方法名一样清楚吗?可以为它们提供一个测试断言,但是
变量名和整体的代码结构该怎么办?它们能大声地、清楚地讲出整个故事吗?
代码能够完成正确的功能但不一定得表达出正确的事情。将模型写入代码是非常困难的。
在设计中还有其他沟通的方式,本书不想全部描述它们。
有一个件事情是非常清楚的:由软件架构师、开发人员和领域专家构成的开发团队,需要一种语言来统一它们的行动,以帮助它们创建一个模型,并使用代码来表现模型。
posted on 2011-12-19 14:04 zhouyonghua0520 阅读(562) 评论(0) 编辑 收藏 举报