领域驱动设计实践(战术篇)

b9db2740-7705-11e9-b77d-2109c5a029d4领域驱动设计实践(战术篇)_第1张图片

课程内容

访谈录:聊聊领域驱动设计

相信很多朋友对领域驱动设计会有这样或那样的困惑,比如领域驱动设计是什么?它在工作中有什么作用?为什么国内关于这方面的书籍少之又少?…… 为了解决这些疑惑,有幸邀请到专家张逸老师来聊聊领域驱动设计,下面是 GitChat 独家采访记录。

GitChat:在探讨领域驱动设计问题时,每个人都有每个人的认识,有的时候可能谁也无法说服对方,这时候该怎么办呢?

张逸:简单说,就是 show me your code。不管领域设计做得怎么样,最终都是要落地的,看实现的效果最有说服力。当然,为了保证交流的顺畅与效率,代码这种形式可能容易让人迷失到纷繁复杂的细节中去,因此还有一种方式就是 show me your model

这里说的 model 就是领域模型。注意,团队在交流领域驱动设计问题时,不应该只是对建模活动的产出物进行讨论,建模的过程同样非常重要。现在诸如 Event Storming 等活动都非常强调利用可视化手段把业务专家与开发团队都包含进来,大家一块协作一块交流,并利用便利贴等工具直观地展现建模活动中的每一个步骤,可以更容易消除误会与分歧。

点击了解《领域驱动设计实践(战术篇)》

GitChat:可以谈谈领域驱动设计的流程吗?比如是先建模?还是做设计?以及应用的场景是什么?

张逸:领域驱动设计强调的是将分析、设计与实现统一到一个领域模型中来,同时又相对清晰地划分为战略设计和战术设计两个阶段。当然,这两个阶段并非瀑布式的,而是迭代和演进的过程。

我认同领域模型对分析、设计与实现的统一,这个思想没有问题。但在我亲身经历的项目中,我还是发现由于沟通角色与建模目标的不同,分析、设计与实现在三个不同的活动是无法完全统一的,就好像在重构时不能实现新功能,这三顶帽子自然也不能同时戴起来。因此,我在《领域驱动战术设计实践》课程中,清晰地将这三个活动称之为领域分析建模、领域设计建模与领域实现建模,它们各自的产出是领域分析模型、领域设计模型与领域实现模型,这三者合起来就是领域模型,而这个过程就是领域模型驱动设计。

之所以在模型驱动设计前面加上“领域”作为定语,是因为我认为二者不能划等号,例如采用数据模型的,同样是模型驱动设计。在《领域驱动战术设计实践》GitChat 课程中,我根据建模视角的不同,将其分别定义为数据模型驱动设计、服务模型驱动设计、领域模型驱动设计,并用了相当篇幅的内容分别介绍了这三种不同的模型驱动设计过程。

GitChat:针对一些设计能力不足的开发团队,可以采用领域驱动设计来改进设计和编码质量吗?

张逸:我个人的观点,这二者之间有关系,但并非必要关系。领域驱动设计的关键不是设计能力,而是要抓住设计的驱动力,必须是领域,且必须要求领域专家参与到分析建模活动中来。

要说明的是,这个所谓“领域专家”不是一个头衔,也不是对技能级别的要求,它其实就是一个指代,代表“懂业务”的人:可以是客户,可以是 Product Owner,可以是业务分析师,可以是产品经理,也可以是懂业务的开发人员,甚至可以是一个负责业务分析的团队。

领域驱动设计能否成功,还是要看建模尤其是分析建模做得是否足够好,这其实是整个设计过程的上游。至于设计能力,则要看领域驱动设计与什么样的编程范式结合?常见的编程范式包括结构范式、对象范式和函数范式。因此这里的“设计能力不足”,究竟指的是哪方面的设计能力不足呢?

当然,从主流的领域驱动设计来看,主要采用的还是对象范式的设计思想与领域驱动设计结合,这就要求团队掌握基本的面向对象设计能力。这方面能力不足的团队,确实会影响到最终的设计和编码质量。这是必须要正视的问题,因此我建议那些希望实践领域驱动设计的团队,不要忘了去提高团队的面向对象设计能力

提升设计能力并非一朝一夕就可以做到。正是考虑到面向对象设计能力不足对领域驱动设计的影响,我在《领域驱动战术设计实践》GitChat 课程中尝试总结了一个相对固化的设计过程。这个过程结合了 DCI、职责驱动设计等设计方法,它不要求团队掌握太多面向对象设计思想、原则与模式,只要懂业务,完全可以以“知其然而不知其所以然”的方式去实践领域驱动设计。

这种方法不能让你的设计变得非常优秀,却可以保证你的设计不至于太糟糕,甚至可以说是不错的设计。

GitChat:应用服务与领域服务的区别是什么呢?

张逸:这个是老生常谈的问题了。从分层架构的角度看,应用服务属于应用层,领域服务属于领域层。应用层是一个包装的外观,按照该层的职责来说,应用服务根本就不该干业务的活儿,它只是一个对外公开的接口而已。

从业务粒度看,应用服务的每个公开方法会对应一个具有业务价值的业务场景或者说用例。领域服务则不然,它实现了业务功能,这个业务功能或者是无状态的,又或者是因为需要协调多个聚合,又或者需要和外部资源协作。

在针对业务场景驱动设计时,应用服务的一个方法往往会暴露给调用者,然后它再将该请求委派给领域层的对象。一般要求领域服务的粒度要小,这样可以避免设计为事务脚本的过程方式,也可以在一定程度上避免贫血模型。

总结:

  • 应用服务:一组面向业务场景的业务外观方法,只是一个对外提供接口、对内分配职责的协作对象,属于应用层。
  • 领域服务:一个领域服务对应最多一个业务场景,往往需要和聚合、Repository、甚至领域服务一起协作。

GitChat:已经上线的《领域驱动战略设计实践》与刚上线的《领域驱动战术设计实践》之间的区别是?有学习的先后顺序吗?

张逸:这两个课程刚好对应领域驱动设计的战略设计与战术设计。

前者强调系统层面的架构模式,包括限界上下文、上下文映射、分层架构等,可以运用这些模式对整个系统的领域进行“分而治之”,从而降低业务复杂度,同时围绕“领域”为核心,建立业务复杂度与技术复杂度的边界。

后者强调领域层面的设计模式,以“模型驱动设计”为主线,贯穿分析、设计与编码实现这三个不同的建模活动,并引入领域驱动设计的战术设计要素,如实体、值对象、领域服务、领域事件、聚合、资源库、工厂等。

当然在我的《领域驱动战术设计实践》课程中,我扩大了领域驱动战术设计的范畴,讲解了数据模型驱动与服务模型驱动,探讨了建模范式与编程范式之间的关系。同时,在设计过程中,我引入了职责驱动设计和 DCI 模式来阐释实体、值对象、领域服务与应用服务之间的协作关系。在编码实现过程中,我又引入了测试驱动开发来推进从设计模型到实现模型。

战略设计和战术设计并非单向的过程,而是一个迭代演进与不断融合的过程。整体来讲,前者更偏向于架构设计,后者更偏向于详细设计与编码。主要还是看读者的关注点与侧重点,并没有一个绝对的学习先后顺序。我个人还是建议先学习《领域驱动战略设计实践》,虽然它更偏向于理论,难度更高一些,但是它毕竟概括了领域驱动设计的全貌。

GitChat:「战略」这个课程分析了“EAS 系统”,在「战术」课程也介绍了“EAS 系统”,两者的侧重点有什么不同吗?

张逸:与战略设计和战术设计的侧重点一样,在「战术」课程中,会针对 EAS 系统进行领域建模,并最终对其进行编码实现。从内容来看,后者会更接地气一些,毕竟讲的是落地的实现。

将战略和战术的 EAS 系统案例结合起来,就是一个系统的完整设计案例了。

到这里,访谈录的内容就结束了,大家若对 DDD 的内容比较感兴趣的话,欢迎订阅本课程,有任何关于本课程内容的疑惑可在读者圈留言或加群交流~

分享交流

我们为本课程付费读者创建了微信交流群,以方便更有针对性地讨论课程相关问题。入群方式请到第 1-1 课末尾添加小编的微信号,并注明「DDD」。

阅读文章过程中有任何疑问随时可以跟其他小伙伴讨论,或者直接向作者提问(作者看到后抽空回复)。你的分享不仅帮助他人,更会提升自己。

点击了解《领域驱动设计实践(战术篇)》

开篇词 | 领域驱动设计的不确定性

课程背景

大家好,我是张逸,去年在 GitChat 平台上上线了一门《领域驱动战略设计实践》达人课,销量已过 4000 份,同时建了两个读者群,也邀请了十几位领域驱动设计方面的专家加入到了读者群,共同探讨和交流领域驱动设计的相关知识。

至今,两个群依然很活跃,每天都有许多问题抛出,同时又有许多问题得到了解答,还有更多的问题悬而未决,因为每个人都有自己心目中的“哈姆雷特”,谁也无法说服对方,谁也无法给出一个让所有人都认同的标准答案。这恰恰是领域驱动设计最棘手的一部分,当然,也是最让人神往的一部分——唯有不确定,方才值得去探索

在探讨领域驱动战术设计的一些问题时,总会有人纠结:这个领域对象应该定义成实体,还是值对象?领域服务和应用服务的区别是什么?聚合的边界该怎么划分?于是,各种设计问题纷至沓来,问题越辩越糊涂,到了最后,已经脱离了最初探讨问题的场景,变成了“空对空导弹”一阵乱发射,最后蓦然回首,才发现目标已然消失了。

这是不合理的。在软件开发领域,没有什么一劳永逸的实现,也没有什么放之四海而皆准的标准,必须结合具体的业务场景做出合理的决策,无论建模和设计再怎么完美,也需要通过落地的检验才知道好还是坏。任何脱离具体业务场景的问题分析,都是空谈;任何不落地的完美方案,都是浮夸。领域驱动设计没有标准,有的只是持续不断的不确定性。

正所谓“以不变应万变”,我们要从实证主义的角度看待领域驱动设计,窃以为,只需守住三项基本原则即可:

  • 必须通过领域建模来驱动设计
  • 领域专家或业务分析师必须参与到建模活动中
  • 设计必须遵循面向对象分析和设计的思想与原则

只要做到这三点,领域驱动战术设计就不会做得太差,剩下的不足,就需要靠经验来填补了。

点击了解《领域驱动设计实践(战术篇)》

课程框架

本课程是我计划撰写的领域驱动设计实践系列的第二部分课程,要解决的正是前面所提及的战术层面的设计问题。单以战术设计阶段来看,我个人认为 Eric Evans 做出的贡献并不多。在《领域驱动设计》一书中,他讲到了模型驱动设计与领域建模,却没有深入阐述该如何正确地进行领域建模;他引入的资源库模式和工厂模式,不过是面向对象设计原则的体现;至于模型的演化与重构带来的突破,其实更多是经验之谈,缺乏切实可行的方法。整体而言,Eric Evans 在战术设计要素方面,最为重要的洞见在于:

  • 强调了领域建模的重要性,并与面向对象分析和设计的原则结合起来
  • 实体与值对象的区分,有利于我们明白模型对象的真相,并能够更好地避免贫血模型
  • 聚合提出了有别于模块粒度的边界,有效地保证了业务规则的不变性和数据的一致性

不可否认,若要做到优良的领域驱动设计,建模和设计的经验是必不可少的,这需要多年的项目实战打磨方可萃取而成,但如果在开始之初,能有一些更为具体的方法作为指引,或许可以让掌握技能的周期大幅度缩短。此外,我还清楚地看到:许多领域驱动设计的门外汉,之所以迟迟不得其门而入,是因为他(她)们连最为基本的面向对象分析和设计的能力都不具备,因此,无法理解领域驱动的战术设计要素也就不足为奇了。关键在于,许多设计问题因为其不确定性,根本没有标准答案,没有任何人能给你指出明确的设计方法和设计思路。这时,就必须要吃透面向对象分析和设计的思想与原则,用它们来指导我们的设计,而不是死板的遵循领域驱动设计的模式。

针对一些设计能力不足的开发团队,若希望采用领域驱动设计来改进设计和编码质量,往往会适得其反,做出来的是一锅“夹生饭”。从理想角度讲,决定是否采用领域驱动设计,不在于团队成员的能力高低,而在于业务的复杂度。然而,我们又不得不面对现实,如果团队成员的设计能力差了,是做不好领域驱动设计的。因此,我在本课程中,一方面分享了我的设计体验和方法,以帮助团队成员的成长,另一方面也给出了一个操作性强的设计过程,可以让基础相对薄弱的开发人员能够依样画葫芦,做出还算不错的设计与实现。

这些考虑帮助我确定了本课程的基本思路,即以能学习和模仿的战术设计方法来弥补经验之不足,以设计思想和设计原则作为指导来解决争议之问题,以能够落地的解决方案来体现领域驱动设计之价值。

本课程分为六部分,共 64 篇(含访谈录、开篇词)。

  • 第一部分:软件系统中的模型(第 1-1 课 ~ 第 1-15 课)

全面讲解和对比软件系统的数据模型、服务模型和领域模型,以这些模型作为不同的设计驱动力,讲解不同的模型驱动设计之过程与利弊,从而得出领域模型驱动设计的优势以及它适用的业务场景。

  • 第二部分:领域分析模型(第 2-1 课 ~ 第 2-7 课)

建立领域分析模型是领域模型驱动设计的起点和基础。领域分析过程是领域专家与开发团队合作最为紧密、沟通最为频繁的阶段,是领域驱动设计成败的关键。我将深入介绍名词动词法、分析模式、四色建模和事件风暴等重要的分析建模方法,在发现显式和隐式领域概念的基础上,建立高质量的领域分析模型。

  • 第三部分:领域设计模型(第 3-1 课 ~ 第 3-17 课)

实体、值对象、领域服务、领域事件、资源库、工厂和聚合是组成领域驱动战术设计的核心内容,也是衡量领域驱动设计质量的分水岭。只有正确地理解了这些设计要素,才能正确地完成领域驱动战术设计。这其中扮演关键角色的其实是面向对象分析与设计。我将围绕着职责驱动设计讲解角色、职责与协作三者之间的关系,通过分辨职责来寻找合理的对象,并结合 DCI 模式与主流设计模式,以时序图作为主要的设计驱动力获得高质量的设计方案。

  • 第四部分:领域实现模型(第 4-1 课 ~ 第 4-6 课)

领域实现模型帮助我们将领域设计模型落地,毕竟,只有交付可工作的软件才是软件开发的终极目标。除了要应对纷繁复杂的业务逻辑,我们还需要考虑如何与外部资源集成,实现数据持久化与消息通信等基础设施内容。在落地过程中,我们需要时刻维护业务复杂度与技术复杂度的边界,降低彼此的影响,同时还需要在编码层次提高代码的内建质量,包括代码的可读性、可重用性、可扩展性和可测试性。

  • 第五部分:融合:战略设计和战术设计(第 5-1 课 ~ 第 5-9 课)

领域驱动设计虽然分为战略设计阶段和战术设计阶段,但这两个阶段并非完全割裂的井水不犯河水的独立过程。我在《领域驱动战略设计实践》课程中介绍领域驱动设计过程时,就提到了这两个阶段的相辅相成与迭代的螺旋上升演进过程。我们必须将战略设计和战术设计融合起来,把分层架构、限界上下文、上下文映射与战术设计的诸要素融汇贯通,才能获得最佳的设计质量,并成为指导我们进行软件架构和设计的全过程。

  • 第六部分:EAS 系统的战术设计实践(第 6-1 课 ~ 第 6-8 课)

继续沿用战略设计实践中使用的全真案例——EAS 系统,采用领域模型驱动设计的过程对系统进行分析建模、设计建模和实现建模,并最终结合战略设计的方案,形成完整的解决方案和代码实现。

综上,本课程的内容并未完全遵照 Eric Evans 的《领域驱动设计》,不同的部分固然是我的一孔之见,未必正确,也未必遵守 Eric Evans 的设计思想,但我仍然不揣冒昧地进行了分享,不是因为我的无知者无畏,而是我认为针对具有不确定性的领域驱动设计,必须要容得下异见者,方能取得发展和突破。

为什么要学习领域驱动设计

如果你已经能设计出美丽优良的软件架构,如果你只希望脚踏实地做一名高效编码的程序员,如果你是一位注重用户体验的前端设计人员,如果你负责的软件系统并不复杂,那么,你确实不需要学习领域驱动设计!

领域驱动设计当然并非“银弹”,自然也不是解决所有疑难杂症的“灵丹妙药”,请事先降低对领域驱动设计的不合现实的期望。我以中肯地态度总结了领域驱动设计可能会给你带来的收获:

  • 领域驱动设计是一套完整而系统的设计方法,它能给你从战略设计到战术设计的规范过程,使得你的设计思路能够更加清晰,设计过程更加规范;
  • 领域驱动设计尤其善于处理与领域相关的高复杂度业务的产品研发,通过它可以为你的产品建立一个核心而稳定的领域模型内核,有利于领域知识的传递与传承;
  • 领域驱动设计强调团队与领域专家的合作,能够帮助团队建立一个沟通良好的团队组织,构建一致的架构体系;
  • 领域驱动设计强调对架构与模型的精心打磨,尤其善于处理系统架构的演进设计;
  • 领域驱动设计的思想、原则与模式有助于提高团队成员的面向对象设计能力与架构设计能力;
  • 领域驱动设计与微服务架构天生匹配,无论是在新项目中设计微服务架构,还是将系统从单体架构演进到微服务设计,都可以遵循领域驱动设计的架构原则。

课程寄语

没有谁能够做到领域驱动设计的一蹴而就,一门课程也不可能穷尽领域驱动设计的方方面面。从知识的学习到知识的掌握,进而达到能力的提升,需要一个漫长的过程。所谓“理论联系实际”虽然是一句大家耳熟能详的老话,但其中蕴含了颠扑不破的真理。我在进行领域驱动设计培训时,总会有学员希望我能给出数学公式般的设计准则或规范,似乎软件设计就像拼积木一般,只要遵照图示中给出的拼搭过程,不经思考就能拼出期待的模型。——这是不切实际的幻想。

要掌握领域驱动设计,就不要被它给出的概念所迷惑,而要去思索这些概念背后蕴含的原理,多问一些为什么。同时,要学会运用设计原则去解决问题,而非所谓的“设计规范”。我强烈建议读者诸君要学会对设计的本质思考,不要只限于对设计概念的掌握,而要追求对设计原则与方法的融汇贯通。只有如此,才能针对不同的业务场景灵活地运用领域驱动设计,而非像一个牵线木偶般遵照着僵硬的过程进行死板地设计。

分享交流

我们为本课程付费读者创建了微信交流群,以方便更有针对性地讨论课程相关问题。入群方式请到第 1-1 课末尾添加小编的微信号,并注明「DDD」。

阅读文章过程中有任何疑问随时可以跟其他小伙伴讨论,或者直接向作者提问(作者看到后抽空回复)。你的分享不仅帮助他人,更会提升自己。

点击了解《领域驱动设计实践(战术篇)》

第1-1课:什么是模型
第1-2课:数据分析模型
第 1-3 课:数据设计模型
第 1-4 课:数据模型与对象模型
第 1-5 课:数据实现模型
第 1-6 课:【案例】培训管理系统
第 1-7 课:服务资源模型
第 1-8 课:服务行为模型
第 1-9 课:服务设计模型
第 1-10 课:领域模型驱动设计
第 1-11 课:理解领域模型
第 1-12 课:领域模型与建模范式之结构范式
第 1-13 课:领域模型与建模范式之对象范式
第 1-14 课:领域模型与建模范式之函数范式
第 1-15 课:领域驱动分层架构与对象模型
第 2-1 课:统一语言与分析模型
第 2-2 课:分析模式对模型的精炼(上)
第 2-3 课:分析模式对模型的精炼(下)
第 2-4 课:彩色 UML 与四色建模
第 2-5 课:【案例】订单核心流程的四色建模
第 2-6 课:事件风暴
第 2-7 课:【案例】事件风暴工作坊
第 3-1 课:表达领域设计模型
第 3-2 课:实体
第 3-3 课:值对象
第 3-4 课:领域服务
第 3-5 课:领域事件
第 3-6 课:事件溯源
第 3-7 课:高质量地设计聚合
第 3-8 课:领域模型对象的生命周期
第 3-9 课:资源库的设计实践
第 3-10 课:应用服务的本质
第 3-11 课:领域服务和应用服务
第 3-12 课:【案例】领域设计模型的价值
第 3-13 课:职责驱动设计的驱动力
第 3-14 课:领域对象的角色
第 3-15 课:设计模型的分治与协作
第 3-16 课:改进设计质量
第 3-17 课:引入 DCI 模式
第 4-1 课:测试驱动开发
第 4-2 课:重构发现隐式概念
第 4-3 课:领域模型与持久化
第 4-4 课:事件与解耦
第 4-5 课:不变量与并发访问
第 4-6 课:一致性问题
第 5-1 课:C4 模型与领域驱动设计
第 5-2 课:子域与限界上下文
第 5-3 课:领域模型的边界
第 5-4 课:命令查询职责分离
第 5-5 课:服务之间的集成模式
第 5-6 课:通过消息实现集成
第 5-7 课:通过 RPC 实现集成
第 5-8 课:REST 服务与 BFF
第 5-9 课:RAID 分析与设计决策
第 6-1 课:EAS 系统的领域分析模型
第 6-2 课:培训上下文的领域分析模型
第 6-3 课:EAS 系统的领域设计模型
第 6-4 课:EAS 系统的技术选型
第 6-5 课:培训上下文的职责驱动设计
第 6-6 课:培训上下文的设计优化
第 6-7 课:EAS 系统的领域实现模型
第 6-8 课:EAS 系统的分层架构与代码模型

阅读全文: http://gitbook.cn/gitchat/column/5cbed2f6f00736695f3a8699

你可能感兴趣的:(领域驱动设计实践(战术篇))