这些 DDD"术语"你知道吗?
DDD
Domain Driven Design
中文名是领域驱动设计,领域驱动设计是一种方法论,是针对某个领域需要解决的特定问题,从纷繁复杂的现实世界中抽象提炼出业务模型的思维方式与实践技巧,强调聚焦于“业务知识”。既然有领域驱动设计,那肯定还有 XX 驱动设计。设计四大范式,有数据表驱动、事物脚本驱动、活动记录模式和领域驱动设计,其中前两个是面向过程的,后两个是面向对象的,各有侧重。具体见软件架构设计模式简述
领域
Domain
领域指的是一个特定的业务范围,可以理解为 领域 = 业务问题
子域
Subdomain
子域与领域不是父子关系,而是包含关系。当多个业务域(领域)的组合形成了一个更大的业务域(领域)时,其中每一个领域(业务域)是这个更大的业务域的一部分,每一个业务域相对于这个更大地业务域称之为这个更大领域的子业务域,简称子域。可以认为 子域 = 部分业务问题。子领域是领域专家根据领域经验选择合适的功能分类策略进行划分,这个过程不会牵扯对业务服务的分析,体现的是领域专家对行业的洞见和深刻认识,获取子领域是一个自顶向下的过程。既然领域可以划分为多个子域,那么多个子域并不是同等重要的,我们可以对子域的重要性进行归类。
核心域
Core (Sub)Domain
核心域是整个业务系统的核心,所有的业务都要围绕着核心业务域展开。核心域是通过分析业务愿景得出的,而不是程序员决定的。核心域通常需要花大的资源来投入,核心域的建模应该是组织中的核心/资深人员来承担。
支撑域
Supporting (Sub)Domain
在业务域中,会有一些比较重要的业务,但却不是核心,那么它便是一个支撑子域。创建支撑子域的原因在于它们专注于业务的某个方面。它不像核心域在整个系统中那么重要。该子域一般建议由组织中的中级开发来承担该类领域的建模与实现,当然也可以考虑外包出去。
通用域
Generic (Sub)Domain
通用域类似于工具,是横向的概念,如果一个业务问题大家都会遇到,那么它就属于通用域。比如认证、权限等等,这类应用很容易买到,没有企业特点限制,不需要做太多的定制化。如果可以的话可以外包或者直接购买 SAAS。即使需要自己开发的话,也可以让组织中的初级开发者来承担该类领域的建模与实现。
统一语言
Ubiquitous Language
统一语言是提炼领域知识的产出物,获得统一语言就是需求分析的过程,也是团队中各个角色就系统目标、范围与具体功能达成一致的过程。统一语言的范围是所有角色而非仅仅局限于工程师。 开发人员与领域专家之间,他们掌握的知识存在巨大的差异。善于技术的开发人员关注于数据库、通信机制、集成方式与架构体系,而精通业务的领域专家对这些不甚了解,但他们在讲解业务知识时,使用各种概念如呼吸一般自然,这些对于开发人员来说,却成了天书,这种交流就好似使用两种不同语言的外国人在交谈。在没有达成一致的情况下,那就是鸡同鸭讲,毫无沟通效率,相反还可能造成误解。同时开发人员与开发人员之间也会有对概念命名发生冲突的时候,比如弹幕,有的叫 danmu,有的却叫 toast,这样对开发内部的交流也是一个阻碍。
事件风暴
Event Storming
事件风暴是由 Alberto Brandolini 发明的一种轻量级,基于 DDD 概念的系统分析方法。事件风暴最大的作用是帮助开发人员,业务人员,UX,测试等项目参与者对于业务流程有一个统一的认识,这包括关键的流程,核心的业务规则,系统不同模块的使用者。其次是帮助开发人员梳理核心的业务对象,从某种程度上来说就是就是领域对象中的聚合。事件风暴都是以 Workshop 的形式展开,实施成本比较高。
问题空间
Question Space
哲学家常常会围绕真实世界和理念世界的映射关系探索人类生存的意义,即所谓“两个世界”的哲学思考。软件世界也可一分为二,分为构成描述需求问题的真实世界与获取解决方案的理念世界。整个软件构建的过程,就是从真实世界映射到理念世界的过程。 定义:真实世界 利用核心子领域、通用子领域、支撑子领域来分解问题空间 问题空间:价值需求+业务需求(业务功能、业务实现) 其中属于问题空间的概念有领域、子域等
解空间
Solution Space
定义:使用软件世界构建的解空间 围绕着领域这一核心开展业务系统的战略设计与战术设计 其中属于解空间的有统一语言、限界上下文、上下文映射等
系统上下文
System Context 定义:定义目标系统解空间的边界,边界范围外的系统是伴生系统。系统上下文就是解空间的边界,该系统是为了解决该解空间的问题,而非解决另外的解空间的问题。
限界上下文【DDD 中核心概念】
Bounded Context
限界上下文是语义和语境的边界。限界上下文拆开来看就是限界和上下文。限界就是领域的边界,而上下文则是语义环境。通过领域的限界上下文,我们就可以在统一的领域边界内用统一的语言进行交流。
限界上下文是 DDD 中比较核心且抽象难懂的概念。
上下文映射
Context Map
限界上下文封装了分离的业务能力,上下文映射则建立了限界上下文之间的关系。上下文映射提供了各种模式(防腐层、开放主机服务、发布语言、共享内核、合作者、客户方/供应方、分离方式、遵奉者、大泥球),本质是在控制变化在限界上下文之间传递所产生的影响。
战略设计
Strategic Design
“战略设计(strategic design)”一词最早来自于 2004 年 Eric Evans 最初的《领域驱动设计:软件核心复杂性应对之道》一书的最后一个部分(第四部分:战略设计)。
战略设计包括统一语言、子域、领域、限界上下文、上下文映射等。具体见领域驱动实战思考(二):用分段思想改进那些混乱的战略设计和战术设计
战术设计
战略设计为我们提供一种高层视野来审视我们的软件系统,而战术设计则将战略设计进行具体化和细节化,它主要关注的是技术层面的实施,也是对程序员来得最实在的地方。很多团队会优先进行战术设计,其实这有点本末倒置了,容易变成自嗨型的 DDD。
分层架构
分层的本质是关注点分离,隔离对下层的变化。由于层间松散的耦合关系,使得我们可以专注于本层的设计,而不必关心其他层的设计,也不必担心当前层的设计会影响其它层。分层架构中最难的问题是决定建立那些层次和每一个层次的职责,不同于传统的三层架构,Eric Evans 在领域驱动设计的第四章分离领域中提出来 DDD 的四层架构(Layered Architecture)
应用服务
Application Service
应用服务是用来表达用例和用户故事(User Story)的主要手段。
应用层通过应用服务接口来暴露系统的全部功能。在应用服务的实现中,它负责编排和转发,它将要实现的功能委托给一个或多个领域对象来实现,它本身只负责处理业务用例的执行顺序以及结果的拼装。通过这样一种方式,它隐藏了领域层的复杂性及其内部实现机制。
应用层相对来说是较“薄”的一层,除了定义应用服务之外,在该层我们可以进行安全认证,权限校验,持久化事务控制,或者向其他系统发生基于事件的消息通知,另外还可以用于创建邮件以发送给客户等。
应用层作为展现层与领域层的桥梁。展现层使用 VO(视图模型)进行界面展示,与应用层通过 DTO(数据传输对象)进行数据交互,从而达到展现层与 DO(领域对象)解耦的目的。 使用应用服务的时候尽量遵循以下几个原则
领域服务
Domain Service
领域层就是较“胖”的一层,因为它实现了全部业务逻辑并且通过各种校验手段保证业务正确性。而什么是业务逻辑呢?业务流程、业务策略、业务规则、完整性约束等。 当领域中的某个操作过程或转换过程不是实体或值对象的职责时,我们便应该将该操作放在一个单独的接口中,即领域服务。请确保该服务和通用语言时一致的;并且保证它是无状态的。 使用领域服务的时候尽量遵循以下几个原则
领域消息/领域事件
Domain Event
领域事件是一个领域模型中极其重要的部分,用来表示领域中发生的事件。忽略不相关的领域活动,同时明确领域专家要跟踪或希望被通知的事情,或与其他模型对象中的状态更改相关联。
领域事件作为领域模型的重要部分,是领域建模的工具之一。
用来捕获领域中已经发生的事情。
领域事件的命名一般是XXX已
XXX并不是领域中所有发生的事情都要建模为领域事件,要忽略无业务价值的事件。
领域事件是领域专家所关心的(需要跟踪的、希望被通知的、会引起其他模型对象改变状态的)发生在领域中的一些事情。
简而言之,领域事件是用来捕获领域中发生的具有业务价值的一些事情。它的本质就是事件,不要将其复杂化。在 DDD 中,领域事件作为通用语言的一种,是为了清晰表述领域中产生的事件概念,帮助我们深入理解领域模型。 具体见DDD理论学习系列(9)– 领域事件
应用消息/应用事件
Application Event
事件的发送,处理逻辑放在应用服务层,即 Application Service 中。 事件的使用建议
聚合【DDD 中核心概念】
Aggregate
聚合就是由业务和逻辑紧密关联的实体和值对象组合而成的,聚合是数据修改和持久化的基本单元,每一个聚合对应一个仓储,实现数据的持久化。 聚合有一个聚合根和上下文边界,这个边界根据业务单一职责和高内聚原则,定义了聚合内部应该包含哪些实体和值对象,而聚合之间的边界是松耦合的。按照这种方式设计出来的微服务很自然就是“高内聚、低耦合”的。
实体
Entity
实体(Entity,又称为 Reference Object)很多对象不是通过他们的属性定义的,而是通过一连串的连续事件和标识定义的。主要由标识定义的对象被称为 ENTITY。实体是与其他事物分开存在的事物,并且具有自己的明确标识。 为一个事物定义了明确的标识后,会使你有一种错觉。 你会感觉只要为事物定义明确标识后,事物就是实体或者实体就是事物了。
值对象
Value Object
很多对象没有概念上的表示,他们描述了一个事务的某种特征。用于描述领域的某个方面而本身没有概念表示的对象称为 Value Object(值对象)。上面这句话比较抽象难以理解,值对象是 DDD 领域模型中的一个基础对象,跟实体一样源于事件风暴所构建的领域模型,都包含若干属性,与实体一起构成聚合。 实体是看得到、摸得着的实实在在的业务对象,实体具有业务属性、业务行为和业务逻辑。 值对象只是若干个属性集合,只有数据初始化操作和有限的不涉及修改数据的行为,基本不包含业务逻辑。值对象与实体最大的区别是实体有唯一标识而值对象没有
领域原语
Domain Primitive
具体见阿里技术专家详解 DDD 系列 第一讲- Domain Primitive
仓储
Repository
repository,又作仓库、仓储。在 DDD 中,是用来持久化领域对象(entity, value object)的 Repository 的职责仅是数据永久化,当然 repository 是不能够包含业务逻辑的。
数据传输对象
DTO
数据传输对象(Data Transferring Object,DTO)在层与层之间进行传递,无业务含义。qry cmd 和 event 都属于 DTO。
视图对象
View Object
视图对象,为 ui 提供数据,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来
业务对象
BO
Business Object,业务对象,在业务逻辑层封装业务逻辑,一般就是聚合或者 Entity
领域对象
DO
Domain Object, 领域对象,就是从现实世界中抽象出来的有形或无形的业务聚合或者实体。
持久化对象
Persistent Object
持久对象,这里用于描述数据库中特定 table。它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应 PO 的一个(或若干个)属性。
数据对象
Data Object
同 PO, 类似
数据访问对象
DAO
数据访问对象
防腐层
Anti-corruption layer / ACL
DDD(Eric Evans)中引入的模式, 用于隔离两个系统, 允许两个系统之间在不知道对方领域知识的情况下进行集成。主要进行的是两个系统之间的 model(模型)或者协议的转换, 并且最终目的是为了系统使用者的方便而不是系统提供者的方便, 进一步解释就是 ACL 尽量把系统提供者的模型转换为系统使用者的模型(而不引入中间第三者模型)
工厂
Factory
Entity 的创建组件
CQRS
Command-Query Responsibility Segregation
CQRS(Command-Query Responsibility Segregation) 是一种读写分离的模式,从字面意思上理解 Command 是命令的意思,其代表写入操作;Query 是查询的意思,代表的查询操作,这种模式的主要思想是将数据的写入操作和查询操作分开。
贫血模型
anaemic domain model
贫血模型中只包含了数据,而不包含任何的业务逻辑。 在一些系统中,数据库映射实体、RPC 请求和返回结果等被设计为贫血模型。这里的“血”指的是业务逻辑
充血模型
rich domain model
在贫血模型的基础上,充血模型的对象拥有了自身的业务方法,能够对外暴露一些“动作”。在贫血模型的基础上,充血模型的对象拥有了自身的业务方法,能够对外暴露一些“动作”。充血模型是 DDD 建议的模型。具体见领域模型、贫血模型、充血模型概念总结
其余相关概念
BDD
Behavior-driven development,即行为驱动开发。其目的是鼓励软件项目中的开发者、QA 和非技术人员或商业参与者之间的协作。是从用户的需求出发,强调系统行为。具体见混合开发:TDD、DDD和BDD交集的值
TDD
Test-driven development,即测试驱动开发。一种开发过程中应用方法。其思想为先根据需求抽象接口,先编写测试用例,然后在开始编写开发代码。TDD 的本意就是通过测试来推动整个开发的进行。具体见混合开发:TDD、DDD和BDD交集的值
评论