DDD、DSL 和 DCI

DDD 概念最早提出于 2004 年,作为一种软件开发的指导思想,DDD 对软件开发带来了诸多可能与方向,张晓龙认为 DDD 为软件开发带来的好处主要有以下几点:

  1. 首先,最大好处就是所有参与者围绕一个统一一致的领域模型工作,传统的分析模型和设计模型不再割裂,不管是做设计、做分析还是写代码、写文档,脑海中所构建的画面都是一致的。

  2. 第二,DDD 是一个软件开发过程,它显式地把领域和设计放到了软件开发的核心,软件人员和业务人员被受到同样的重视,他们合作来构建领域模型,使得软件的交付质量更高且维护成本更低;

  3. 第三,DDD 提出的分层架构,有效分离了业务复杂度和技术复杂度,凸显了领域模型,使得领域层的代码和领域模型保持高度一致;

  4. 第四,统一语言非常重要,每个概念在各自的上下文中是清晰的无歧义的,同时要控制领域模型的复杂度,于是 DDD 在战略上提出了分离子域(问题域空间)和拆分 BC(解决方案空间)的模式,BC 间通过 Context Mapping 来集成;

  5. 第五,DDD 在战术层面提出了很多模式(聚合,实体,值对象,服务,工厂,仓储),对领域模型中的元素进行了分类,并给出了每类元素在领域模型中的职责和特征,降低了领域模型的构建成本。

张晓龙此前曾在 DDD-China 峰会和 ArchSummit 全球架构师峰会上分别做过《当 DDD 遇上 DSL(Domain-Specific Language)》、《当 DDD 遇上 DCI(Data,Context, Interactive)》的演讲,在他看来,DDD 和 DSL、DCI 之间存在极强的关联性。

DDD 和 DSL 的融合有三点:

  1. 面向领域;

  2. 模型的组装方式;

  3. 分层架构演进。

DSL 可以看作是在领域模型之上的一层外壳,可以显著增强领域模型的能力。它的价值主要有两个,一是提升了开发人员的生产力,二是增进了开发人员与领域专家的沟通。举个例子:想让 BA 负责流程契约的设计,该流程契约是一个活文档,可以跑测试,而 BA 不熟悉宿主语言。于是,我们设计了一种外部 DSL 来专门描述流程契约,对 BA 非常友好,学习成本也很低(不超过 5 分钟就可以学会),最后发现 BA 很快就广泛使用了起来。外部 DSL 并不一定要定义新文法,我们直接复用了 plantUML 文法,安装该插件可以自动生成序列图,非常棒!对于外部 DSL,需要自己实现一个解析器将 DSL 文法解析成语法树,再根据语法树生成语义模型。语义模型可以看作领域模型(严格的讲语义模型是领域模型的子集),外部 DSL 就是对领域模型的一种组装方式。

DCI 的作用主要体现在两方面:

首先,DCI 助力 DDD 战术设计:

  1. 显式的对 ROLE 建模,解决了贫血模型与充血模型之争;

  2. 一个聚合可以支持哪些 ROLE,一个 ROLE 可以由哪些聚合扮演,一个场景下哪些聚合要扮演哪些角色;

  3. 当 Aggregate 内部实体行为比较多时可以嵌套使用 DCI 来拆分和组合;

其次,DCI 助力 DDD 代码落地:

  1. 对象就是 Data,Client 为 Context,对象在 Client 中的行为就是 ROLE。

  2. 根据正交设计原则得到小类(素材库),根据多重继承(only C++)或依赖注入来组合素材,不管是行为类还是数据类,都按 Role 的方式来组合,对像仅仅组合 Role 并注入依赖;

  3. 小类大对象:类作为一种模块化手段,遵循高内聚,低耦合,让软件易于应对变化;对象作为一种领域对象的的直接映射,解决了过多的类带来的可理解性问题,让领域可以指导设计,设计真正反映领域;领域对象需要真正意义上的生命周期管理。

张晓龙认为,DCI 对一些开发人员的影响可能比 DDD 和 DSL 还大,因为开发人员每天都在不断倒腾代码,想让代码的组合性更强,以便快速应对需求的变化。

开发团队真的需要 DDD

DDD 思想贯穿了整个软件开发的生命周期,包括对需求的分析、建模、架构、设计,和最终的代码实现,甚至对代码的测试与重构。代码是业务的核心资产,不管是否特性团队,开发团队肯定是代码的编写者和守护者。

对于开发团队而言,需要关注以下几点:

  • 首先是统一语言,让团队成员可以做到无障碍的沟通,不管是什么角色都能基于同样的画面进行讨论;

  • 其次是团队中各个角色都围绕领域模型开展工作;

  • 第三是代码物理设计容易标准化,比如说在分层设计时,基础设施层怎么设计,应用层怎么设计,DTO 应该放在哪儿,领域层中各个建模元素如何组织?

更进一步,在分层架构里,应用层更加关注横切面的东西,比如说要上报一个告警,要给用户发送一个 Email,这些最好都集中放到应用层里面。但触发是在领域层发生的,应用层怎么知道?通过领域事件来实现依赖反转,即应用层订阅领域事件,领域层发布领域事件。

在中兴通讯,核心业务属于通信行业,DDD 的应用场景跟互联网企业有着很大差别:

  1. 嵌入式软件;

  2. 兼业务复杂性和技术复杂性;

  3. 软件规模大,功能复杂,特性交叉;

  4. 高质量,高性能,高可靠等要求。

张晓龙举例提到,中兴通讯在开发团队中实践 DDD 的经验具体而言有以下几点:领域专家下团队,和团队一起交流和协作;教练指导,开展战训营,定期 review;架构、设计、编码和工程实践:

(1)DCI,DSL,正交设计,组合式设计;

(2)编码规范和纪律;

(3)嵌入式 C/C++ 最佳实践;软件工程能力:开发者测试,小步安全流畅的重构,持续交付流水线,每日 Code Review。

DDD 与微服务

DDD 概念提出距今已经有 15 年的历史,前十年时间都一直处于不温不火的状态,而在最近几年才开始大行其道。张晓龙表示,中兴通讯在 2012-2015 年期间也有过一些成功的案例,但对于整个业界来说了解的人并不多。他拿 DDD-China 峰会举例解释:这次峰会的参会者有 500 人的规模,而我们假设峰会在 2015 年之前举办的话,估计参会者不会超过 100 人。因此,我们可以断定是微服务的热风让人们才重新发现了领域驱动设计的价值。

微服务架构从提出以来一直没有很好的理论支撑如何合理地划分服务边界,人们常常为服务要划分多大而争吵不休。而 DDD 被发现恰好可以弥补微服务的营养不良:(1)服务最大不要大过一个 BC,否则服务内可能会存在有歧义的领域概念;(2)服务最小不要小过一个聚合,否则会引入分布式事务的复杂度;(3)服务间最好通过 Domain Event 来进行交互,这样可以让服务保持松耦合。微服务和 DDD 的结合,让微服务架构看起来似乎更加稳健了。

“微服务就像是 DDD 的心上人,使得 DDD 真正焕发起了青春。”张晓龙这样解释。

对于业界目前流行的中台概念,张晓龙同样也有自己的看法:

中台和 DDD 不是同一个层面的东西,不能为了把它们联系在一起,而强行找相似点。中台实际上就是多条业务线的共同需求,比如对于滴滴公司来说,快车、专车和出租车等业务都是微服务架构,这些业务的很多服务是相似的,考虑将这些服务从各个前台下沉到统一的平台,这个平台就是中台。中台要考虑各个前台的需求,所以复杂性变高了。

中台是一种企业级的架构模式,从企业全局整体视角来看架构全貌,而 DDD 是一种主流的软件开发方法,用来应对软件的核心复杂性。中台架构可以看作是微服务架构的延伸和发展,服务复杂性很高,所以更需要用 DDD 的方式去设计和建模,但二者之间并不是相同层面的概念。

DDD 的困局

最近几年 DDD 的火爆也给业界开发团队带来了一些迷思,为什么我的 DDD 推行不下去?为什么我的 DDD 做起来总是跟敏捷一样,最后都变了味?

张晓龙总结了 DDD 目前面临的几大困局:

  • 首先是领域案例面比较窄。目前业界的 DDD 实践案例并不多,而且很多案例是偏向互联网领域的,对于工业领域、嵌入式领域和操作系统领域基本没有涉及;

  • 第二,DDD 书籍非常少,而且大多数书籍是以 Java 或 C# 写的。如果开发团队用的是 C、C++、Python 或 Go 语言,基本没有可参考的书籍,难度也就更大一些(尤其是 C 和 C++);

  • 第三,各个巨头公司,比如 Google,微软,BAT 等,很少组织、参与或赞助 DDD 峰会,没有形成引导作用,业界自然也就少有跟随效应;

  • 第四,开发团队要么找不到领域专家,要么领域专家无法与开发团队长时间保持沟通,导致实践中出现偏差;

  • 第五,DDD 落地有一定的门槛,对开发者的技能和素质都有较高的要求。

针对以上几大困局,张晓龙也给出了自己的解决方案:

  1. 培训 OOA、OOD 和 OOP 的基本知识,并实战演练,不断弥补与高手的 gap ;

  2. 领域专家和团队一起工作,确保大家头脑中的画面是一致的;

  3. DDD 建模要有文档交付物,并和代码同步演进,以便对代码不熟悉的人员也能看到并理解领域驱动设计成果的全貌。

软件开发没有银弹,DDD 也不是万能的。如果开发团队真的决定用 DDD 的思想指导软件开发,就一定要跟随时代的脚步,吃透 DDD 这个旧瓶里装的新酒。

DDD:架构思想的旧瓶新酒的更多相关文章

  1. ddd 架构设计——abp

    一.为什么要分层 分层架构是所有架构的鼻祖,分层的作用就是隔离,不过,我们有时候有个误解,就是把层和程序集对应起来,就比如简单三层架构中,在你的解决方案中,一般会有三个程序集项目:XXUI.dll.X ...

  2. 分布式抽奖秒杀系统,DDD架构设计和实现分享

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.用大项目,贯穿知识体系 写CRUD.堆API.改屎山⛰,熬多少个996也只是成为重复的螺丝 ...

  3. 怎么说服领导,能让我用DDD架构肝项目?

    作者:小傅哥 博客:https://bugstack.cn 原文:https://mp.weixin.qq.com/s/ezd-6xkRiNfPH1lGwhLd8Q 沉淀.分享.成长,让自己和他人都能 ...

  4. ReactiveCocoa常见操作方法介绍/MVVM架构思想

      1.ReactiveCocoa常见操作方法介绍. 1.1 ReactiveCocoa操作须知 所有的信号(RACSignal)都可以进行操作处理,因为所有操作方法都定义在RACStream.h中, ...

  5. 剥析surging的架构思想

    1.前言   前面第一篇阐述了采用基于.NET CORE微服务架构,应用surging服务端与客户端之间进行通信的简单示例以及对于surging服务化框架简单介绍.在这篇文章中,我们将剥析surgin ...

  6. iOS swift的xcworkspace多项目管理(架构思想)

    iOS  swift的xcworkspace多项目管理(架构思想) 技术说明: 今天在这里分享 swift下的 xcworkspace多项目管理(架构思想),能为我们在开发中带来哪些便捷?能为我们对整 ...

  7. 前端笔记之NodeJS(四)MongoDB数据库&Mongoose&自制接口&MVC架构思想|实战

    一.MongoDB数据库 1.1 NoSQL简介 随着互联网web2.0网站的兴起,传统的SQL数据库(关系数据库)在应付web2.0网站,特别是超大规模和高并发的SNS(social network ...

  8. 『练手』005 Laura.SqlForever历史遗留 的 架构思想缺陷

    005 Laura.SqlForever历史遗留 的 架构思想缺陷 我们 比较一下 Laura.WinFramework 和 Laura.XtraFramework 的差异: Laura.WinFra ...

  9. Restful架构思想

    java作为一门后端语言,其厉害之处在于web,大家比较熟知的各种网络应用,java都能做,那么在这个移动优先的时代,如何继续发挥java的强大呢.通常是让java作为一个app的服务端,为app客户 ...

随机推荐

  1. addEventListener兼容性问题

    参考链接:https://blog.csdn.net/lililiaaa/article/details/83960924

  2. VS混淆/反编译/远程调试/Spy++的Tools工具

    VS的Tools工具(混淆/反编译/远程调试/Spy++等) https://blog.csdn.net/chunyexiyu/article/details/14445605 参考:http://b ...

  3. box-shadow 用法总结

    一.基础知识 box-shadow 属性向框添加一个或多个阴影. 语法 box-shadow: offset-x offset-y blur spread color inset; box-shado ...

  4. hdu 5418 题解

    第一眼看到这题,哇,这不是我刚做完的题吗?大水题!然后 这题表面很水,实际上有点坑. 题意 求经过 $ 1 - n $(不能遗漏) 并且回到 $ 1 $ 的最短路. 在看这题之前我们可以来看下这题 最 ...

  5. 在做爬虫或者自动化测试时新打开一个新标签页,必须使用windows切换

    在做爬虫或者自动化测试时,有时会打开一个新的标签页或者新的窗口,直接使用xpath定位元素会发现找不到元素,在firefox中定位了元素还是找不到, 经过多次发现,在眼睛视野内看到这个窗口是在最前面, ...

  6. Windows环境下Python3安装Pyspider

      执行命令: pip3 install pyspider Windows 下可能会出现这样的错误提示:Command "python setup.py egg_info" fai ...

  7. Python重要配置大全

    PYTHON 环境安装 安装虚拟环境 pip install virtualenv 卸载包是用:pip uninstall virtualenv 快捷下载安装可用豆瓣源,方法为: pip instal ...

  8. Mybatis整合(Redis、Ehcache)实现二级缓存

    目的: Mybatis整合Ehcache实现二级缓存 Mybatis整合Redis实现二级缓存 Mybatis整合ehcache实现二级缓存 ssm中整合ehcache 在POM中导入相关依赖 < ...

  9. JPA 一对一 一对多 多对一 多对多配置

    1 JPA概述 1.1 JPA是什么 JPA (Java Persistence API) Java持久化API.是一套Sun公司 Java官方制定的ORM 方案,是规范,是标准 ,sun公司自己并没 ...

  10. AtomicIntegerFieldUpdater和AtomicInteger

    为什么有了AtomicInteger还需要AtomicIntegerFieldUpdater? 当需要进行原子限定的属性所属的类会被创建大量的实例对象, 如果用AtomicInteger, 每个实例里 ...