在 DDD 是银弹吗? 中,D瓜哥分享了关于领域驱动设计的三个问题。最近在读一本书 《架构设计2.0:大型分布式系统架构方法论与实践》。(这本书还不错,推荐)这本书中,花了两个章节的篇幅,重点谈论了领域驱动设计。引用书中的观点,结合个人开发经验,再来谈一谈 DDD 是否是银弹?
软件建模的困难 首先,必须面对的一个事实是:软件建模,困难重重;尤其是对于复杂业务的建模,更是难上加难。
对于复杂业务的软件开发,其生命周期大概分为如下五个阶段:
确定业务目标和业务价值。
比如某消费信贷业务。
目标被拆解成一系列核心功能点。
比如消费信贷下的授信、交易、账务等。
围绕这些功能点定义业务流程、业务规则,以及整个过程设计什么样的业务数据或业务对象。
比如账单分期金额必须大于 100 元。
领域建模。
比如对账务系统进行建模。
基于领域模型做技术架构的设计。
比如是否要做读写分离?是否要做分库分表等?
史前时期最骇人的景象,莫过于一群巨兽在焦油坑里做垂死前的挣扎。不妨闭上眼睛想像一下,你看到了一群恐龙、长毛象、剑齿虎正在奋力挣脱焦油的束缚,但越挣扎,焦油就缠得越紧,就算他再强壮、再厉害,最后,都难逃灭顶的命运。过去十年间,大型系统的软件开发工作就像是掉进了焦油坑里……
— 佛瑞德·布鲁克斯(Frederick P. Brooks) 《人月神话》 应该早在 2019 年,在 左耳朵耗子哥 的推荐下阅读了 《领域驱动设计》,并将读书摘要整理成几篇文章:
《领域驱动设计》读书笔记(一):运用领域模型
《领域驱动设计》读书笔记(二):模型驱动设计的构造块
《领域驱动设计》读书笔记(三):通过重构来加深理解
《领域驱动设计》读书笔记(四):战略设计
部门要搞 DDD 和体系化建设,正好有一个核心项目要做重构,领导让实践一下领域驱动设计,苦于没有范例可以参考,感觉无处下手,所以又读了 《中台架构与实现·基于DDD和微服务》(最早读的是极客时间专栏,后专栏编撰成该书)。
我们面临的真正挑战是找到深层次的模型,这个模型不但能够捕捉到领域专家的微妙的关注点,还可驱动切实可行的设计。我们的最终目的是开发出能够捕捉到领域深层含义的模型。
要想成功地开发出实用的模型,需要注意以下 3 点:
复杂巧妙的领域模型是可以实现的,也是值得我们去花费力气实现的。
这样的模型离开不断的重构是很难开发出来的,重构需要领域专家和热爱学习领域知识的开发人员密切参与进来。
要实现并有效地运用模型,需要精通设计技巧。
重构就是在不改变软件功能的前提下重新设计它。
自动化的单元测试套件能够保证对代码进行相对安全的试验。
设计模式重构 — 为实现更深层模型而进行的重构。
代码细节重构
简称为“领域模型重构”。 学习以更高维度去看待问题。
《重构》一书中所列出的重构分类涵盖了大部分常用的代码细节重构。这些重构主要是为了解决一些可以从代码中观察到的问题。
领域模型会随着新认识的出现而不断变化,由于其变化如此多样,以至于根本无法整理出一个完整的目录。
建模和设计都需要你发挥创造力。
对象分析的传统方法是先在需求文档中确定名词和动词,并将其作为系统的初始对象和方法。
事实上,初始模型通常都是基于对领域的浅显认知而构建的,既不够成熟也不够深入。
遵循“职责驱动设计”的原则,
“契约式设计”思想。
开发一个好的领域模型是一门艺术。
图 1. 模型驱动设计语言 第 4 章 分离领域 模式:Layered Architecture 在面向对象的程序中,常常会在业务对象中直接写入用户界面、数据库访问等支持代码。而一些业务逻辑则会被嵌入到用户界面组件和数据库脚本中。这么做是为了以最简单的方式在短期内完成开发工作。
如果与领域有关的代码分散在大量的其他代码之中,那么查看和分析领域代码就会变得异常困难。对用户界面的简单修改实际上很可能会改变业务逻辑,而要想调整业务规则也很可能需要对用户界面代码、数据库操作代码或者其他的程序元素进行仔细的筛查。这样就不太可能实现一致的、模型驱动的对象了,同时也会给自动化测试带来困难。考虑到程序中各个活动所涉及的大量逻辑和技术,程序本身必须简单明了,否则就会让人无法理解。
要想创建出能够处理复杂任务的程序,需要做到关注点分离——使设计中的每个部分都得到单独的关注。
Layered Architecture 的基本原则是层中的任何元素都仅依赖于本层的其他元素或其下层的元素。
图 2. 应用分层
序 控制复杂性的关键是有一个好的领域模型,这个模型不应该仅仅停留在领域的表面,而是要透过表象抓住领域的实质结构,从而为软件开发人员提供他们所需的支持。
在领域建模过程中不应将概念与实现割裂开来。
概念与实现密不可分的最主要原因在于,领域模型的最大价值是它提供了一种通用语言,这种语言是将领域专家和技术人员联系在一起的纽带。
领域模型并不是按照“先建模,后实现”这个次序来工作的。
真正强大的领域模型是随着时间演进的,即使是最有经验的建模人员也往往发现他们是在系统的初始版本完成之后才有了最好的想法。
既品尝过成功的美酒,也体验过失败的沮丧。
前言 真正决定软件复杂性的是设计方法。
很多应用程序最主要的复杂性并不在技术上,而是来自领域本身、用户的活动或业务。
领域驱动设计是一种思维方式,也是一组优先任务,它旨在加速那些必须处理复杂领域的软件项目的开发。
领域驱动设计的实质就是消化吸收大量知识,最后产生一个反映深层次领域知识并聚焦于关键概念的模型。
极端的简约主义是解救那些过度追求设计的执迷者的良方。
实际上, XP最适合那些对设计的感觉很敏锐的开发人员。 XP过程假定人们可以通过重构来改进设计,而且可以经常、快速地完成重构。
首先需要深入研究模型,然后基于最初的(可能是不成熟的)模型实现一个初始设计,再反复改进这个设计。每次团队对领域有了新的理解之后,都需要对模型进行改进,使模型反映出更丰富的知识,而且必须对代码进行重构,以便反映出更深刻的模型,并使应用程序可以充分利用模型的潜力。 第一部分 运用领域模型
模型是一种简化。它是对现实的解释——把与解决问题密切相关的方面抽象出来,而忽略无关的细节。