浅谈领域驱动设计实践——董炎焱

简介: 近年来领域驱动设计(Domain Drive Design)大火。那么我们为什么要学习领域驱动设计,它适合用于哪些场景?怎么去用?在用的过程中,又有哪些需要注意的地方呢?

关于可组装开发理念

Gartner在其发布的《企业机构在2022年需要探索的重要战略技术趋势》中提出了Composable Applications组装式应用的概念,指出组装式应用由以业务为中心的模块化组件构成,具备更易使用和可重复使用的代码,可加速新软件解决方案的上市时间,并释放企业价值。

那么具体如何实现组装式应用呢?其核心是封装业务能力Packaged Business Capability,简称PBC)。在不断变化的业务环境中,业务适应性需求将引导企业转向使用支持快速、安全和高效应用变化的技术架构。在这种背景下,需要将一个个的业务对象或功能模块化,以实现快速“组装”或替换。组装式应用增强了这种适应性。有利于更安全更高效更快的变更和迭代,提升敏捷性减少重复劳动

在这点上,领域驱动设计(DDD与之不谋而合。

领域驱动设计的“新”

传统的系统架构多采用MVC三层模型设计,即Controller->Service->Dao分层结构,所有的业务逻辑都集中在Service层。随着业务持续发展,这种面向事务脚本进行编码的方式,会使代码臃肿,可复用性差架构腐化很快。

image.png

领域驱动设计是对面向事务脚本编程的进一步升华:

  • 它强调“领域”的概念,将服务提供(Service层划分为domain层和App
  • 把现实对象映射到代码中的领域对象,提升代码可读性
  • 通过稳定的领域模型来提供代码复,提升研发效率和代码质量
  • Infrastructure层包括所有对基础设施和其他服务的依赖。在Mapper之上封装Gateway,用于领域层调用;调用MQ库发送消息等逻辑都也在Infrastructure
  •  Domain层对基础设施的依赖通过DIP(依赖倒转)解耦,Domain层可以独⽴存在

目前使用较多的是由阿里DDD专家 张建飞设计的COLA架构,详见https://github.com/alibaba/COLA,这里不做赘述

领域驱动设计是YYDS吗?

领域驱动模型设计能够构造高扩展性高可维护性快速迭代的架构。在实体比较复杂、各实体关联比较多,操作中可能涉及其他实体方法比较紧密的时候,用领域驱动设计是比较好的选择。它能使功能操作逻辑易于理解,模块分界清晰,易于后期扩展改造,较好地支撑产品演进。

如果是一个较小型的项目后期演进一般,操作多是简单的crud,实体属性比较少且并不涉及复杂业务逻辑。这时使用领域驱动设计我倒觉得有点大材小用,反而传统的MVC架构就足以应对,且开发起来更加简洁。因为领域驱动设计开发会涉及比较多的DO<->领域模型<->VO/CO/DTO对象的转换,在简单的业务逻辑背景下,这些转换看起来占比比较重,使得代码不是那么简洁,俗话说:杀鸡焉用牛刀?

当然,在现阶段和未来,绝大多数的应用都不只是“简单”的,领域模型驱动设计会得到更好的发展和普及。也不排除将来会出现更好的开发设计模式,因为哪里有需求,哪里就有解决问题的办法。

我们怎么更好地去用它?

比如某个应用以公司的“资产”为核心对象之一,衍生出很多相关的功能和操作。“资产”这个对象本身包含二三十种属性,围绕“资产”的业务逻辑包含:资产查验,标准化管理,属性列表完善,上、下架,审批,用户对该资产是否有权限等等。这些业务逻辑往往比较复杂,如果都通过dao->Service层来处理,会带来以下的种种问题:service层非常臃肿,代码比较散乱,重复性代码较多,业务方法不够内聚,维护梳理障碍,扩展/变更性差……

如果将“资产”作为领域模型,除了它的属性外,将其涉及的业务操作抽象成方法也放在里面,那么对于代码可读性、对象及对象操作的范围边界、业务模块等将会比较清晰。

用领域模型设计后,service层的代码是这样的:

image.png

我们将多变的业务逻辑从service层拆出来,整合进领域和gateway,服务层专注于服务本身。从上面的图中可以看到,一个业务操作涉及了多个领域的多个业务方法单元,不仅实现了业务逻辑复用,是不是还很简洁明了呢?

这里要提示一点:要注意领域驱动设计的思考抽象方法,要尽可能遵循其约定,避免在后续的迭代更新过程中沦为之前的实体作用。

下面是一些使用心得分享:

领域类需要完整的构造

我们通常是通过两种方法来构造领域类:(1)数据库的表结构(2)抽象业务操作的实体和相关业务方法。

要注意的是:领域类一定要构造完整,对于不同的使用领域类的场景下,领域类对外的暴露都是完整且一致的。 不要出现部分属性没有初始化的情况。

尽量将逻辑沉淀为领域类中的方法,保持较好的结构和复用率

避免写着写着就绕开领域模型,增加逻辑直接调用Mapper处理业务。这是大多数习惯传统MVC架构的程序员在使用DDD之初一段时间内常犯的问题。

Gateway不要揉太多业务逻辑

      在底层infrastructure模块,gateway的作用主要是为了让domain类与基础设施层解耦,如领域类的保存行为不应该感知后端存储是MySQL还是其他数据库等,所有的业务逻辑应该沉淀在domain类中,通过gateway来对接不同的基础设施。

懒加载技巧

      领域对象会与其他的领域对象产生关联,每次构造领域对象会导致大量关联领域对象的初始化。大多数的领域对象初始化不仅会消耗内存和计算量,还会进行数据库IO,从而影响响应速度,导致领域对象初始化速度慢。 所以尽可能将这种依赖通过方法懒加载的方式暴露。

抛弃部分CQRS,走领域模型做查询

      我们有些习惯在查询场景下绕过领域层,直接select多条记录,存储为DO返回给Client端。但是这会导致越来越多的冗余逻辑存在,破坏代码结构,影响领域层的沉淀。所以不管出于何种考虑,既然选择了DDD,应该尽量去遵守其约定,走领域模型做查询。

相关文章
|
设计模式 缓存 自然语言处理
DDD领域驱动设计如何进行工程化落地
DDD领域驱动设计到底如何进行实际的工程化落地,为什么要进行领域分层?本文主要围绕DDD领域分层,设计了可落地的工程结构。
DDD领域驱动设计如何进行工程化落地
|
前端开发 Java 数据库连接
领域驱动设计:从学习到实践(一)
产品同学将需求分析完和开发同学进行需求评审,评审完毕后开发同学开始基于需求进行设计,一般会落到数据库设计,将库表设计完毕后,再向上进行分层开发。如果是前后端分离的项目,会在前期约定接口,进行基于契约的并行开发。所以,我们称这种方式为数据驱动开发,或基于数据模型的开发。
领域驱动设计:从学习到实践(一)
|
3月前
|
缓存 架构师 中间件
成为工程师 - 如何做DDD领域驱动设计?
成为工程师 - 如何做DDD领域驱动设计?
|
4月前
|
设计模式 存储 JavaScript
于领域驱动设计的理解
领域驱动设计DDD学习总结,主要参考Eric Evens的《Domain-Driven Design–Tackling Complexity in the Heart of Software》
55 0
|
领域建模 微服务
领域驱动设计总结——落地与思考
本文为领域驱动设计系列总结的第六篇,主要对领域驱动设计概念做个介绍,本系列领域驱动设计总结主要是在Eric Evans 所编写的《领域驱动设计》 一书的基础上进行归纳和总结。 本文也是领域驱动设计总结系列最后一篇,主要是简单的探讨下,领域驱动设计的落地方式,以及对这整个系列做一个总结。
350 0
|
设计模式 程序员 项目管理
领域驱动设计揭秘
领域驱动设计揭秘
|
存储 消息中间件 JSON
领域驱动设计:从理论到实践,一文带你掌握DDD!
学习DDD一个半月,最开始学习DDD的原因是因为我负责的业务线,涉及的系统非常多,想借鉴领域驱动设计的思想,看后续如何对系统进行重构。在没有学习DDD之前,感觉DDD可能属于那种“虚头巴脑”的东西,学完DDD之后,感觉。。。嗯。。。真香!
1760 0
领域驱动设计:从理论到实践,一文带你掌握DDD!
|
前端开发 大数据 程序员
【深度】领域驱动设计的实践
关注公众号“达摩院首座”,了解开发者最真实生活
613 0
【深度】领域驱动设计的实践
|
存储 消息中间件 设计模式
领域驱动设计(DDD)实践之路(二):事件驱动与CQRS
这是“领域驱动设计实践之路”系列的第二篇文章,分析了如何应用事件来分离软件核心复杂度。探究CQRS为什么广泛应用于DDD项目中,以及如何落地实现CQRS框架。当然我们也要警惕一些失败的教训,利弊分析以后再去抉择正确的应对之道。
1409 0