《领域驱动设计》读书笔记(一):运用领域模型

《领域驱动设计》读书笔记(一):运用领域模型

控制复杂性的关键是有一个好的领域模型,这个模型不应该仅仅停留在领域的表面,而是要透过表象抓住领域的实质结构,从而为软件开发人员提供他们所需的支持。

在领域建模过程中不应将概念与实现割裂开来。

概念与实现密不可分的最主要原因在于,领域模型的最大价值是它提供了一种通用语言,这种语言是将领域专家和技术人员联系在一起的纽带。

领域模型并不是按照“先建模,后实现”这个次序来工作的。

真正强大的领域模型是随着时间演进的,即使是最有经验的建模人员也往往发现他们是在系统的初始版本完成之后才有了最好的想法。

既品尝过成功的美酒,也体验过失败的沮丧。

前言

真正决定软件复杂性的是设计方法。

很多应用程序最主要的复杂性并不在技术上,而是来自领域本身、用户的活动或业务。

领域驱动设计是一种思维方式,也是一组优先任务,它旨在加速那些必须处理复杂领域的软件项目的开发。

领域驱动设计的实质就是消化吸收大量知识,最后产生一个反映深层次领域知识并聚焦于关键概念的模型。

极端的简约主义是解救那些过度追求设计的执迷者的良方。

实际上, XP最适合那些对设计的感觉很敏锐的开发人员。 XP过程假定人们可以通过重构来改进设计,而且可以经常、快速地完成重构。

首先需要深入研究模型,然后基于最初的(可能是不成熟的)模型实现一个初始设计,再反复改进这个设计。每次团队对领域有了新的理解之后,都需要对模型进行改进,使模型反映出更丰富的知识,而且必须对代码进行重构,以便反映出更深刻的模型,并使应用程序可以充分利用模型的潜力。 第一部分 运用领域模型

模型是一种简化。它是对现实的解释——把与解决问题密切相关的方面抽象出来,而忽略无关的细节。

模型正是解决此类信息超载问题的工具。模型这种知识形式对知识进行了选择性的简化和有意的结构化。

领域模型并非某种特殊的图,而是这种图所要传达的思想。

对这类知识严格的组织且有选择的抽象。

领域建模并不是要尽可能建立一个符合“现实”的模型。

建模更像是制作电影——出于某种目的而概括地反映现实。

在领域驱动的设计中,3个基本用途决定了模型的选择。

  1. 模型和设计的核心互相影响。

  2. 模型是团队所有成员使用的通用语言的中枢。

  3. 模型是浓缩的知识。

软件的核心是其为用户解决领域相关的问题的能力。所有其他特性,不管有多么重要,都要服务于这个基本目的。

第 1 章 消化知识

有效建模的要素:

  1. 模型和实现的绑定。

  2. 建立了一种基于模型的语言。

  3. 开发一个蕴含丰富知识的模型。

  4. 提炼模型。

  5. 头脑风暴和实验。

语言和草图,再加上头脑风暴活动,将我们的讨论变成“模型实验室”,在这些讨论中可以演示、尝试和判断上百种变化。

高效的领域建模人员是知识的消化者。

领域模型的不断精化迫使开发人员学习重要的业务原理,而不是机械地进行功能开发。领域专家被迫提炼自己已知道的重要知识的过程往往也是完善其自身理解的过程,而且他们会渐渐理解软件项目所必需的概念严谨性。

模型永远都不会是完美的,因为它是一个不断演化完善的过程。

高效率的团队需要有意识地积累知识,并持续学习。

业务活动和规则如同所涉及的实体一样,都是领域的核心,任何领域都有各种类别的概念。知识消化所产生的模型能够反映出对知识的深层理解。

当我们的建模不再局限于寻找实体和值对象时,我们才能充分吸取知识,因为业务规则之间可能会存在不一致。

知识消化是一种探索,它永无止境。

第 2 章 交流与语言的使用

领域模型可成为软件项目通用语言的核心。

模式:Ubiquitous Language

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

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

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

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

Ubiquitous Language(通用语言)的词汇包括类和主要操作的名称。

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

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

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

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

改善模型的最佳方式之一就是通过对话来研究,试着大声说出可能的模型变化中的各种结构。

讨论系统时要结合模型。使用模型元素及其交互来大声描述场景,并且按照模型允许的方式将各种概念结合到一起。找到更简单的表达方式来讲出你要讲的话,然后将这些新的想法应用到图和代码中。

如果连经验丰富的领域专家都不能理解模型,那么模型一定出了什么问题。

领域专家可以使用模型语言来编写用例,甚至可以直接利用模型来具体说明验收测试。

UML图无法传达模型的两个最重要的方面,一个方面是模型所表示的概念的意义,另一方面是对象应该做哪些事情。

简洁的小图能够很好地实现这些目标,而涵盖整个对象模型的综合性大图反而失去了沟通或解释能力,因为它们将读者淹没在大量细节之中,加之这些图也缺乏目的性。

应使用简化的图,图中只包含对象模型的重要概念——这些部分对于理解设计至关重要。

设计的重要细节应该在代码中体现出来。良好的实现应该是透明的,清楚地展示其背后的模型(

务必要记住模型不是图。图的目的是帮助表达和解释模型。

将代码作为设计文档也有局限性。它可能会把读代码的人淹没在细节中。

文档不应再重复表示代码已经明确表达出的内容。

当编程语言无法直接明了地实现概念时,文档可以澄清设计意图。

设计文档的最大价值在于解释模型的概念,帮助在代码的细节中指引方向,或许还可以帮助人们深入了解模型预期的使用风格。

解释性模型不必是对象模型,而且最好不是。

第 3 章 绑定模型和实现

领域驱动设计要求模型不仅能够指导早期的分析工作,还应该成为设计的基础。

模式:Model-Driven Design

严格按照基础模型来编写代码,能够使代码更好地表达设计含义,并且使模型与实际的系统相契合。

在创建分析模型时并没有考虑程序设计的问题,因此分析模型很有可能无法满足程序设计的需求。

如果整个程序设计或者其核心部分没有与领域模型相对应,那么这个模型就是没有价值的,软件的正确性也值得怀疑。同时,模型和设计功能之间过于复杂的对应关系也是难于理解的,在实际项目中,当设计改变时也无法维护这种关系。若分析与和设计之间产生严重分歧,那么在分析和设计活动中所获得的知识就无法彼此共享。

分析工作一定要抓住领域内的基础概念,并且用易于理解和易于表达的方式描述出来。设计工作则需要指定一套可以由项目中使用的编程工具创建的组件,使项目可以在目标部署环境中高效运行,并且能够正确解决应用程序所遇到的问题。

Model-Driven Design(模型驱动设计)不再将分析模型和程序设计分离开,而是寻求一种能够满足这两方面需求的单一模型。

软件系统各个部分的设计应该忠实地反映领域模型,以便体现出这二者之间的明确对应关系。我们应该反复检查并修改模型,以便软件可以更加自然地实现模型,即使想让模型反映出更深层次的领域概念时也应如此。我们需要的模型不但应该满足这两种需求,还应该能够支持健壮的 Ubiquitous Language(通用语言)。

从模型中获取用于程序设计和基本职责分配的术语。让程序代码成为模型的表达,代码的改变可能会是模型的改变。而其影响势必要波及接下来相应的项目活动。完全依赖模型的实现通常需要支持建模范式的软件开发工具和语言,比如面向对象的编程。

面向对象编程之所以功能强大,是因为它基于建模范式,并且为模型构造提供了实现方式。

需要反复研究领域知识,不断重构模型,才能将领域中重要的概念提炼成简单而清晰的模型。

Model-Driven Design 要求只使用一个模型。

模式:Hands-On Modeler

其一,模型的一些意图在其传递过程中丢失了。

第二个原因是模型与程序实现及技术互相影响,而我无法直接获得这种反馈。

如果编写代码的人员认为自己没必要对模型负责,或者不知道如何让模型为应用程序服务,那么这个模型就和程序没有任何关联。如果开发人员没有意识到改变代码就意味着改变模型,那么他们对程序的重构不但不会增强模型的作用,反而还会削弱它的效果。同样,如果建模人员不参与到程序实现的过程中,那么对程序实现的约束就没有切身的感受,即使有,也会很快忘记。 Model-Driven Design 的两个基本要素(即模型要支持有效的实现并抽象出关键的领域知识)已经失去了一个,最终模型将变得不再实用。最后一点,如果分工阻断了设计人员与开发人员之间的协作,使他们无法转达实现 Model-Driven Design 的种种细节,那么经验丰富的设计人员则不能将自己的知识和技术传递给开发人员。

整体设计的有效性有几个非常敏感的影响因素——那就是细粒度的设计和实现决策的质量和一致性。

任何参与建模的技术人员,不管在项目中的主要职责是什么,都必须花时间了解代码。任何负责修改代码的人员则必须学会用代码来表达模型。每一个开发人员都必须不同程度地参与模型讨论并且与领域专家保持联系。参与不同工作的人都必须有意识地通过 Ubiquitous Language 与接触代码的人及时交换关于模型的想法。

Model-Driven Design 将模型和程序实现过程紧密结合。 Ubiquitous Language 则成为开发人员、领域专家和软件产品之间传递信息的渠道。