从此
📄文章 #️⃣专题 🌐酷站 👨‍💻技术 📺 📱

🏠 » 📄文章 » 内容

 欢迎来访!

架构师入门 领域驱动设计DDD

🕗2022-12-02👁️7

  模型被用来描述人们所关注的现实或想法的某个方面。模型是一种简化。它是对现实的解释 —— 把与解决问题密切相关的方面抽象出来,而忽略无关的细节。

 

  每个软件程序是为了执行用户的某项活动,或是满足客户的某种需求。这些用户应用软件的问题区域就是软件的领域

  一些领域涉及物质世界,例如,机票预定程序的领域中包括飞机乘客。有些领域则是无形的,例如,会计程序的金融领域。

 

  为了创建真正能为用户所用的软件,开发团队必须运用一整套与这些活动有关的知识体系。所需知识的广度可能令人望而生畏,庞大复杂的信息也可能超乎想象。模型正是解决此类信息超载问题的工具。模型这种知识形式对于知识进行了选择性的简化和有意的结构化。适当的模型可以使人理解信息的意义,并专注于问题。

 

  领域模型并非某种特殊的图,而是这种所要传达的思想。它绝不单单是领域专家头脑中的知识,而是对这类知识严格的组织且有选择的抽象

  领域模型并不是要尽可能建立一个符合“现实”的模型。即使是对具体、真实世界中的事物进行建模,所得到的模型也不过是对事物的一种模拟。出于某种目的概括地反应现实。

 

  模型在领域驱动设计中的作用

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

  (1)模型和设计的核心互相影响。正是模型与实现之间的紧密联系才使模型变得有用,并确保我们在模型中所进行的分析能够转化为最终产品(即一个可运行的程序)。

  (2)模型是团队所有成员使用的通用语言的中枢。由于模型与实现之间的关联,开发人员可以使用语言来讨论程序。可以在无需翻译的情况下与领域专家进行沟通。

  (3)模型是浓缩的知识。模型是团队一致认同的领域知识的组织方式和重要元素的区分方式。透过我们如何选择术语、分解概念、以及将概念联系起来,模型记录了我们看待领域的方式。

 

  软件的核心

  软件的核心是为用户解决领域相关的问题的能力。所有其他特性,不管有多么重要,都要服务于这个基本目的。当领域很复杂时,这是一项艰巨的任务。开发人员必须钻研领域以获取业务知识。必须磨砺其建模技巧,并精通领域设计。

 

1.消化知识

  一.有效建模的要素

  (1)模型和实现的绑定。最初的原型虽然简陋,但它在模型和实现之间建立了早期链接,而且在所有后续的迭代中我们一直维护该链接。

  (2)建立一种基于模型的语言。

  (3)开发一个蕴含丰富知识的模型。对象具有行为和强制性规则。模型并不仅仅是一种数据模式,它还是解决复杂问题不可或缺的部分。模型包含各种类型的知识。

  (4)提炼模型。

  (5)头脑风暴和实验。语言和草图,再加上头脑风暴活动,将我们的讨论变成 “模型实验室” ,在这些讨论中可以演示、尝试和判断上百种变化。当团队走查场景时,口头表达本身就可以作为所提议的模型的可行性测试,因为人们听到口头表达后,就能立即分辨出它是表达得清楚、简捷,还是表达得很笨拙。

 

  二.知识消化

  高效的领域建模人员是知识的消化者。他们在大量信息中探寻有用的部分。他们不断尝试各种信息组织方式,努力寻找对大量信息有意义的简单视图。很多模型在尝试后被放弃或改造。只有找到一组适用于所有细节的抽象概念后,工作才算完成。这一精华严谨地表示了所发现的最为相关的知识。

  知识消化并非一项孤立的活动,它一般是在开发人员的领导下,由开发人员和领域专家组成的团队来共同协作。他们共同收集信息,并通过消化而将它组织为有用的形式。

  模型聚焦于需求分析。它与编程和设计紧密交互。模型对理解领域必须是切实可行的。

 

  三.持续学习

  高效率的团队需要有意识地积累知识,并持续学习。对于开发人员来说,这意味着既要完善技术知识,也要培养一般的领域建模技巧,也包括认真学习他们正在从事的特定领域的知识。

 

  四.知识丰富的设计

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

  当我们的建模不再局限于寻找实体和值对象时,我们才能充分吸取知识,因为业务规则之间可能会存在不一致。领域专家需要反复研究所有规则、解决规则之间的矛盾以及常识来弥补规则的不足等一系列工作。

 

  五.深层模型

  有用的模型很少停留在表面。随着对领域和应用程序需求的理解逐步加深,我们往往会丢弃那些最初看起来很重要的表面元素,或者切换它们的角度。

 

2.交流与语言的使用

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

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

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

 

  一.模式:Ubiquitous Language

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

  

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

  Ubiquitous Language(通用语言)的词汇包括类和主要操作的名称。语言中的术语,有些用来讨论模型中意境明确的规则,还有一些规则来自施加于模型上的高级组织原则。

 

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

 

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

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

 

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

 

  二.“大声地” 建模

  改善模型的最佳方法之一就是通过对话来研究,试着说出可能的模型变化中的各种结构。这样不完善的地方很容易被听出来。

 

  使用单词和短语是极为重要的——其将我们的语言能力用于建模工作,这就如同素描对于表现视觉和空间推理一样重要。我们既要利用系统性分析和设计方面的分析能力,也要利用对代码的神秘“感觉”。这些思考方式互为补充,要充分利用它们来找到有用的模型和设计。在所有这些方式中,语言上的试验通常是最容易被忽视的。

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

 

  三.一个团队,一种语言

  开发人员会使用领域专家无法理解的技术术语。用户也会用开发人员无法理解的、超出应用程序范畴的专用术语。这些都是对语言的扩展。但在这些语言扩展中,同一领域的相同词汇不应该反映不同的模型。

 

  四 文档和图

  一边画图一边用语言来丰富它们的意义,或者讨论时进行解释。

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

  当通过UML图表示整个模型或设计时,会因为过于细致导致 “只见树木,不见森林”。可以把细节(例如约束和断言)在图中用文本加进来。

 

  图是一种沟通和解释手段,它们可以促进头脑风暴。简洁的小图能够很好地实现这些目标,而涵盖整个对象模型的综合性大图反而失去了沟通和解释能力,因为它们将读者淹没在大量细节之中,加之这些图也缺乏目的性。鉴于此,我们应避免使用包罗万象的对象模型图,甚至不能使用包含所有细节的UML数据存储库。相反,应使用简化的图,图中只包含对象模型的重要概念——这些部分对于理解设计至关重要。

 

  设计的重要细节应该在代码中体现出来。良好的实现应该是透明的,清楚地展示其背后的模型。互为补充的图和文档能够引导人们将注意力放在核心要点上。

 

  务必要记住模型不是图。图的目的是帮助表达和解释模型。代码可以充当设计细节的存储库。

 

  1. 书面文档设计

  口头交流可以解释代码的含义,因为可作为代码精确性和细节的补充。但书面文档是必不可少的,任何规模的团队都需要它来提供稳定和共享的交流。

  两条用于评估文档的总体原则:

  (1)文档应作为代码和口头交流的补充

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

    其他文档应该着重说明含义,以便使人们能够深入理解大尺度结构,并将注意力集中在核心元素上。

  (2)文档应当鲜活并保持最新

    通过将文档减至最少,并且主要用它来补充代码和口头交流,就可以避免文档与项目脱节。

 

  2.完全依赖可执行代码的情况

  良好的代码具有很强的表达能力,但它所传递的信息不能确保是准确的。一段代码所产生的实际行为是不会改变的。测试中的断言是严格的,但变量和代码组织方式所表达出来的意思未必严格。好的编程风格会尽力使这种联系直接化,但其仍然主要靠开发人员的自律。

  尽管代码可能产生误导,但它仍然比其他文档更基础。要想利用当前的标准技术使代码所传达的消息与它的行为和意图保持一致,需要纪律和思考设计的特定方式(后面会详细介绍)。

 

  五 解释性模型

  在实现、设计和团队交流中需要使用同一个模型作为基础。如果各有各的模型,将会造成危害。

  对设计起到推动作用的模型是领域的一个视图,但为了学习领域,还可以引入其他视图,这些视图只作用传递一般领域知识的教学工具。出于此目的,人们可以使用与软件设计无关的其他种类模型的图片或文字。

  

  使用其他模型的一个特殊原因是范围。驱动软件开发过程的技术模型必须经过严格的精简,以便用最小化的模型来实现其功能。而解释性模型则可以包含那些提供上下文的领域方面——这些上下文用于澄清范围更窄的模型。

  解释性模型提供了一定的自由度,可以专门为某个特殊主体定制一些表达力更强的风格。领域专家在一个领域中所使用的视觉隐喻通常呈现了更清晰的解释,这可以教给开发人员领域知识,同时使领域专家们的意见更一致。

 

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

 

3.绑定模型和实现

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

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