2

领域驱动设计(DDD)靠谱么?

 2 years ago
source link: https://xie.infoq.cn/article/00390d9067add4aa58dcb9daa
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

hello,大家好,我是张张,「架构精进之路」公号作者。

好像最近几年 DDD 特别的火,关于 DDD 到底是银弹还是垃圾 的分析网络上还是挺多的。

最近组内一名同学迷恋上了领域驱动设计(DDD),原因是在极客上花钱学习了 DDD 的课程,然后一心想要在工作项目中加以实践,让理论落地~ 😂

一、DDD 分层架构

相信大部分了解 DDD 的开发者,持支持的观点主要认为:

DDD(Domain Driven Design,领域驱动设计)作为一种软件开发方法,它可以帮助我们设计高质量的软件模型。在正确实现的情况下,我们通过 DDD 完成的设计恰恰就是软件的工作方式。

业务系统设计的关键是在于如何定义系统的模型以及模型之间的关系,其中主要是领域模型的定义,当我们在模型确定之后,模型之间的关系也会随之明确。

Eric Evans 在《领域驱动设计-软件核心复杂性应对之道》这本书中提出了传统的四层架构模式。

简单概要理解如下:

  • 接口层 Interface:主要负责与外部系统进行交互 &通信,比如一些 dubbo 服务、Restful API、RMI 等,这一层主要包括 Facade、DTO 还有一些 Assembler;

  • 应用层 Application:这一层包含的主要组件就是 Service 服务,但是要特别注意,这一层的 Service 不是简单的 DAO 层的包装,在领域驱动设计的架构里面,Service 层只是一层很“薄”的一层,它内部并不实现任何逻辑,只是负责协调和转发、委派业务动作给更下层的领域层;

  • 领域层 Domain:Domain 层是领域模型系统的核心,负责维护面向对象的领域模型,几乎全部的业务逻辑都会在这一层实现。内部主要包含 Entity(实体)、ValueObject(值对象)、Domain Event(领域事件)和 Repository(仓储)等多种重要的领域组件;

  • 基础设施层 Infrastructure:它主要为 Interfaces、Application 和 Domain 三层提供支撑。所有与具体平台、框架相关的实现会在 Infrastructure 中提供,避免三层特别是 Domain 层掺杂进这些实现,从而“污染”领域模型。Infrastructure 中最常见的一类设施是对象持久化的具体实现。

二、贫血模型 vs 充血模型

Q1:所谓的 “贫血模型” 到底是什么呢?

在传统的 MVC 分层架构下,我们将项目结构分为 Controller,Service,DAO 这三个主要的层,所有的业务逻辑都在 Service 中体现,而我们的实体类 Entity 却只是充当一个与数据库做 ORM 映射的数据容器而已,它并没有反映出模型的业务价值。

Q2:“贫血模型”有什么坏处呢?

在我们的代码 中将会到处看到各种的 setter 方法和各种各样的参数校验的代码,尤其是在 Service 层,但是这些代码它并没有反映出它的业务价值。DDD 推荐你用充血模式写代码,也就是按 OOP 的方式去做抽象,然后把行为挂在对象上,而不是以纯过程式 的方法去写代码。

Q3:所谓的充血是什么呢?

就是对象本身有很多关联的行为,而不只是一个单纯的数据库的表的字段映射。

DDD 声称的充血模式的优势是,大部分的行为被封装到了对象内部,这样我们在阅读流程代码的时候,是一目了然的,直接能看到 step 1,step 2,step 3。但实际即使我们不用 OOP 来组织行为,一样可以把不同的业务 step 做好封装和复用。

有些公司的服务粒度拆的特别细,比如只有 5000-10000 行代码,在 DDD 里声称的充血模式的优势没有那么明显。

三、便于指导微服务的划分?

相信很多朋友都了解“ DDD 可以有效的指导微服务拆分”,关于这点,主要是利用 界限上下文(Bounded Context)。

限界上下文是 DDD 中用来划分不同业务边界的元素,这里业务边界的含义是「解决不同业务问题」的问题域和对应的解决方案域。你可以认为限界上下文的存在是为了解决某种类型的业务问题。

那如何划分呢?

主要是将数据与功能的抽象。例如:外卖、物业、ERP 这些产品的共有数据模型,用户资源可以拆分成一个服务,很简单是不是?但这是万里长征第一步,难就难在具体编码实践中的 DDD 运用。

很多人对此的结论就是:DDD 对服务划分有帮助,但是对人员能力要求很高。

任何软件的架构演进都是螺旋式的。

  • 当没有足够的经验直接解决问题,或问题庞大到不足以使用经验解决时,能支撑你做出决策就只有对输入问题进行有效的分析。

  • 使用 DDD 指导微服务划分,能在一定程度上弥补经验的不足,做出有理有据的系统架构设计。

四、做个总结吧

领域驱动开发的关注点在于领域模型,所有的考虑都应该从领域的角度出发,重心放在业务。领域模型必须能够精准地表达业务逻辑,领域模型需要在开发过程中不断被完善,并且能够指导工程师的开发工作。

但是,现实往往并不如我们所预期的一样:

  • 国内关于 DDD 的最佳实践还是太少了

除了知名的几个大厂以外很少看到有关于 DDD 的落地实践,最佳实践太少意味着,我们可以参考的资料就少,承担的项目失败的风险就大。

  • DDD 中出现了很多新概念和术语

比如 聚合根,值对象,六边形架构,CQRS(命令和查询职责分离),事件驱动等等概念。很多人看到了这么多概念的时候,心中就开始打退堂鼓了。

如果你是在大公司一线工作了两三年的程序员,这些新概念、名词的本质内容,其实应该都很好理解。没有啥值得说的。如果是为了出去分享 Show 一下,你倒是可以借鉴包装一下,别让自己显得那么土,哈哈哈~

  • 关于 ROI 需要进一步商榷

DDD 需要我们在领域建模花费很多的时间和精力,而且还可能导致付出和收益不成正比的情况。因为在界限上下文的划分上是非常考验架构师的业务水平。如果没有将业务模型很好的识别出来,那么可能很快模型就会在迭代的过程中腐败掉了。

今天主要跟大家聊了下 DDD 的主要概念和服务划分上手很简单的推崇卖点。其实要把 DDD 用在具体的代码中,还需要开发人员的能力很高,不仅要会八股文上的东西,还要对编码技巧有很高的要求。

最后说一句:尽信书不如无书,实践是检验真理的唯一标准!  


💪🏻 坚持原创分享有价值的干货技术文章!

Thanks for reading!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK