领域驱动设计的概念
领域驱动设计(DDD,Domain-Driven Design):软件开发不是一蹴而就的事情,不可能在不了解产品或行业领域的前提下进行软件开发,在开发前,通常需要进行 大量的业务知识梳理,然后才到软件设计的层面,最后才 是开发。而在业务知识梳理的过程中,我们必然会形成某个领域知识,根据领域知识来一步步驱动软件设计,就是领域驱动设计的基本概念。
为什么需要 DDD
业务初期,功能大都非常简单,普通的CRUD就能满 足,此时系统是清晰的。随着产品不断迭代和演化,业务 逻辑变得越来越复杂,我们的系统也越来越冗杂。各个模 块之间彼此关联,甚至到后期连作者都很难说清模块的具 体功能意图是什么。这样就会导致在修改一个功能时,要追溯到这个 功能需要的修改点需要很长时间,更别提修改带来的不 可预知的影响面。
比如,订单服务接口中提供了查询、创建订单相关的接口,也 提供了订单评价、支付的接口。同时订单表是个大表, 包含了非常多字段。在我们维护代码时,将会导致牵一 发而动全身,很可能只是想改下评价相关的功能,却影 响到了创建订单的核心路径。虽然我们可以通过测试来 保证功能完备性,但当我们在订单领域有大量需求同时并行开发时,改动重叠、恶性循环、疲于奔命修改各种 问题。 然后一般的解决方案是 不断的重构系统,让系统的设计随着业务成长也进行不断 的演进。通过重构出一些独立的类来存放某些通用的逻辑 解决混乱问题,但是我们很难给它一个业务上的含义,只 能以技术纬度进行描述,这样带来的问题就是其他人接手 这块代码的时候不知道这里的含义或者可以通过修改这块 通用逻辑来达到某些需求 。
领域模型追本溯源
早期的领域模型就是数据库设计. 不管是做传统项目的流程或者做互联网项目的流程,都是首先讨论需求,然后是数据库建模, 在需求逐步确定的过程不断的去更新数 据库的设计。接着我们在项目开发阶段,发现有些关系没 有建立、有些字段少了、有些表结构设计不合理,又在不断 的去调整设计,最后上线。在传统项目中,数据库是整个 项目的根本,数据模型出来以后,后续的开发都是围绕着数 据展开,然后形成如下的一个架构 :
这样可能会带来一些问题:
1.service很重,所有逻辑处理基本都放在service层。
2. POJO作为service层的非常重要的一个实体,会 因为不同场景的需求做不同的变化和组合,就会造成 POJO的几种不同模型导致领域模型太胖或者太瘦, 随着业务变得复杂以后,包括数据结构的变化,那么各 个模块就需要进行修改,原本清晰的系统经过不断的演 化变得复杂、冗余、耦合度高,后果就非常严重 。
如果一个软件产品不依赖数据库存储设 备,怎么去设计这个软件呢?如果没有了数据存 储,那么领域模型就得基于程序本身来设计,这个就是DDD需要去考虑的问题了。DDD理解起来有点抽象(抽象:使用抽象能够精简问题空间,而且问题越小越容易 理解,比如说我们要对接支付,我们抽象的纬度应该是支 付,而不是具体的微信支付还是支付宝支付 ),用法又有点像设计模式。
细化上下文
通过上下文划分以后,我们还需要进一步梳理上下文之间的关系,梳理的好处在于:
1.任务更好拆分(一个开发人员可以全身心投入到相关子域的上下文中);
2.方便沟通,明确自身上下文和其他上下文之间的依赖关系,可以实现更好的对接 ,然后是基于上下文的更进一步细化建模,在 DDD 中存在一些名词:
实体 :当一个对象由其标识(而不是属性)区分时,这种对象称为实体(Entity)。
值对象 :当一个对象用于对事物进行描述而没有唯一标识时,它被称作值对象。
聚合根 :聚合根属于实体对象,它是领域对象中一个高度内聚的核 心对象。 (聚合根具有全局的唯一标识,而实体只有在聚 合内部有唯一的本地标识,值对象没有唯一标识,不存在这个值对象或那个值对象的说法)
领域服务: 一些重要的领域行为或操作,可以归类为领域服务。它实 现了全部业务逻辑并且通过各种校验手段保证业务的正确性。
资源库: 资源封装了基础设施来提供查询和持久化聚合操作。这样 能够让我们始终关注在模型层面,把对象的存储和访问都 委托给资源库来完成。他不是数据库的封装,而是领域层 与基础设施之间的桥梁。DDD关心的是领域内的模型, 而不是数据库的操作。
领域驱动的好处
用 DDD 可以很好的解决领域模型到设计模型的同步、演 进到实际的代码逻辑。DDD有几个好处:
- DDD 能够让我们知道如何抽象出界限上下文以及如何去分而治之:把复杂的大规模软件拆分成若干个子模块,每 一个模块都能独立运行和解决相关问题。并且分割后各个 部分可以组装成为一个整体。
- DDD的限界上下文可以完美匹配微服务的要求 ,在系统复杂之后,我们都需要用分治来拆解问题。一般有 两种方式,技术维度和业务维度。技术维度是类似MVC这 样,业务维度则是指按业务领域来划分系统。 微服务架构更强调从业务维度去做分治来应对系统复杂度, 而DDD也是同样的着重业务视角 。
领域驱动设计可以认为是一种指导思想,是 一种软件开发方法,通过DDD可以将系统解构的更加合理, 最终满足高内聚低耦合的本质。其实也有点类似数据库的三范式,当有足够的设计经验后慢慢发现三范式带来的好处,当然也并不一定要严格按照这三范式去进行设计,某些情况下是可以灵活调整的。