浅谈DDD

领域驱动设计

Posted by Keal on March 13, 2024

最近公司有同事分享了篇关于DDD的文章, 想来DDD第一次提出已经是2003年的东西了. 我第一次认真读关于DDD的书籍还是在InfoQ上读的其他人总结的«领域驱动设计精简版». 如今结合实际, 想再随便写一点关于DDD我的看法.

DDD是什么

DDD(Domain-Driven Design)提出是在2003年那本 Domain-Driven Design –Tackling Complexity in the Heart of Software 书中, 作者 Eric Evans 的资料很少. 能比较容易查到的是他参与开发了多个大型业务系统. 这本书算是他的一个总结.

作为一种处理复杂领域的设计思想,DDD试图分离技术实现的复杂性,并围绕业务概念构建领域模型来控制业务的复杂性,以解决软件难以理解,难以演进的问题。它通过边界划分将复杂业务领域简单化,帮我们设计出清晰的领域和应用边界,可以很容易地实现架构演进。

DDD是面向对象的设计思想,是面向对象设计的一种升华。它提供的是一个从现实业务到程序运行期间整个过程的方案, 既有代码编写前的顶层 战略设计:指导领域的划分, 也有实际代码开发中的 战术设计: 从类命名到整体服务的架构选择设计.

DDD的开放性

领域驱动设计是一种方法论(Methodology),根据维基百科的定义,方法论是一套运用到某个研究领域的系统与理论分析方法。领域驱动设计就是针对软件开发领域提出的一套系统与理论分析方法。Eric Evans 在创造性地提出领域驱动设计时,实则是针对当时项目中聚焦在以数据以及数据样式为核心的系统建模方法的批判。面向数据的建模方法是关系数据库理论的延续,关注的是数据表以及数据表之间关系的设计。这是典型的面向技术实现的建模方法,面对日渐复杂的业务逻辑,这种设计方法欠缺灵活性与可扩展性,也无法更好地利用面向对象设计思想及设计模式,建立可重用的、可扩展的代码单元。领域驱动设计的提出,是设计观念的转变,蕴含了全新的设计思想、设计原则与设计过程

由于领域驱动设计是一套方法论,它建立了以领域为核心驱动力的设计体系,因而具有一定的开放性。在这个体系中,你可以使用不限于领域驱动设计提出的任何一种方法来解决这些问题。例如,可以使用用例(Use Case)、测试驱动开发(TDD)、用户故事(User Story)来帮助我们对领域建立模型;可以引入整洁架构思想及六边形架构,以帮助我们建立一个层次分明、结构清晰的系统架构;还可以引入函数式编程思想,利用纯函数与抽象代数结构的不变性以及函数的组合性来表达领域模型。这些实践方法与模型已经超越了 Eric Evans 最初提出的领域驱动设计范畴,但在体系上却是一脉相承的。这也是为什么在领域驱动设计社区,能够不断诞生新的概念诸如 CQRS 模式、事件溯源(Event Sourcing)模式与事件风暴(Event Storming);领域驱动设计也以开放的心态拥抱微服务(Micro Service),甚至能够将它的设计思想与原则运用到微服务架构设计中。

DDD实际举例

从一个电影院业务系统的实践来举例描述DDD的方法.

  1. 统一语言, 原文称为Ubiquitous Language, 这个好理解, 就是大家对这个业务相关的词不要产生歧义, 不能说影院你说是cinema, 他说是theater, 可能统称为site,关键在于大家要有共识,为后面的构建领域模型做基础
  2. 领域划分, 根据业务情况,一个领域有哪些模型, 模型之间的关系是什么. , 引入限界上下文(Bounded Context)上下文映射(Context Map)来区分出核心领域(Core Domain)子领域(SubDomain), 比如可能会区别出有影厅,票务,影片这几个领域. 有了这些提炼出来的领域, 就可以设计或者选择一个适合的架构, 比如跟领域模型十分契合的微服务架构.
  3. 程序设计, 这部分主要是当划分了各个领域之后, 根据各领域的不同需求,内部采用不同的程序设计. 举个例子就是微服务里各个服务可能采用了不同的语言,不同的设计风格, 这取决于领域的复杂度和实际需求. 你当然可以在一个web项目中采用MVC或MVP架构, 也可以采用分层架构设计一个简单的内部服务.
  4. 编码实现, 实现你的那些设计!

上面只是一个很简单的基于DDD理论的实践路径, 在描述各个领域的模型时, 提供了很多概念要素,这里仅仅罗列一下方便知道有这些.

  • 值对象(Value Object)
  • 实体(Entity)
  • 领域服务(Domain Service)
  • 领域事件(Domain Event)
  • 资源库(Repository)
  • 工厂(Factory)
  • 聚合(Aggregate)
  • 应用服务(Application Service)

OK,你现在可能大概知道领域模型的内容. 但是实践上,每个人都会遇到一些现实问题,比如:

领域如何划分?

有人问过《实现领域驱动设计》作者 Vaughn Vernon 是如何去做的, 得到的答案是”By experience!”. 可想而知, 划分领域事情本身,就已经让一个应试教育的精英头疼了! 不过我想这也是DDD的开放之处吧(笑)

如果业务发生变更怎么办?

想要贴近DDD, 最佳做法当然是重构. 特别是随着业务发展,之前划分的领域的限界上下文变得模糊不清的时候. 但事情很可能是朝着阻力最小而非最正确的方向走, 现实里大家更愿意在自己旧的领域中冗余更多的信息, 而非与人沟通一起重构.

我是如何看待DDD的

Domain-Driven Design –Tackling Complexity in the Heart of Software 这本书是2003年了. 在2024年的当下, 微服务架构随着虚拟机,容器技术的发展而随之流行, DDD战略设计中的领域划分思想与微服务出乎意料的契合. 但DDD提供的战术设计, 并非适用一切问题的银弹. 软件设计20多年的发展, 基于底层的一些设计原则和方向, 诞生了许多降低系统复杂度的架构设计和方法. Golang,Rust等程序语言的流行使得面向对象的设计思想也不再是一家独大, DDD推荐的许多实践方法, 是需要贴合自己所处的实际情况来参考的.

最后

最后吐槽一句, 国内的技术氛围,让我总感觉与网上脱轨. 例如Java在国内的主流地位和世界编程语言排名的差异. 还有关于中台的看法随着阿里市值的变迁而变迁. 所谓技术追着市值跑, 谁市值高,谁讲出来的技术就牛逼. 看到这里估计有人以为我是在嘲讽阿里, 其实我是在说大部分程序员根本就不想去了解和研究技术和现实问题, 最希望的就是有个能解决所有问题的银弹. 互联网和github就扮演了类似这样的角色, 但偏偏这样的人很可能是互联网发声最多的人,现实比想象中更可笑.