DDD的精髓
2022-09-29 08:53:30 1 举报
AI智能生成
DDD的精髓
作者其他创作
大纲/内容
定义
通过统一(产品各个开发阶段中使用的)术语、业务抽象、领域划分和领域建模等系列手段来控制软件复杂度的方法论
起源
2003年一位外国人Eric Evans出版的书中提出的概念
革命性
是一种面向对象分析的方法论,可利用封装、多态有效化解复杂性
简单案例:银行转账
不使用DDD思想的实现:数据驱动
定义一个拥有balance属性(同时有getter&setter)的Account对象,然后在一个TransferTransactionFunc
事务函数中分别查出对应的account实体, 再直接调用实体的getter&setter方法获取和
更新balance,计算过程也呈现这个函数中,没有过多封装;
*特点*:是初期实现简单、直观,但随着业务需求迭代,这样的代码就不好优化,也不可能把新逻辑都堆
在此方法中,特别是在后期来重新优化改造,成本巨大,易出bug
事务函数中分别查出对应的account实体, 再直接调用实体的getter&setter方法获取和
更新balance,计算过程也呈现这个函数中,没有过多封装;
*特点*:是初期实现简单、直观,但随着业务需求迭代,这样的代码就不好优化,也不可能把新逻辑都堆
在此方法中,特别是在后期来重新优化改造,成本巨大,易出bug
使用DDD思想的实现:领域驱动
在方案一的基础上进行改进,Account对象增加incr/decr即增减余额方法,然后事务函数就只需要调用account
实体的incr/decr方法完成业务逻辑了
*特点*:在初期就将职责划分的比较清晰,增减余额应当归于Account自身的逻辑,不应暴露给外部操作;相比
方案一来说,强化了域(Domain)的概念,将域的职责进行严格划分(域是一个泛概念,可以指代类,服务);
这样,在后期优化时,改动的是Account的方法而不是事务函数,同时提醒后面的开发人员延续这种封装风格
实体的incr/decr方法完成业务逻辑了
*特点*:在初期就将职责划分的比较清晰,增减余额应当归于Account自身的逻辑,不应暴露给外部操作;相比
方案一来说,强化了域(Domain)的概念,将域的职责进行严格划分(域是一个泛概念,可以指代类,服务);
这样,在后期优化时,改动的是Account的方法而不是事务函数,同时提醒后面的开发人员延续这种封装风格
主要特点
1. 着重关心的是业务中的领域划分和领域建模
2. 开发过程也不再以数据模型为起点,而是以领域模型为出发点
3. 领域模型对应的是业务实体,在代码中表现为类、服务、对象等;
更关注业务语义的显性化表达,而不是数据存储和数据之间的关系,这是和“数据驱动设计”显著的区别
更关注业务语义的显性化表达,而不是数据存储和数据之间的关系,这是和“数据驱动设计”显著的区别
4. 研发过程:需求分析 —— 领域分析 —— 领域建模 —— 具体逻辑
提及ORM
曾经ORM非常🔥,提供了各种映射方式(继承映射、多对多映射等)以实现数据模型和
领域模型的统一,但实际效果差强人意,甚至导致原来的数据模型也变成四不像;
领域模型的统一,但实际效果差强人意,甚至导致原来的数据模型也变成四不像;
问题所在: 数据库存在的实体可以映射,但不存在的就无法映射了,过于理想化~
解法:ORM只负责数据库实体一对一建模即可,领域建模由人工预先规划好,然后在代码中
通过类(或结构体)和方法去灵活实现
解法:ORM只负责数据库实体一对一建模即可,领域建模由人工预先规划好,然后在代码中
通过类(或结构体)和方法去灵活实现
优势
1. 统一术语
主要思想:通过在业务和代码中的技术之间采用共同术语达到让开发的程序
和业务相匹配的效果
和业务相匹配的效果
业务语言中的术语由业务侧和技术侧同事共同协商定义,目的是创建大家都认可,无歧义的统一术语
代码、类、方法、属性和模块的命名必须和统一术语相匹配,必要时对代码进行重构
最终收益:极大提升业务部门和技术部门的沟通&工作效率
2. 面向对象
DDD的核心是领域模型,而领域模型的精髓则在于面向对象、对事物的抽象能力;
一个DDD架构师必然是一个面向对象分析大师
一个DDD架构师必然是一个面向对象分析大师
DDD鼓励我们接到需求后的第一步是考虑领域模型,而不是切割为数据和行为;
强调的是业务抽象和面向对象编程,而不是过程式编程,重点不同,导致代码实现架构完全不同
3. 业务语义显性化
前面2点都是为了提高代码可读性和可维护性。同时,代码也尽可能体现出了领域实体之间的关系原貌,
让代码更容易理解和维护,显然就降低了系统复杂度
让代码更容易理解和维护,显然就降低了系统复杂度
4. 分离业务逻辑和技术细节
代码复杂度是由业务复杂度和技术复杂度组成的,DDD让我们可以分离业务逻辑和技术细节,
比如业务逻辑是给某账户加/减钱,那技术细节就是在对应数据表中更改数据
比如业务逻辑是给某账户加/减钱,那技术细节就是在对应数据表中更改数据
DB、Framework、Component(不论前后端)都是技术细节,不应该影响业务逻辑的实现
核心概念
领域实体
代码世界中定义的能够一对一对应现实世界中事物的实体(对象),以及它们的职责、行为和之间关系
- 比如租房业务中有租客和房东(还有中介、房子)几个角色和事物,那么建模后代码中也会定义对应的对象
聚合根(Aggregate Root)
是DDD中的一个概念,是一中更大范围的封装。它把一组具有相同生命周期、在业务上
不可分割的实体和值对象放在一起,只有根实体可以对外暴露引用(也是内聚的体现)
不可分割的实体和值对象放在一起,只有根实体可以对外暴露引用(也是内聚的体现)
- 比如房东是房子(实体)、房东个人信息(值对象)以及房东钱包(实体)的聚合根
领域服务(Domain Service)
有些领域中的动作是动词,看上去并不属于任何对象。这时不能忽略它们或
简单将其归类到某个实体或值对象中;推荐的实践方式是将它声明为一个服务,即Service
简单将其归类到某个实体或值对象中;推荐的实践方式是将它声明为一个服务,即Service
- 比如银行转账案例中,转账行为发生在两个账号之间,将其归属于某个账号并不合适,所以
直接命名为MoneyTransferDomainService就比较合适
直接命名为MoneyTransferDomainService就比较合适
识别这个主要看其是否满足3个特征
1. 执行的操作代表了一个领域概念,其无法自然的隶属于一个实体或值对象
2. 执行的操作设计领域中的其他实体
3. 操作是无状态的
领域事件(Domain Event)
定义:是一个特点领域由一个用户动作触发的事件,且这个事件是系统其他部分和关联系统感兴趣的
(可理解为分布式系统中生产于用户,消息组件暂存的事件)
(可理解为分布式系统中生产于用户,消息组件暂存的事件)
注意几点
1. 事件命名:推荐使用DomainName+动词过去式+Event
- 比如MoneyTransferedEvent、MoneyTransferFailedEvent
- 比如MoneyTransferedEvent、MoneyTransferFailedEvent
2. 事件内容:计算机术语中叫payload,有两种形式,根据具体情况选择
2.1 自恰:在事件payload中尽可能多放数据,这样消费者不需回查数据
2.2 回查:在payload中只放xx_id,让消费者需要时自行查询
边界上下文(Bounded Context)
领域实体的意义是有上下文边界的
- 比如同样是apple,手机店和水果店的apple就完全不同
- 比如同样是apple,手机店和水果店的apple就完全不同
在同一个上下文中,要保证模型在逻辑上统一
扩展——防腐层(Anti-corruption layer)
定义:介于新应用和遗留应用之间,用于确保新应用的设计不受老应用的限制,
是一种在不同应用间转换的机制。
是一种在不同应用间转换的机制。
创建一个防腐层,以根据客户端自己的域模型为客户提供功能。该层通过其现有接口与另一个系统
进行通信,几乎不需要或不需要对其进行任何修改。因此,防腐层隔离不仅是为了保护您免受混乱
的代码的侵害,还在于分离不同的域并确保它们在将来保持分离。
进行通信,几乎不需要或不需要对其进行任何修改。因此,防腐层隔离不仅是为了保护您免受混乱
的代码的侵害,还在于分离不同的域并确保它们在将来保持分离。
防腐层是将一个域映射到另一个域,这样使用第二个域的服务就不必被第一个域的概念“破坏”
在不共享相同语义的不同子系统之间实施外观或适配器层。 此层转换一个子系统向另一个子系统发出
的请求,使用防腐层模式可确保应用程序的设计不受限于对外部子系统的依赖。
的请求,使用防腐层模式可确保应用程序的设计不受限于对外部子系统的依赖。
这是2017年微软团队提出的9个微服务设计模式之一
推荐CSDN博客的一篇介绍
领域建模方法
1. 用例分析法
2. 四色建模法
(使用时再查询每个方法的具体细节)
模型演化
建模不是一次性工作,业务在变,模型也会变化,必要时需要进行代码重构
为什么DDD饱受争议
背景:有不少DDD实践失败的案例,它们声称实践了DDD,但并没有控制住复杂度(甚至增加了~)
原因1:很多人是通过阅读《领域驱动设计:软件核心复杂性应对之道》入门DDD的,无脑照搬书中
概念(Repository/Domain/ValueObject),没有领悟精髓;对于一个OOP高手而言,不使用这些概念也能实现DDD
概念(Repository/Domain/ValueObject),没有领悟精髓;对于一个OOP高手而言,不使用这些概念也能实现DDD
原因2:抽象的灵活性
- 不同于纯粹的技术,领域建模主要考验一个人的抽象能力,这非常依赖个人经验和综合能力。
因此,若团队决定实践DDD,必须由一个经验丰富的人带领,否则不合理的抽象不如没有抽象,
使得系统最终成为一个“异形”
- 不同于纯粹的技术,领域建模主要考验一个人的抽象能力,这非常依赖个人经验和综合能力。
因此,若团队决定实践DDD,必须由一个经验丰富的人带领,否则不合理的抽象不如没有抽象,
使得系统最终成为一个“异形”
原因3:领域层的边界
- 在DDD架构中,核心部分是领域层(Domain layer),但是Application和Domain层的边界是很模糊的,
分不清边界会导致项目结构混乱无序
- 在DDD架构中,核心部分是领域层(Domain layer),但是Application和Domain层的边界是很模糊的,
分不清边界会导致项目结构混乱无序
总结
DDD是一门庞大的学问,有一定的学习门槛和学习曲线
实践时不可教条式照搬概念,真正的面向对象大师,即使不使用Repository、AggregateRoot
和ValueObject这些概念也能很好的实现DDD
和ValueObject这些概念也能很好的实现DDD
本思维导图内容总结自《代码精进之路—从码农到工匠》——张建飞 第7章 DDD的精髓
0 条评论
下一页