DDD从小白到入门

DDD(领域驱动设计)基础篇

1、DDD简介

DDD(Domain-Driven Design 领域驱动设计),DDD是一种设计思想,他可以同时指导中台业务建模和微服务设计。DDD强调的是领域模型和微服务设计的一致性。DDD 核心思想是通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性。

2、微服务设计采用领域驱动设计

软件架构模式的演变大体来说经历了三个阶段:
单机-两层架构(C\S架构):
	采用面向过程的设计方法,系统包括客户端 UI 层和数据库两层,采用 C/S 架构模式,
	整个系统围绕数据库驱动设计和开发,并且总是从设计数据库和字段开始。

集中式架构-三层架构(SOA架构):
	采用面向对象的设计方法,系统包括业务接入层、业务逻辑层和数据库层,
	采用经典的三层架构,也有部分应用采用传统的 SOA 架构。
	这种架构容易使系统变得臃肿,可扩展性和弹性伸缩性差。

分布式微服务架构-DDD分层架构:
	用户接口层:用户界面、web服务、其他
	应用层:应用服务
	领域层:聚合:实体、值对象,领域服务
	基础层:数据库、总线、API网关、缓存

微服务确实也解决了原来采用集中式架构的单体应用的很多问题,比如扩展性、弹性伸缩能力、小规模团队的敏捷开发等等。而按照 DDD 方法设计出的微服务的业务和应用边界都非常合理,可以很好地实现微服务内部和外部的“高内聚、低耦合”。

DDD10大核心概念

公司在 IT 系统建设过程中,由于预算和资源有限,对不同类型的子域应有不同的关注度和资源投入策略,记住好钢要用在刀刃上。
领域:领域就是用来确定范围、边界的,DDD的领域就是这个边界内要解决的业务问题域
领域的核心思想就是将问题域逐级细分,来降低业务理解和系统实现的复杂度。
通过领域细分,逐步缩小微服务需要解决的问题域,构建合适的领域模型,而领域模型映射成系统就是微服务了。

子域:领域可以进一步划分为子领域。我们把划分出来的多个子领域称为子域,每个子域对应一个更小的问题域或更小的业务范围。
	子域可以根据自身重要性和功能属性划分为三类子域,它们分别是:核心域、通用域和支撑域。
	子域还可根据需要进一步拆分为子子域,比如,支付子域可继续拆分为收款和付款子子域。

核心域:决定产品和公司核心竞争力的子域是核心域,它是业务成功的主要因素和公司的核心竞争力。

通用域:没有太多个性化的诉求,同时被多个子域使用的通用功能子域是通用域
	比如认证、权限等等,这类应用很容易买到,没有企业特点限制,不需要做太多的定制化

支撑域:有一种功能子域是必需的,但既不包含决定产品和公司核心竞争力的功能,也不包含通用功能的子域,它就是支撑域。
	支撑域则具有企业特性,但不具有通用性,例如数据代码类的数据字典等系统。

限界上下文:定义领域边界的利器,限界上下文本质上也是子域。
	通用语言定义上下文含义,可以解决交流障碍这个问题,使领域专家和开发人员能够协同合作,从而确保业务需求的正确表达。
		通用语言贯穿DDD整个设计过程,将业务需求准确转化为代码设计
		通用语言包含术语和用例场景,并且能够直接反映在代码中。
		通用语言中的名词可以给领域对象命名,如商品、订单等,对应实体对象;
		而动词则表示一个动作或事件,如商品已下单、订单已付款等,对应领域事件或者命令。
	
	限界上下文则定义领域边界,用来封装通用语言和领域对象,提供上下文环境,
	保证在领域之内的一些术语、业务相关对象等(通用语言)有一个确切的含义,没有二义性。
	这个边界定义了模型的适用范围,使团队所有成员能够明确地知道什么应该在模型中实现,什么不应该在模型中实现。
		限界上下文确定了微服务的设计和拆分方向,是微服务设计和拆分的主要依据。
		如果不考虑技术异构、团队沟通等其它外部因素,一个限界上下文理论上就可以设计为一个微服务。

实体(Entity):实体是看得到、摸得着的实实在在的业务对象,实体具有业务属性、业务行为和业务逻辑。
	有这样一类对象,它们拥有唯一标识符,且标识符在历经各种状态变更后仍能保持一致。对这些对象而言,重要的不是其属性,而是其延续性和标识,
	对象的延续性和标识会跨越甚至超出软件的生命周期。我们把这样的对象称为实体。
	领域模型中的实体是多个属性、操作或行为的载体。
	代码模型中,实体的表现形式是实体类,这个类包含了实体的属性和方法,通过这些方法实现实体自身的业务逻辑。
		这些实体类通常采用充血模型,与这个实体相关的所有业务逻辑都在实体类的方法中实现,跨多个实体的领域逻辑则在领域服务中实现。
	实体以 DO(领域对象)的形式存在,每个实体对象都有唯一的 ID。
	在领域模型映射到数据模型时,一个实体可能对应 0 个、1 个或者多个数据库持久化对象。大多数情况下实体与持久化对象是一对一。
		在某些场景中,有些实体只是暂驻静态内存的一个运行态实体,它不需要持久化。比如,基于多个价格配置数据计算后生成的折扣实体。

值对象(ValueObject):值对象只是若干个属性的集合,只有数据初始化操作和有限的不涉及修改数据的行为,基本不包含业务逻辑。
	值对象的属性集虽然在物理上独立出来了,但在逻辑上它仍然是实体属性的一部分,用于描述实体的特征。
	值对象本质上是一个集合,将“省、市、县和街道等属性”拿出来构成一个“地址属性集合”,这个集合就是值对象了。
	实体和值对象是组成领域模型的基础单元。

	值对象嵌入到实体的话,有这样两种不同的数据格式,也可以说是两种方式,分别是属性嵌入的方式和序列化大对象(JSON)的方式。

	在领域建模时,我们可以将部分对象设计为值对象,保留对象的业务涵义,同时又减少了实体的数量;
	在数据建模时,我们可以将值对象嵌入实体,减少实体表的数量,简化数据库设计。
	
	有些场景中,地址会被某一实体引用,它只承担描述实体的作用,并且它的值只能整体替换,这时候你就可以将地址设计为值对象,比如收货地址。
	而在某些业务场景中,地址会被经常修改,地址是作为一个独立对象存在的,这时候它应该设计为实体,比如行政区划中的地址信息维护。	

聚合(Aggregate):领域模型内的实体和值对象就好比个体,而能让实体和值对象协同工作的组织就是聚合,
	它用来确定这些领域对象在实现共同的业务逻辑时,能保证数据的一致性
	聚合是数据修改和持久化的基本单元。
	
	聚合有一个聚合根和上下文边界,这个边界根据业务单一职责和高内聚原则,定义了聚合内部应该包含哪些实体和值对象,
	而聚合之间的边界是松耦合的。按照这种方式设计出来的微服务自然就是“高内聚、低耦合”的。
	聚合可以独立作为一个微服务,以满足版本的高频发布和极致的弹性伸缩能力

聚合根(AggregateRoot):
	聚合根的主要目的是为了避免由于复杂数据模型缺少统一的业务规则控制,而导致聚合、实体之间数据不一致的问题
	把聚合比作组织,那聚合根就是这个组织的负责人。聚合根也称为根实体,它不仅是实体,还是聚合的管理者。
	聚合之间通过聚合根ID关联引用,如果需要访问其他聚合的实体,就要先访问聚合根,
	再导航到聚合内部实体,外部对象不能直接访问聚合内实体

设计过程中我们可以用一些表格,来记录事件风暴和微服务设计过程中产生的领域对象及其属性。比如,领域对象在 DDD 分层架构中的位置、属性、依赖关系以及与代码模型对象的映射关系等。

聚合的设计原则

    1、在一致性边界内建模真正的不变条件。聚合用来封装真正的不变性,而不是简单的将对象组合在一起。
		各实体和值对象按照统一的业务规则运行,实现数据的一致性,边界之外的任何东西都与该聚合无关,
		这就是聚合能实现业务高内聚的原因。
	2、设计小聚合。小聚合设计可以降低业务过大导致聚合重构的可能性,让领域模型更能适应业务的变化。
	3、通过唯一标识引用其他聚合。聚合之间是通过关联外部聚合根ID的方式引用,而不是直接对象引用的方式。
	4、在边界之外使用最终一致性。聚合内数据强一致性,而聚合之间数据最终一致性。
		在一次事务中,最多只能修改一个聚合的状态,如果一次业务操作涉及多个聚合状态的更改,
		应采用领域事件的方式异步修改相关的聚合,实现聚合之间的解耦
	5、通过应用层实现跨聚合的服务调用。为实现微服务内聚合之间的解耦,以及未来以聚合为单位的微服务组合和拆分,
		应避免跨聚合的领域服务调用和跨聚合的数据库表关联。

本篇文章我列举了一些关于领域驱动设计的一些核心概念,我觉着这些概念对以后理解领域驱动设计起着十分重要的重要。虽然偏理论,但已经很简化了其实。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值