写点什么

我的领域中有一位牛仔! - Implementing Domain Driven Design 书评及采访

2013 年 10 月 01 日

Vaughn Vernon Implementing Domain Driven Design (实现领域驱动设计)一书中指出了软件社区里一个公开的秘密:打算采用 Domain Driven Design (DDD)的人很多,理解如何使用它的人却很少。Vernon 这个问题的处理方式,是带领读者们理解 DDD 的原则,列举出每一项原则的重要性,并指导它们的运用。通过运用的大量教授技巧,例如代码示例、经验法则、一个贯穿全书的案例学习,以及“好牛仔的逻辑”(漫画),IDDD 达到了相当的可读性,它使得即使初学者对 DDD 也能够很好地理解。

(漫画)牛仔逻辑

LB:当你感到极度口渴时,远离人群去饮水(always drink upstream from the herd 英语习语)

在整本书中,Vernon 描述了一个虚构的软件团队学习及实现 DDD 的过程。在每一个章节中,该团队都通过应用不同的概念变得更加熟练,他们对于各种新思想进行了优缺点两方面的详细讨论,使读者感觉到自己仿佛也置身于他们的决策过程中。随着团队的设计不断迭代及改进,他们也证明了必须把重构作为理解他们自己的领域的一种机制。通过这个 DDD 流程中表现出的高度联系实际的各种协作的示例,读者可以和这个案例学习中的团队一起实践,而不用冒任何风险。

DDD 的内容广度是它最终为组织所采用的一个常见的阻力。出于这一原因,开发者常常会选择回避那种“大爆炸”式的推广方式,只有在对 DDD 中的某个方面的需求逐渐在他们的领域中变得清晰时,才会着手实现这一部分。Vernon 认可这种渐进式的 DDD 应用方式,并且通过联系他的经验及详细的示例,他能够帮助读者理解提早采用某个新概念的优点。并阐述了当团队选择推迟应用这种概念时,他们可能会面对的一些问题。这种对 DDD 多方面的阐述方式,使得读者可以作出相应的判断,不需要实际的尝试及失败,他们就能够判断出自身领域的成熟度。

(漫画)牛仔逻辑

LB:你知道吗,J?当一个牛仔已经老到不能作出坏榜样了,他会反过来作出良好的建议。

Implementing Domain Driven Design 一书为软件设计文化中的常见部分作出了重要的注解,尤其关注于领域驱动设计。Vernon 选用了清晰而且有用的示例,并以一种既亲切、又具有权威性的方式进行描述,这就给了读者足够的自信及必需的知识,让他们敢于自行尝试 DDD。为了进一步加强关联性及实用性,IDDD 中列举的实践与 DDD 这一领域中之前的各种工作成果完全吻合,包括了 Eric Evans Domain Driven Design Jimmy Nilsson Applying Domain Driven Design ,并进一步强化了面向对象设计的地位及实践。Implementing Domain Driven Design 一书是对DDD 文化的一种致敬及重要的注解,它同时也帮助开发者提升他们的设计水平及协作技巧……虽然这一点并非本书的首要重心。

此次在欧洲举行的 IDDD Tour 培训班的收尾阶段,InfoQ 有幸采访到了 Vaughn Vernon,以下是这次采访的内容:

InfoQ**:Eric Evans在 Domain Driven Design一书中的成果,现在已经普遍被认为是 DDD定义及实施的黄金标准了。而你的这本有关 DDD的书是在 Evans**的“蓝皮书”之后过了差不多十年才出版的,为什么选择这个时间?

如果你看看周围,我想你会发现其它一些书也在某些方面探讨了 DDD。比如说,Jimmy Nilsson 的书就基本是紧接着 Eric Evans 的书问世的。我认为 Jimmy 在他的书中体现了他的远见,而他的努力也为.NET 社区的进步贡献良多。

我的书不同于其它书籍的一点是,它采取了一种案例学习的途径,并有意识地展现了采用 DDD 时最常见的各种错误,然后再揭示如何修正这些错误,或者是避免错误。这种方式至少有两点好处:首先,它通过预先指出常见的陷阱,清晰地指示读者如何避免它。对于一个软件顾问来说,最困难的一种情况是,在他进入的项目中每个人都工作很努力,但在不断地挣扎与失败,而他需要指出大家的问题所在。团队成员会本能地拒绝帮助,因为他们已经离不开他们熟悉的方式了,并坚持他们的方式会得到更好的结果。

这本书则通过一个虚构的团队指出问题,这有助于读者抛开防卫心态。他们可以任意地把自己代入这个失败中的团队,但一切只是虚构的。第二点,这本书提供了清晰的指导,如何按照尽可能最安全的方式实施 DDD。通过遵循这些指导,或者说这些经验法则,采用 DDD 的团队就能按照最佳建议成功地实施 DDD。这并不是说如果你违反了一两个规则就一定不会成功,但如果你不了解放弃这些规则的代价,你就应该遵循它。

为什么选择这个时间?在我们这个行业工作了十年或者二十年之后,有谁不认为现在是时候正视软件开发,就像开发一架飞行器一样严肃对待了呢?当然,有人会选择无视现实,而我们只能期望最好不要和他们在一个项目里共事。而当期望落空时,我们需要知道如何通过应用某些 DDD 实践使自己从这种混乱中脱身。所以我想说,现在正是时候。

InfoQ**:在企业中实施 DDD可能需要一定时间,从 DDD的尝试当中,是否可以渐进式地获得某些收益?**

我认为,打算以渐进式步骤改善设计的团队可以采取两种方式齐头并进。首先采用一些策略式设计(Strategic design),决定出那些能为企业带来大价值的部分。如果你是在为一个成熟的企业(而非一个创业型公司)工作,那很可能这部分价值会与某个陈旧的遗留系统相关。使用上下文映射(Context Mapping)和子领域(subdomain)分析会帮助你理解问题的范围,指出通往解决方案的正确方向。一旦你的团队领会了这种策略方式,团队成员就能决定新业务应该在怎样的上下文边界(Bounded Context)中进行建模了。

不过有一个问题经常被提起,那就是与陈旧的遗留系统进行整合的最佳方式是什么?这里有两种主要的解决方法:如果可能的话,你可以让遗留系统发布某些关键的领域事件(Domain Event),以提示系统中的发生的事。让新的边界上下文侦听这些重要的领域事件,并对其作出响应,以实现某些系统功能。我想你总能够找到方法,从遗留系统中发布某些关键的领域事件。

不过,想把遗留系统转入一个完整的事件驱动架构(事件驱动架构)可能会有些不实际。这种情况下,找到另一种在遗留系统和新系统之间交换信息的方式就会显示出必要性了。我建议你去尝试一下这两种策略方式:开放主机服务(Open Host Service)和防护层(Anti-Corruption Layer)。虽然还存在其它的可能性,但这两者被认为是 DDD 整合的有效途径。

不过,要注意到我们并没有为改善遗留系统投入大量精力,我们只是渐增式地为遗留系统加入了一些钩子(hook),不用多,足够满足新系统的需要就可以了。我们也许会重写一小部分代码,但经验告诉我们,重写过程必需小心谨慎。如果不尽量减少重写,那么对遗留系统的一处小改动经常会造成严重的连锁反应,并大面积地破坏现有的测试。而要想处理所有的连锁反应不仅困难并花费精力,还会降低系统稳定性。

最后,使用 DDD 战术设计(tactical design)可以对边界上下文进行深度或浅度建模。使用聚合(Aggregate)很有价值,但要得到设计良好的聚合将面临许多挑战。为了确保成功,需要对“经验原则”投入大量的关注。

InfoQ**:有些人被 DDD吓跑,因为它有着自己的语言,非常复杂,指导手册也接近 600页。DDD**是真的这么难实现吗?

是也不是。我想这主要取决于你的背景。对那些非常熟悉优秀面向对象设计的人来说,许多概念自然而然就会从头脑里跳出来。另一方面,有些人更熟悉数据库驱动的设计,在贫血模型中有着无数的 getter 和 setter,他们就需要更多的训练了。因为他们不仅要学习新知识,还需要抛弃大量现有的观念。在这种情况下,最重要的就是看开发者作出改变的意愿了。

我的这本书会帮助以上两种人更容易在应用 DDD 上获得成功。我必须厚着脸皮推荐一下我的培训课程,即 IDDD 培训班。我已经在整个欧洲进行了一系列的培训课程,现在已接近结束了。2013 年 7 月 22 日至 25 日,我将在美国科罗拉多州的丹佛开讲,你可以在这里注册

InfoQ:对于打算推行 DDD的人来说,他在企业里会面对怎样的阻力呢?他又该如何克服这些阻力?

如果你打算用 DDD 改变你的整个公司或者其中很大一部分,你注定要失败。无论你是否获得业务上的支持都会失败的。何况,如果你有打算改变公司中的很大部分的某种想法,你本来也很难得获得业务上的支持。我的观点里,采用 DDD 最大的错误是一个包含开发者和架构师的团队想做的太多,哪怕本身想法很好,但是对管理执行者来说,听到某个团队打算对现有系统作出重大影响的改变,甚至是完全重写多个系统,他一定会被吓到的。其实这不仅仅是对管理者很恐怖,对于任何一个了解如何正确使用 DDD 的人,或者仅是了解顺利完成这种高投入的项目的复杂性的人而言,这都很恐怖。而当 DDD 提倡者不断重复他们的倡议时,矛盾就更激化了。

我认为要避免业务上的阻力,最好是找到某种开销较小的方法,在一个新的边界上下文中交付实际的,重要的商业价值。第一个项目最好能够将范围控制得相对小一些,只要保证你在预算和时间计划内能正常交付就可以了。也不要把它当作一项“重大机密科研项目”来处理,因为你至少要从一位领域专家中那里分享思想。虽然你也可以把它当作地下工作来搞,但这种方式必定难以长久。因此最好计划能产生一定的影响力,同时也保持合理的期望。这就意味着你需要对你自己和其它开发者的期望加以控制。这种以商业思考方式进行思考的训练很有益,它对按照正确的方法实施 DDD 是非常重要的。

不要提太多倡议,保持飞行在雷达之下,不断交付,获得他人的尊敬与信任。在你交付了一两个能产生可见的商业价值的项目之后,你再基于你的成功经验,以及你对应该怎样使用及不应该怎样使用 DDD 的清晰见解,提出对 DDD 的倡议,就处于比较有利的位置了。

InfoQ:归根到底,是否所有的垂直行业都适合应用 DDD呢?当系统中的其余部分的复杂性在不断提升的情况下,是否能有一部分始终保持一定程度的复杂性不变呢?

使用 DDD 的最佳时机,是用以处理你的业务中最复杂的部分,以及能够带来最大商业价值的地方。这就意味着在整体业务中的某些技术部分是不值得投入 DDD 的。但我并不是说在这些要求较低的地方,就不必应用正确的软件开发原则,甚至某些原则还是基于 DDD 的。我想表示的是:即使某个系统在战略上的价值不高,也不意味着应该糟糕地实现它。即便是通用软件和支持软件,对整个端到端的解决方案的运维也有着重要意义。不过,你就不需要和领域专家做那么深度的探讨了,无需达到那些核心领域一样的程度。

团队有时会吃惊地发现,某个他们一直不重视的系统或子系统,会在某一时刻成为一个核心领域,或者至少是在一个新的核心中起到整合作用。这是不是意味着你应该提早预计到这种事情的发生,并提早建模,就像这个系统会最终采用 DDD 一样?我觉得这种方法并不明智。但我还是要说,你应该让你的团队尽可以开发出最好的软件,即使团队和领域专家没有常规的探讨。越是良好设计的系统,越容易演化维护,并在它需要担任一个比以往更重要的角色时及时扩展。

我觉得这里的重点是,了解何时及如何正确地采用 DDD,同时不要把暂时不考虑使用 DDD 的那部分当作可以产出质量糟糕的软件的不毛之地,这是种不负责任的做法。

另一个建议是有序。即使一个没有用 DDD 建模的系统,也可以发布某些重要的领域事件,或提供一个开放主机服务作为它的服务级契约的一部分。请记住,即使是一个令人厌烦的遗留系统,也能够在改造后在最低程度上发布领域事件,这就不需要做出什么翻天覆地的大改动了。实现这点不需要对 DDD 进行很大的投入,只需和一两个团队共同整理出在系统中进行信息交换所需的领域事件或 API 就可以了。如果你的服务契约成为整个公司的重要部分,那就到了可以创建一个组织级公共语言(Published Language)的时候了,这是 DDD 策略设计中的另一个重要组件。

你可以看一看我书中的某个示例模型:认证及访问上下文是如何采用这一途径的。认证及访问上下文被看作一个通用的子领域,因此它并未完全采用 DDD 设计,但它依旧是设计良好的。它发布重要的领域事件,并提供了一个开放主机服务,以允许其它系统,如核心 DDD 领域与它进行集成。

InfoQ**:如果一个 DDD尝试者打算使用 DDD以帮助改善他们的产品,你建议他们先从什么概念开始呢?**

首先使用上下文映射及子领域来诊断出问题的范围,并且将核心领域设计为一个新的边界上下文,这种方式非常有价值。你会发现领域事件及聚合会在战术设计中扮演关键性的角色。如果可能,尽量偏向于使用值对象(Value Object)而不是实体(Entity)。只要你能选择实现不可变性(immutability)及无副作用(side-effect-free)的功能,你就有可能避免很多问题。

你可以阅读这本书的示例,以观察如何使用各种策略及战术建模技术,示例包含了 Java 及 C#代码:

InfoQ:有许多相关的概念在当前的主流软件开发技术中获得了良好的发展势头:如 DDD,事件溯源(Event Sourcing**),NoSQL及函数式编程等等。DDD看起来与这些概念合作良好,你认为这种势头会带领我们走向何方呢?**

DDD 方法的原则可以在很长一段时间内得到应用,并与各种技术、模式、方式及习惯良好合作。我对这个问题的简单回答是:DDD 会在可见的未来依然得到使用,在我看来事件溯源以及 NoSQL 就是明证。在函数式编程中使用 DDD 的经验也在增加,而且很可能会继续加强,使得函数式编程真正得到广泛应用。

有一个你没提到的架构模式是角色模型(Actor Model),我个人现在就在为推广在 DDD 中使用角色模型这一方式提供一些经验并打造一些工具。在函数式编程环境中,这种方式可能被称为代理人模型(Agent Model)而非角色模型,不过两者都强调了消息传递和非阻塞式并发,因此可以达到高度分布式。通过这种重要的方式,我们就可以靠增加 CPU 核的数量获得更多的计算能力,虽然这种核的处理速度是弱于单机处理器的。角色模型的基本概念极大的简化了我们理解并应用并发和分布式的难度。

如果你打算尝试一下角色模型,你可以在这里找到我的实验项目

你也可以尝试一个完整的角色模型系统,是面向 Scala 或 Java 的 Akka 项目。如果你在.NET 平台上进行开发,你也可以尝试微软的 ActorFX

关于作者

Vaughn Vernon 是一位经验丰富的软件从业者,他在软件设计、开发及架构上已有超过 25 年的经验了。他是简化软件设计,及使用创新式方法开发软件方面的意见领袖。他从上世纪 80 年代起就开始应用面向对象语言进行开发了,并在上世纪 90 年代早期的一个 Smalltalk 领域模型中就开始遵循领域驱动设计的宗旨了。他的丰富经验横跨各种商业领域,包括航空、环境治理、地理空间、保险、医药保健,以及电信。他也在技术领域有着诸多贡献,包括创建可重用的框架、类库及提高开发效率的工具。他在全球进行顾问工作,进行各种演讲,并在多个大陆讲授他的 Implementing Domain-Driven Design 课程。你可以在他的博客中了解他的最新信息,也可以在Twitter 上关注他: @VaughnVernon

查看英文原文: There is a Cowboy in my Domain! - Implementing Domain Driven Design Review and Interview

2013 年 10 月 01 日 01:443600
用户头像

发布了 428 篇内容, 共 148.4 次阅读, 收获喜欢 20 次。

关注

评论

发布
暂无评论
发现更多内容

渣本全力以赴33天,四面阿里妈妈(淘宝联盟),拿下实习岗offer

小Q

Java 学习 编程 架构 面试

史上最通俗Netty入门长文:基本介绍、环境搭建、动手实战

JackJiang

网络编程 Netty nio 即时通讯 IM

微服务架构中的“参天大树”:SpringBoot+SpringCloud+Docker

小Q

Java 学习 容器 面试 微服务

解读登录双因子认证(MFA)特性背后的TOTP原理

华为云开发者社区

算法 totp 密钥

2020年底备战—从技术到面试合集

iOSer

ios 编程 面试题 大厂面试 面试题总结

接口测试并不只是测试参数和返回值

测试人生路

接口测试

区块链数字货币商城系统开发模式

薇電13242772558

区块链 数字货币

6个JDK自带JVM调优工具,一次性打包给你说清楚

田维常

jvm调优

容器和虚拟机到底有啥区别?

网管

容器 虚拟机 容器化

基于Vue实现一个有点意思的拼拼乐小游戏

徐小夕

Java GitHub H5游戏 H5 游戏开源

【应用运维】公司业务迭代迅速,运维如何高效进行应用发布?

嘉为蓝鲸

可视化 PaaS 运维自动化 部署与维护 发布

2020双十一,阿里云GRTN拉开直播和RTC技术下半场的序幕

阿里云视频云

架构 云直播 直播 流媒体 直播架构

直播卖货已成趋势

anyRTC开发者

音视频 WebRTC RTC

为什么容器内存占用居高不下,频频 OOM

996小迁

Java 架构 容器 面试 k8s

go-zero 如何扛住流量冲击(一)

Kevin Wan

go microservice go-zero goctl

Java中的线程与C++中的区别

jiangling500

Java c++ 线程

什么是服务器租用?

德胜网络-阳

影视剪辑类自媒体运营心得:如何抓住观众的痛点

石头IT视角

甲方日常 52

句子

工作 随笔杂谈 日常

响应式关系数据库处理R2DBC

程序那些事

MySQL R2DBC 程序那些事 响应式系统 响应式数据库

这份算法攻略,我拿到了5个大厂的offer

yes的练级攻略

面试 算法 笔试

支撑2715​亿元海量订单 揭秘京东大促背后的数据库基石

京东智联云开发者

数据库 数据仓库 云服务 云数据库

数字货币交易所开发源码,币币撮合交易系统搭建

WX13823153201

《程序员面试金典》.pdf

田维常

面试

SpringBoot-技术专题-Hystrix学习介绍

李浩宇/Alex

厉害了!阿里内部都用的Spring+MyBatis源码手册,实战理论两不误

小Q

Java spring 学习 面试 mybatis

【JVM】肝了一周,吐血整理出这份超硬核的JVM笔记(升级版)!!

冰河

性能优化 内存模型 JVM 堆栈 JVM笔记

.net core增强工作流组件,基于稳定平台,多项目整合开发

雯雯写代码

这才是图文并茂:我写了1万多字,就是为了让你了解AQS是怎么运行的

鄙人薛某

Java 并发编程 AQS 并发 ReentrantLock

SQL数据库集合运算

大规模数据处理学习者

SQL表联结 SQL集合运算

Java中NullPointerException的完美解决方案

Silently9527

java8 Optional

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

我的领域中有一位牛仔! - Implementing Domain Driven Design书评及采访-InfoQ