其它-关于领域驱动模型

领域驱动模型的学习与思考(V1)

Posted by Kang on September 18, 2019

推荐阅读-领域驱动设计到底难在哪? 推荐阅读-领域驱动设计系列

领域驱动设计的概念

  在开发前通常需要进行大量的业务知识梳理,然后才到软件设计的层面,最后才是开发。在业务知识梳理的过程中,必然会形成某个领域知识,根据领域知识来一步步驱动软件设计,就是领域驱动设计(DDD,Domain-Driven Design)的基本概念 。DDD首先应该是一种软件开发过程,它拥抱与发展了敏捷开发方法,采用演进式设计和各种先进的软件技术实践,追求一个统一一致的领域模型(而不是曾经分裂的分析模型和实现模型),在实践过程中使用通用语言(Ubiquitous Language)各个参与者脑海中对应的认识是高度一致的,目标是做到模型既设计、代码与设计保持一致!
领域模型-基础结构图1

领域模型的来源

  在早期开发中,领域模型就是数据库设计。做传统项目的流程或者说包括现在我们做项目的流程,都是首先讨论需求,然后是数据库建模,在需求逐步确定的过程不断的去变更数据库的设计,接着我们在项目开发阶段,发现有些关系没有建、有些字段少了、有些表结构设计不合理,又在不断的去调整设计,最后上线。在传统项目中,数据库是整个项目的根本,数据模型出来以后后续的开发都是围绕着数据展开。

传统的架构

从展示层到数据库:View -> Controller -> Service -> Da0(POJO) -> DB

传统架构存在的问题
  • Service层很重,所有逻辑处理基本都放在service层。
  • POJO作为 Service 层非常重要的一个实体也是和底层数据库交互的对象,会因为不同场景的需求做不同的变化和组合,就会造成 POJO 的几种不同模型(失血、贫血、充血),以此用来形容领域模型太胖或者太瘦。
  • 随着业务变得复杂,各个模板都需要进行修改,并且系统内部和边界等容易变的冗余、混乱不堪。

DDD思考了什么

  DDD关心的是领域内的模型,而不是数据库的操作。其重点与难点是是如何去划分领域,划分好边界。

DDD中战术层面划分

  当一个对象用于对事物进行描述而没有唯一标识时,那么它被称作值对象。

实体(Entity)

  当一个对象由其标识(而不是属性)区分时,这种对象称为实体(Entity)。标识->唯一键?和数据库表对应??

值对象(Value Object)

  

领域服务(Domain Service)

  一些重要的领域行为或操作,它们不太适合建模为实体对象或者值对象,它们本质上只是一些操作,并不是具体的事物,另一方面这些操作往往又会涉及到多个领域对象的操作,这些操作只负责来协调这些领域对象完成操作而已,那么我们可以归类它们为领域服务。理解起来,领域服务有点facade的味道。

聚合及聚合根(Aggregate,Aggregate Root)

  

工厂(Factory)

  隐藏创建复杂对象的细节。防止领域层的业务逻辑泄露到应用层,同时也减轻应用层负担,它只要简单调用领域工厂来创建出期望的对象就可以了。

仓储(Repository)

  资源仓储封装了基础设施来提供查询和持久化聚合操作。我们始终关注在模型层面,把对象的存储和访问都委托给资源库来完成,Repository不是数据库的封装,而是领域层与基础设施之间的桥梁。

界限上下文

  用模块(Modules)来进行上下文界定和划分,将整个系统划分也不同的上下文(模块)来进行业务服务。

  从实践的角度看,如果一个类中的属性被它不同接口访问的内聚度不同或者访问频率不同,就应该将这些属性和接口拆分出来形成一个新类。这些新类往往和原有的类表示一个概念的不同方面,例如OrderedBook、DeliveredBook。当如此需要依赖前缀区分的概念逐渐变多则代表着一种味道,提醒着我们需要考虑将它们拆分到不同的BC(Bounded Context,界限上下文)中去。最终这些概念在每个BC下的含义又变得唯一和一致,也就不再需要前缀的修饰。

  每个BC都会有一个领域模型。拆分BC的同时也分离了关注点,降低了每个BC下领域模型的复杂度。   界限上下文通常有三种类型,分别为核心域、支撑域、通用域。

  • 核心域:系统最核心并有复杂业务逻辑的业务界限上下文,比如电商平台的订单上下文,OA系统的费用管理上下文。
  • 支撑域:系统支撑其他界限上下文的基础,比如电商平台的商品,OA系统的员工基础资料。
  • 通用域:需要使用的基础框架或第三方成熟解决方案,比如OA系统中封装的钉钉框架上下文、学习中心。

层次结构图

  对于每个上下文模块DDD总体结构分为四层 : Infrastructure(基础实施层),Domain(领域层),Application(应用层),Interfaces(表示层,也叫用户界面层或是接口层)。这些层次是存在于限界上下文中的。
领域模型-分层结构图示例

不过从分层架构图中可以发现,将基础设施层放入底层是存在缺点的,领域层依赖于基础设施层,这对领域层的内聚性产生影响。一个解决方案就是依赖倒置。

暂时还没理解到产生啥影响,对于来说不就是应该上层依赖下层么?--有待完善

六边形架构

  六边形架构实际上也是一种分层架构,只不过不是上下或左右,而是变成了内部和外部。六边形的内部代表了application(功能承接与流程流转)和domain层(内部业务基本单位)。外部代表应用的驱动逻辑、基础设施或其他应用。内部通过端口和外部系统通信,端口代表了一定协议,以API呈现。
领域模型-六边形架构
  一个典型的六边形架构应用有两个端口,一个端口对应用户接口层,用于应用控制,一个对应数据访问层,用于数据获取和持久化,每个端口都可以对应几个适配器。

DDD在微服务中的使用

DDD微服务的营养不良:服务最大不要大过一个BC,否则服务内会存在有歧义的领域概念;服务最小不要小过一个聚合,否则会引入分布式事务的复杂度;服务间最好通过Domain Event来进行交互,这样可以让服务保持松耦合。