什么是DDD

软件开发不是一蹴而就的事情,我们不可能在不了解产品(或行业领域)的前提下进行软件开发,在开发前,通常需要进行大量的业务知识梳理,而后到达软件设计的层面,最后才是开发。而在业务知识梳理的过程中,我们必然会形成某个领域知识,根据领域知识来一步步驱动软件设计,就是领域驱动设计的基本概念。
DDD从2004年Eric evans那本书出来到现在20年了,国内根本就不认这一套东西,完全没有流行起来。我认为现在社会是浮躁的,追求快速交付和一次性交付,快速交付意味着程序员没有过多勇气和精力去运用DDD,雕琢自己的领域模型,只能被源源不断的需求驱赶走向稳定的MVC或其他习惯的模式。而ddd只有在持续性交付时,才展现旺盛的生命力,那我们为什么要了解一下呢,因为我觉得随着技术的发展,未来可能就是它的天下,希望那时候我们也不用这么卷了。

软件开发 VS DDD

一般软件设计或者说软件开发分两种:瀑布式,敏捷式。
前者是开发人员根据需求文档,他们只需要照此开发便是。这种模式下,是很难频繁的从用户那里得到反馈,因此在前期分析时就已经默认了这个业务模型是正确的,那么结果可想而之,数月甚至数年后交付的时候,必然和客户的预期差距较大。
后者在此基础上进行了改进,它也需要大量的分析,范围会设计到更精细的业务模块,它是小步迭代,周期性交付,那么获取客户的反馈也就比较频繁和及时。可敏捷也不能够将业务中的方方面面都考虑到,并且敏捷是拥抱变化的,大量的需求或者业务模型变更必将带来不小的维护成本,同时,对人(Developer)的要求也必然会更高。
DDD则不同:它像是更小粒度的迭代设计,它的最小单元是领域模型(Domain Model),所谓领域模型就是能够精确反映领域中某一知识元素的载体,这种知识的获取需要通过与领域专家(Domain Expert)进行频繁的沟通才能将专业知识转化为领域模型。领域模型无关技术,具有高度的业务抽象性,它能够精确的描述领域中的知识体系;同时它也是独立的,我们还需要学会如何让它具有表达性,让模型彼此之间建立关系,形成完整的领域架构。通常我们可以用象形图或一种通用的语言(Ubiquitous Language)去描述它们之间的关系。在此之上,我们就可以进行领域中的代码设计(Domain Code Design)。如果将软件设计比做是造一座房子,那么领域代码设计就好比是贴壁纸。前者已经将房子的蓝图框架规划好,而后者只是一个小部分的设计:如果墙纸贴错了,我们可以重来,可如果房子结构设计错了,那可就悲剧了。

建立领域知识(Build Domain Model)

说了这么多领域模型的概念,到底什么是领域模型呢?以飞机航行为例子:
现要为航空公司开发一款能够为飞机提供导航,保证无路线冲突监控软件。那我们应该从哪里开始下手呢?根据DDD的思路,我们第一步是建立领域知识:作为平时管理和维护机场飞行秩序的工作人员来说,他们自然就是这个领域的专家,我们第一个目标就是与他们沟通,也许我们并不能从中获取所有想要的知识,但至少可以筛选出主要的内容和元素。你可能会听到诸如起飞,着陆,飞行冲突,延误等领域名词,让们从一个简单的例子开始(就算是错误的也没关系):

  • 起点->飞机->终点

这个模型很直接,但有点过于简单,因为我们无法看出飞机在空中做了什么,也无法得知飞机怎么从起点到的终点,刚才我们似乎提到无路线冲突,那么如此似乎会好些:

  • 飞机->路线->起点/终点

既然点构成线,那何不:

  • 飞机->路线->points(含起点,终点)

这个过程,是我们不断建立领域知识的过程,其中的重点就是寻找领域专家频繁沟通,从中提炼必要领域元素。
尽管看起来还是很简单,但我们已经开始一步步的在建立领域对象和领域模型了。

通用语言(Ubiquitous Language)

上面的例子的确看起来简单,但过程并非容易:我们(开发人员)和领域专家在沟通的过程中是存在天然屏障的:我们满脑子都是类,方法,设计模式,算法,继承,封装,多态,如何面向对象等等;这些领域专家是不懂的,他们只知道飞机故障,经纬度,航班路线等专业术语。
所以,在建立领域知识的时候,我们(开发人员和领域专家)必须要交换知识,知识的范围范围涉及领域模型的各个元素,如果一方对模型的描述令对方感到困惑,那么应该立刻换一种描述方式,直到双方都能够接受并且理解为止。在这一过程中,就需要建立一种通用语言,作为开发人员和领域专家的沟通桥梁。
可如何形成这种通用语言呢?其实答案并不唯一,确切的说也没有什么标准答案。

  • UML
    利用UML可以清晰的表现类,并且展示它们之间的关系。但是一旦聚合关系复杂,UML叶子节点将会变的十分庞大,可能就没有那么直观易懂了。最重要的是,它无法精确的描述类的行为。为了弥补这种缺陷,可以为具体的行为部分补充必要说明(可以是标签或者文档),但这往往又很耗时,而且更新维护起来十分不便。
  • 伪代码
    极限编程是推荐这么做的,这个办法对程序猿来说固然好,可立刻就要将现有模型映射到代码层面,这对人的要求也是不低,并不容易实现。

    模型驱动设计(Domain Driven Design)

    模型关系图(Model-Driven Design)

    image.png
  1. User Interface(用户接口层):负责向用户展现信息,并且会解析用户行为,即常说的展现层。
  2. Application Layer(应用层):应用层没有任何的业务逻辑代码,它很简单,它主要为程序提供任务处理。
  3. Domain Layer(领域层):这一层包含有关领域的信息,是业务的核心,领域模型的状态都直接或间接(持久化至数据库)存储在这一层。
  4. Infrastructure Layer(基础层):为其他层提供底层依赖操作。层结构的划分是很有必要的,只有清晰的结构,那么最终的领域设计才宜用,比如用户要预定航班,向Application Layer的service发起请求,而后Domain Layler从Infrastructure Layer获取领域对象,校验通过后会更新用户状态,最后再次通过Infratructure Layer持久化到数据库中。

    实体(Entity) & 值对象(Value Object)

    实体与面向对象中的概念类似,在这里再次提出是因为它是领域模型的基本元素。在领域模型中,实体应该具有唯一的标识符,从设计的一开始就应该考虑实体,决定是否建立一个实体也是十分重要的。
    值对象和我们说的编程中数值类型的变量是不同的,它仅仅是没有唯一标识符的实体,比如有两个收获地址的信息完全一样,那它就是值对象,并不是实体。值对象在领域模型中是可以被共享的,他们应该是“不可变的”(只读的),当有其他地方需要用到值对象时,可以将它的副本作为参数传递。

文章大部分内容转载自 :简书 作者:Pursue
链接:https://www.jianshu.com/p/b6ec06d6b594
来源:简书