实践 DDD 领域驱动设计

栏目: 后端 · 发布时间: 6年前

内容简介:领域驱动设计最近又火了。概念不断被提及,但是相信对于像笔者一样的很多开发者对于其如何应用都一头雾水。正如《实现领域驱动设计》中作者提到的不同公司的业务能力开发能力和成熟度不一样,

实践 DDD 领域驱动设计

说明

领域驱动设计最近又火了。概念不断被提及,但是相信对于像笔者一样的很多开发者对于其如何应用都一头雾水。

正如《实现领域驱动设计》中作者提到的不同公司的业务能力开发能力和成熟度不一样, DDD为了解决复杂业务为生,并不适合所有的软件项目, 对于很多初创公司而言,业务本身就是模糊的,只是需要做出一个MVP(最小可行性产品)来试探商业模式 ,采用ddd显得过“重”了一点,反而给团队成员带来额外的负担,所以 团队 管理者首先应该关注的是软件系统是否值得做出DDD投入

不过不管黑猫白猫,能抓到老鼠就是好猫。 我们以电商业务来演练和实践ddd的部分理论,并解释ddd的概念。

战略设计阶段

领域:即业务是属于哪块,电商领域,保险领域,零售领域,又可细化分为子领域。如电商下(订单交易领域、库存领域、会员领域、物流领域....)

领域专家:一般指熟悉对应领域的产品经理项目经理  

子域:子域可细分为核心子域、通用子域和支撑子域,简单理解为哪部分是比较核心的就可称作核心子域,哪些功能偏边缘化叫支撑域。

互联网公司的敏捷开发模式的产品研发流程从收集需求、PRD评审、技术模块拆分这些前期流程。而战略设计即在这个阶段完成,顾名思义侧重于从宏观上对业务进行拆分,和对未来走向的预测。

DDD的目的是为了领域专家更好地与开发进行沟通合作,使得代码更好地传达业务规则。

最初的需求方可能会提一些凌乱的需求。

为了更好地传达规则, 领域专家将需求整合提取出领域的概念, 技术/项目管理者一起划分好子域和限界上下文。各方统一所谓的 通用语言 并在以后的协作中使用 。比如电商业务中双方约定好中商家用户和买家用户的概念,用户和账户的概念,交易订单和支付订单、物流订单、售后订单的概念,以实现后期沟通顺畅。

最终产出:划分出了哪些子领域、上下文映射图是怎样的。

贴一个电商业务的上下文映射图(下单交易上下文为下游,其他皆为上游):

实践 DDD 领域驱动设计

而各个上下文的交互方式,即 集成限界上下文 的方式其实就是我们常说的系统交互方式:RPC调用、REST接口调用、消息队列通信。

怎么理解限界上下文和子域的关系?

限界上下文:是一个显示边界,领域模型即存在于这个边界之内。在边界内,通用语言有特定明确的意义。

ps:是不是觉得每个字都认得,但是不知道表达了什么意思....

在理解限界上下文和子域上确实有点费劲。笔者当时的疑惑主要是:为什么要用上下文映射图而不是子域交互图,子域划分出来不就说明边界已经明确了么,为什么还专门搞一个限界上下文的概念。

关于限界上下文,贴一下个人理解:

接下来要咬文嚼字一些了。

1、从“限界”二字来说。限界上下文明确了业务范围和职责边界。针对上面问题“子域中不是已经有边界的概念了么”。可以思考一个有意思的事,子域有边界,还是说因为有了边界才有子域。听到过一个非常到位的类比: 如果没有细胞壁,如何定义细胞质 ?

2、从“上下文”来说。上下文关注的是两个系统交互时的环境,或者说语境。

举个例子:小学是一个子域,中学是一个子域。升学这个事件动作则要上下文表达。

通用语言要在限界上下文(语境)中保证其明确意义。举个例子,商家管理上下文中,我们(平台)说的用户指的是商家而不是买家,支付上下文中,我们以支付单为核心,语境无需引入物流单、库存等词汇。

通常来说,我们可以近似地认为子域和限界上下文一一对应的。

战术设计阶段

截止到此,我们已经划分好了子域,对开发人员来说,已经拆分好了项目。各个团队可以针对自己的子域进行独立开发了。对于ddd而言,我们开始进行战术设计阶段。战略设计关心做什么,战术设计则更关心技术实现细节,即:怎么做。

先说下ddd中推荐的 六边形架构

实践 DDD 领域驱动设计

这里要吐槽一下六边形架构这个命名,搞得好像有六个什么东西一样。其实只是根据视觉形状起的名。现在叫端口与适配器架构。

转换一下是这样的

实践 DDD 领域驱动设计

严格分层架构:某层只能与直接位于其下方的层发生耦合

松散分层架构:允许上方层可以与任意下方层发生耦合。

这里采用松散分层架构。也可按依赖倒置原则, 基础层依赖领域层的一些东西(常见的就是实体Entity)

适配器层:

负责接口转换,即是最外层请求处理类,将外部请求转化为内部API能理解的输入。对于REST接口可能是一个controller类;

对于dubbo调用来说是开放出去的provider服务类;

对于grpc调用来说,是protobuf请求对象转换处理类;

对于消息机制来说,对应的是消息的监听器

如此采用端口适配器模式,可以不影响内部服务,只需在适配器层进行增改。尽管大家不知道六边形架构的定义,但相信很多人是这样做的。无须赘述。

应用层:负责协调领域层的接口实现前端展示或返回需要。

领域层:定义领域实体和逻辑。包括实体、值对象、领域服务、领域事件、资源库。

基础层:如数据库相关。

实体和值对象

实体:

有唯一业务标识

有自己的业务属

性和行为

属性可变,有自己的生命周期

值对象:  可以有唯一业务标识

有自己的业务属性和行为

一旦定义不可改变

二者的关系可总结为: 值对象关心对象是什么样的,实体侧重描述对象是哪个?

提到有自己的业务属性和行为这块,想想这不就是我们年轻时说的面向对象编程的思想码?

但是回顾一下会发现,这个思想好像被很多人抛诸脑后很久了,定义的对象类都成了一个个的pojo,只有属性和属性对应getter和seter方法,也就是ddd中所说的 失血模型。

失血模型:只含属性和对应的getter/setter方法,无业务处理逻辑

贫血模型:包含不依赖持久化的部分领域逻辑,依赖持久的逻辑被放在领域服务层。

充血模型:绝大数业务逻辑都放在其中,包括持久化逻辑。少数不适合的逻辑被提取出来放在领域服务层中。

胀血模型:主张不需要领域服务层,把一些业务逻辑都放在模型对象中处理

领域服务

胀血模型主张把所有的业务逻辑放在模型中处理,但是事实上有些逻辑并不是适合放在某个领域对象中处理。比如

1、领域对象间的转换

2、某些场景下需要多个领域对象作为输入值,结果产生一个值对象。

区别于应用层的服务,领域服务处理的是业务逻辑。应用层负责对领域服务处理结果进行渲染和组装返回给前端。ps: 针对查询类的操作,建议作为应用层的查询服务单独拎出来,因为查询尝尝涉及到多个维度的查询,或把多个领域对象的查询结果组装成一个返回值对象。

举个栗子:订单领域需要向商家(PC端)和买家(APP端),商家端按发货条件时间查询所有买家的订单,操作发货处理售后等流程。买家端完成下单、查询个人订单。在应用层我们抽象三个应用处理出来,公用的查询应用、商家端应用(关联商家权限控制上下文)、买家端应用(关联买家权限控制上下文)。

领域事件

领域事件即领域业务周期中一些关键行为,关键的定义是其他地方需要依赖此事件推送业务流转。如订单被支付这个事件,需要触发库存扣减、商家待结算账户余额增加等操作。关于领域事件处理方法:跨子域处理常用消息队列发布/订阅模式,同项目处理常用注册事件监听器处理。不多描述。

聚合和资源库

领域对象之间常常有依赖关系。比如主订单-子订单(商品)项,子订单依附于主订单存在,二者的关系称作 聚合 ,主订单作为 聚合根。

@Data
public class TradeOrderEntity {
//订单号
String orderNo;
// 商品详情
List<OrderItemDetailEntity> orderItemDetails;// ...}

我们通过为每一个聚合选择一个根,并通过根来控制所有对边界内的对象的访问。 外部对 象只能持有根的引用; 由于根控制了访问,因此我们无法绕过它去修改内部元素。所以在ddd中,资源库Repository 是面向聚 合根操作的,可对多个dao对象 的组合使用。

@Repository
public class TradeOrderRepository {

@Autowired
TradeOrderMapper tradeOrderMapper;

@Autowired
OrderItemDetailMapper orderItemDetailMapper;
}

关于其中一些思想,笔者也没有想清楚,所谓知行合一,恐怕很多方法论要真的遇到问题了才会理解其价值。先整理到这。最后针对 Java 后端开发同学,提供一个模块分层的框架供参考

实践 DDD 领域驱动设计

思考

无忌,我教你的还记得多少?” “回太师傅,我只记得一大半”

“ 那,现在呢?” “已经剩下一小半了”

“那,现在呢?” “我已经把所有的全忘记了!”

“好,你可以上了…”

实践 DDD 领域驱动设计

实践 DDD 领域驱动设计

END


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Code Reading

Code Reading

Diomidis Spinellis / Addison-Wesley Professional / 2003-06-06 / USD 64.99

This book is a unique and essential reference that focuses upon the reading and comprehension of existing software code. While code reading is an important task faced by the vast majority of students,......一起来看看 《Code Reading》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具