初探DDD

简介: 基于学习《殷浩详解DDD:领域层设计规范》后的动手实践,简单总结,以及个人理解

基础概念:Domain Primitive(DP/原子领域)

就好像Integer、String是所有编程语言的Primitive一样,DP是 DDD的 原子类型、基础类型

在DDD里,DP可以说是一切模型、方法、架构的基础,就像Integer、String一样,DP在DDD里,又是无所不在的。

DP的定义

Domain Primitive (DP)是一个在特定领域里,拥有精准定义的、可自我验证的、拥有行为的 Value Object 。

  1. DP是一个传统意义上的Value Object,拥有Immutable的特性
  2. DP是一个完整的概念整体,拥有精准定义
  3. DP使用业务域中的原生语言
  4. DP可以是业务域的最小组成部分、也可以构建复杂组合

什么情况下应该用Domain Primitive

常见的DP的使用场景包括:

  • 有格式限制的String:比如NamePhoneNumberOrderNumberZipCodeAddress
  • 有限制的Integer:比如OrderId(>0),Percentage(0-100%),Quantity(>=0)等
  • 可枚举的int:比如Status(一般不用Enum因为反序列化问题)
  • DoubleBigDecimal:一般用到的DoubleBigDecimal都是有业务含义的,比如TemperatureMoneyAmountExchangeRateRating
  • 复杂的数据结构:比如Map>等,尽量能把Map的所有操作包装掉,仅暴露必要行为

DP三原则

  • 将隐性的概念显性化。
  • 将 隐性的 上下文 显性化
  • 封装 多对象 行为

案例




使用DDD进行应用架构

一个好的应用架构,应该需要实现以下几个目标:

  1. 独立于框架:架构不应该依赖某个外部的库或框架,不应该被框架的结构所束缚。
  2. 独立于UI:前台展示的样式可能会随时发生变化(今天可能是网页、明天可能变成console、后天是独立app),但是底层架构不应该随之而变化。
  3. 独立于底层数据源:无论今天你用MySQL、Oracle还是MongoDB、CouchDB,甚至使用文件系统,软件架构不应该因为不同的底层数据储存方式而产生巨大改变。
  4. 独立于外部依赖:无论外部依赖如何变更、升级,业务的核心逻辑不应该随之而大幅变化。
  5. 可测试:无论外部依赖了什么数据库、硬件、UI或者服务,业务的逻辑应该都能够快速被验证正确性。

防腐层


这种常见的设计模式叫做Anti-Corruption Layer(防腐层或ACL)。

很多时候我们的系统会去依赖其他的系统,而被依赖的系统可能包含不合理的数据结构、API、协议或技术实现,如果对外部系统强依赖,会导致我们的系统被”腐蚀“。

这个时候,通过在系统间加入一个防腐层,能够有效的隔离外部依赖和内部逻辑,无论外部如何变更,内部代码可以尽可能的保持不变。

ACL不仅仅只是多了一层调用,在实际开发中ACL能够提供更多强大的功能:

  • 适配器:很多时候外部依赖的数据、接口和协议并不符合内部规范,通过适配器模式,可以将数据转化逻辑封装到ACL内部,降低对业务代码的侵入。在这个案例里,我们通过封装了ExchangeRate和Currency对象,转化了对方的入参和出参,让入参出参更符合我们的标准。
  • 缓存:对于频繁调用且数据变更不频繁的外部依赖,通过在ACL里嵌入缓存逻辑,能够有效的降低对于外部依赖的请求压力。同时,很多时候缓存逻辑是写在业务代码里的,通过将缓存逻辑嵌入ACL,能够降低业务代码的复杂度。
  • 兜底:如果外部依赖的稳定性较差,一个能够有效提升我们系统稳定性的策略是通过ACL起到兜底的作用,比如当外部依赖出问题后,返回最近一次成功的缓存或业务兜底数据。这种兜底逻辑一般都比较复杂,如果散落在核心业务代码中会很难维护,通过集中在ACL中,更加容易被测试和修改。
  • 易于测试:类似于之前的Repository,ACL的接口类能够很容易的实现Mock或Stub,以便于单元测试。
  • 功能开关:有些时候我们希望能在某些场景下开放或关闭某个接口的功能,或者让某个接口返回一个特定的值,我们可以在ACL配置功能开关来实现,而不会对真实业务代码造成影响。同时,使用功能开关也能让我们容易的实现Monkey测试,而不需要真正物理性的关闭外部依赖。


抽象数据存储层

抽象第三方服务

抽象中间件



个人理解

 目前个人理解就是将一些可封装成DP的数据类型,封装成DP,在DP内完成对数据的强校验,错误处理,提高在入参时的清晰度,最终实现降低业务代码的耦合度,提高可测性,做到一次修改DP模型内的校验,定义,在逻辑发生改变时,在DP模型内进行修改即可。

在应用层面,就是面向接口编程,尽量实现不耦合强依赖某个实现,可灵活替换底层实现。通常加入防腐层设计模式实现依赖解耦。

相关文章
|
6月前
|
数据库
DDD架构浅谈
DDD架构浅谈
139 4
|
存储 负载均衡 算法
一文揭秘DDD到底解决了什么问题(2)
一文揭秘DDD到底解决了什么问题
105 0
一文揭秘DDD到底解决了什么问题(2)
|
存储 安全 大数据
一文揭秘DDD到底解决了什么问题(3)
一文揭秘DDD到底解决了什么问题
68 0
一文揭秘DDD到底解决了什么问题(3)
|
运维 数据挖掘 测试技术
一文揭秘DDD到底解决了什么问题(4)
一文揭秘DDD到底解决了什么问题
101 0
一文揭秘DDD到底解决了什么问题(4)
|
消息中间件 存储 架构师
一文揭秘DDD到底解决了什么问题(1)
一文揭秘DDD到底解决了什么问题
161 0
|
存储 安全 大数据
DDD到底解决了什么问题
DDD作为架构设计思想帮助微服务控制规模复杂度,那它是怎么做到的呢?
21736 1
DDD到底解决了什么问题
|
存储 设计模式 运维
DDD的关键理解
当我们在学习DDD的过程中,感觉学而不得的时候,可能会问:我们还要学么?这的确引人深思。本文基于工作经验,尝试谈谈对DDD的一些理解。
DDD的关键理解
|
存储 安全 架构师
一文揭秘 DDD 到底解决了什么问题
一文揭秘 DDD 到底解决了什么问题
285 0
|
安全 程序员 微服务
DDD战略战术
DDD开篇总结》[1]的前三篇已经阐述了几个内容 1.DDD是什么2.复杂系统的特征3.DDD如何应对复杂系统4.模型概念5.软件开发流程 但一般DDD资料中都会分为两部分讲述:战略和战术,所以按这两种分类,重新归纳整合一下
371 0
DDD战略战术
|
存储 数据库
DDD之形
DDD现在已然变成哲学,正因为是哲学,所以法无定法,到底怎么具体怎么实施,各显神通,心法固然重要,但心法有几人能真正领悟,一说就懂,一问就不会,一讨论就吵架;所以还是从外形看看,收集一些实践后的形态,由表入里,以形学形,慢慢品 看下面两个分层,左边是Vaughn Vernon 在《实现领域驱动设计》一书中给出了改良版的分层架构,他将基础设施层奇怪地放在了整个架构的最上面;右边就是DDD最标准的分层形态
170 0
DDD之形