大话领域驱动设计——基础概念

1 简介 如果说当下最热门的技术概念或架构思想,那么领域驱动设计(DDD)一定占有一席之地。上个系列,我讲了ABP vNext框架在微服务架构下的落地思路,

1. 简介

如果说当下最热门的技术概念或架构思想,那么领域驱动设计(DDD)一定占有一席之地。上个系列,我讲了ABP vNext框架在微服务架构下的落地思路,而ABP vNext是基于DDD思想的完整框架之一,同时DDD也是微服务架构服务拆分的主流依据。无论想学好ABP还是微服务架构,首先要理解DDD。这一系列,我就从各个概念,结合在ABP vNext中的用法详细讲解DDD。

DDD是Domain Driven Design的缩写,中文翻译为领域驱动设计。首先要明确一点,DDD是一套方法论,主要面向软件设计的方法论。学习它首先要把它从具体的实现抽离出来,也要从微服务架构的概念里抽离出来,它们是相互独立的概念。而ABP框架是DDD思想的基础落地方案之一。所以是先学思想,再学落地。

DDD的核心是领域。领域又称为问题域,是对系统业务的抽象,意在将我们的重点放在需要解决的问题本身,而不是如何实现。DDD希望为业务专家(领域专家)和研发人员(技术专家)提供一套完整高效的沟通方式,并在此基础上由他们共同建立可快速落地的系统模型(领域模型)。在此工程中,业务专家不需要去关注技术实现,技术人员应该优先把精力放在理解业务本身而不是实现的细节。

DDD的核心产出结果是领域模型,在过去无论是传统软件工程方法或是基于UML的面向对象建模,软件设计过程都会产出多个不同维度的设计图,例如类图、顺序图、流程图……。但是这样存在一个问题,因为需求不断变更,每次变化我们都要花大量时间修改多个设计图。尤其对于进度比较急项目,经常会出现代码不断修改但是设计图没有足够的时间去维护。慢慢会导致设计图和实际代码不一致甚至区别很大,那么设计图将失去意义。而在DDD的思想中,所有的领域设计,都会绘制在一个图也就是领域模型图中,相当于将过去的多个图合成一个。那么我们改代码的同时,就很容易同步去修正领域模型。

领域驱动设计分为战略设计和战术设计两个阶段。

2. 战略设计

战略设计又称为策略设计、战略模式。是从宏观的角度理解系统业务,是系统分析的过程。同时,战略设计过程也是领域专家和技术人员相互磨合的过程。在这个过程中,我们识别和划分领域,并识别有界上下文并建立适合这个团队的通用语言。

2.1. 有界上下文

有界上下文是指在空间或时间上有边界的一段环境背景,它确定了每个模型的适用范围,模型体现了这个范围内的逻辑一致性。

在对系统的理解和沟通中,我们会发现同一个事物或名词,在不同的场景中会有不同的场景会有不同的意义。而为了保证理解一致,我们也需要在同一场景下同一事物的叫法同一。为方便大家理解举两个子:

一个是很经典的一句话:“冬天能穿多少穿多少,夏天能穿多少穿多少”。同样是“多少”,但是在不同的场景下,我们明显表达了截然不同的两个意思。如果去掉冬天或夏天这样的场景,我们就不知道“多少”代表的实际意义。

另一个例子是,同样是一台手机的参数的8G+128G,有人会说“8G内存,128G存储空间”,也有人说“128G内存”。这里我们就要要求在战略设计时将说法统一,否则可能会出现到底是8G内存还是128G内存的疑惑。

有界上下文的重点和难点是界的划分,通常我们会在业务流程或领域故事(通过讲故事的方式梳理,理解业务)中找到关键词提炼上下文,并依据业务场景划分上下文的边界。

2.2. 领域拆分

领域拆分是对业务的拆分,由领域专家主导,提出整个系统需要解决的问题以及需要实现的目标。依据问题和子问题划分领域。领域划分通常也可以理解为对上下文边界的进一步细化。一个领域也可以理解为一个业务模块。通常一个系统中会包含以下三种领域:

核心域:该系统主要解决的问题或者说最重要的业务功能,也可以理解为一个系统的核心买点。在一个系统中,核心域是优先级最高的领域,需要优先设计。其他领域设计时应以核心域为主,而不应该因为其他领域的设计而改变核心域的功能。

支撑域:主要是为核心域提供数据和功能的支撑,重要程度仅次于核心域,可以说没有支撑域,核心域的功能无法独立完成。例如商城系统,我们可以认为订单是它的核心域,那么商品管理、商户管理、顾客管理等就可以理解为支撑订单这个核心域的支撑域,它们不是商城系统要解决的核心问题,但是没有这些领域做为支撑,订单业务将无从谈起。

通用域:在我们划分完核心域和支撑域之后,我们通常会发现还剩余一部分功能,这些功能乐能是一些通用逻辑,通用处理,也可能是有现成解决方案或者是由第三方系统提供的模块。这些都属于通用域的范畴。还是以商城系统为例,我们会发现物流和支付都是商城系统所需要的功能。但是这两部分我们一般可以通过调用或集成第三方系统接口或模块来完成,且抛开商城系统,在其他系统中也可以复用这个领域完整的模型,所以我们就可以把这两个领域认为成通用域。

2.3. 领域语言

在我们沟通领域划分、建立领域模型的过程中,需要建立一套团队中所有人员都能听得懂的语言,这种语言被称为领域语言,也可称为通用语言。这里的所有人员包含技术人员也包含不懂技术的领域专家。

领域语言没有一个统一的标准,原则上,只要这个团队内所有成员可以理解而且不会出现偏差的方式,都可以作为领域语言。不同的团队依据自己的人员组成、知识结构、习惯等情况,使用的领域语言也不尽相同。

通常来说,存粹的自然语言具有二义性,同一段文字不同人阅读,可能存在理解上的偏差。所以不建议使用纯自然语言作为领域语言。而图文结合的方式,绘图和文字可以相互补充、相互对照,更容易达到理解上的统一,所以是现在主流的语言形式。

由于领域语言没有一个统一的标准,所以目前也没有一个统一的或者专门为领域驱动设计提供的图文档编写工具。尽管我们想到很多比较成熟的绘图或建模工具例如EA、PD、Visio等但我们经常会发现,并不是所有人都能熟练掌握这类工具,这些工具绘制出来的图形也不是为DDD而生,经常不能完整的表达我们所设计的领域模型。所以在很多团队中,我们会看到初期的领域模型建立可能是一群人围在几张纸或者一块白板上来绘制领域模型图。等领域模型建立完成后再通过照片或者借助软件工具来重新绘制的方式存档。

3. 战术设计

战术设计就相当于传统软件工程里的概要设计和详细设计工作,而在DDD下,我们是通过聚合、实体、值对象等概念来表达领域模型。在战术设计完成之后,我们可以直接依据这个领域模型开发出成相应的代码。

而在本系列后面的文章中,我们会将重点放在战术设计的各种概念和实现上。主要包含以下几个方面:

  1. 分层架构
  2. 具体概念(实体、聚合根、服务、领域事件……)
  3. 落地方案

由于篇幅及个人水平有限,更多详细细节可以参考各类书籍资料。推荐领域驱动设计之父Eric Evans的《领域驱动设计:软件核心复杂性应对之道》