DDD战略战术

简介: DDD开篇总结》[1]的前三篇已经阐述了几个内容1.DDD是什么2.复杂系统的特征3.DDD如何应对复杂系统4.模型概念5.软件开发流程但一般DDD资料中都会分为两部分讲述:战略和战术,所以按这两种分类,重新归纳整合一下

《DDD开篇总结》[1]的前三篇已经阐述了几个内容

1.DDD是什么

2.复杂系统的特征

3.DDD如何应对复杂系统

4.模型概念

5.软件开发流程

但一般DDD资料中都会分为两部分讲述:战略和战术,所以按这两种分类,重新归纳整合一下

在讨论战略和战术前,先表述一下“道”

DDD是一种软件开发的方法论,任何方法论,都必须落实到“减少代码复杂度”

那么“道”是什么呢?

一直认为DDD的战略就是道,结果搞错了

软件开发的终极“道”就是“高内聚、低耦合”,它是任何有价值思想和方法的具象

如何才能达到这个终极道呢?

1.DRY2.分离关注点

2.1. 业务和技术分离2.2. 业务和部署分离2.3. 变与不变分离

3.缩小依赖范围4.向稳定方向依赖


image.png

战略

DDD战略主要包含统一语言和限界上下文

统一语言

image.gifimage.png

在以往OO开发过程中,会经过OOA,再到OOD,复杂系统中,没有人能全方位了解系统并实现系统,术业有专工,专业人士干伟业事,这是正确的

但分工后,团队合作时沟通至关重要,,在整个系统开发过程中,是有一根主线的,那就是业务知识,业务知识在系统落地前经过层层传递,走样变形是常有的事,从开发人员经过多少次的返工情况就很清楚

如果解决这个问题呢?DDD引入了统一语言,把业务名词含义事先确定好,减少不必要的翻译过程,车同轨,书同文,行同伦

这也消除了业务与技术之间的重复,共同使用业务原语对话

代码就是文档,代码就是领域知识

userService.love(Jack, Rose) => Jack.love(Rose)
companyService.hire(company,employee) => Company.hire(employee)

界限上下文

界限上下文囊括了实现道的方方面面,如分离关注点,每个上下文围绕一个关注点,通过整洁架构让各层向稳定方向依赖,合理的划分界限,使各个上下文之间减小依赖

说白了界限上下文就是把一个大系统分而治之

界限上下文算是DDD中的核心知识点,但常被技术人员忽视,对于实用主义的程序员来讲,战术常常更吸引人,其实大到微服务,小到实体类,背后都渗透着上下文的概念

引入限界上下文的目的,不在于如何划分边界,而在于如何控制边界

Alberto Brandolini认为bounded context are a mean of safety(限界上下文意味着安全),safety的意思是being in control and no surprise,对限界上下文是可控制的,就意味着你的系统架构与组织结构都是可控的

显然,限界上下文并不是像大多数程序员理解的那样,是模块、服务、组件或子系统,而是你对领域模型、团队合作以及技术风险的控制

限界上下文是“分而治之”架构原则的体现,我们引入它的目的其实为了控制(应对)软件的复杂度,它并非某种固定的设计单元,我们不能说它就是模块、服务或组件,而是通过它来帮助我们做出高内聚低耦合的设计。只要遵循了这个设计,则限界上下文就可能成为模块、服务或组件。所以,文章《Bounded Contexts as a Strategic Pattern Beyond DDD》才会写到:“限界上下文体现的是高层的抽象机制,它并非编程语言或框架的产出工件,而是体现了人们对领域思考的本质。”

战术

对于开发人员而,战术是最实用的,比如聚合、实体、值对象、工厂、仓储、领域事件等等, 使用这些战术组件建模工具,DDD满足了软件真正的技术需求。这些战术设计工具使开发人员能够按照领域专家的思维开发软件

战略部分讲了,界限上下文的思想是核心,在战术组件中都有体现,比如实体,实体就是一个最小上下文,聚合就是相对实体大一点的上下文

但残酷的现实是,花费了大量的精力来学习这些DDD战术组件,却在实现项目中却用不上,为什么呢?因为事务脚本思维太深,分层也大多是从技术角度出发,没有抽象出领域模型,也就是没有OO抽象,没有一个完整的对象,实体都没有,像工厂,值对象也就成了水中花

这也是我们虽然常重构代码,也不过是大类变小类,大函数拆分成小函数,符合一下代码规范,但对整个项目而言,其实没有实质性改进

如何能有实质性改进,对于复杂系统如何运用上这些战术组件呢?

此时,结构性思维发挥作用了

第一步:过程分解,把一个复杂的系统按流程拆解成各个阶段和步骤,这也是事务脚本的强项

第二步:对象建模,过程性拆解虽然可以降低了开发难度,但领域知识被割裂,代码的业务语义也不明确,在这方面OO是强项,提升代码复用性和内聚性

image.gifimage.png

结合这两步,自上而下的结构化分解+自下而上的面向对象建模,过程化分析更好地清理了模型之间的关系,而对象模型提升代码复用性和业务语义表达能力

总结

DDD是一套很好的方法论,有时我们常在理论纯洁性与实战性之间徘徊。这也许是初级阶段常有的纠结点

DDD有适用场景,事务脚本有存在的优势

image.png

不能因为现在人们开口闭口都是DDD,就硬要开展DDD

DDD难以落地除了本身带来了很多概念,还需要团队整体素质

软件开发没有银弹,不能偏执于一种理论,实际开发是场硬仗,像混合格斗一样,不在于一招一式是哪门哪派,制敌才是终极目标,所以需要根据自身情况进行裁剪,灵活运用

References

[1] 《DDD开篇总结》: http://www.zhuxingsheng.com/blog/ddd-opening-summary.html


目录
相关文章
|
移动开发 小程序 Linux
【Linux】Linux和Window下\r与\n的区别、git命令行的使用
目录 1. 回车换行符在Window下和在Linux下的区别: 1.1回车换行符: 1. 2.行缓冲区打印: 1.3进度条小程序 :
421 0
|
JavaScript 前端开发 Java
vue3-element-admin 项目说明文档
vue3-element-admin 项目说明文档
|
设计模式 存储 缓存
初探DDD
基于学习《殷浩详解DDD:领域层设计规范》后的动手实践,简单总结,以及个人理解
|
Java 关系型数据库 MySQL
面试官:聊聊你对分库分表的理解?
面试官:聊聊你对分库分表的理解?
143 3
|
C语言
【C语言】英寸英尺转换米
【C语言】英寸英尺转换米
130 0
|
消息中间件 存储 架构师
一文揭秘DDD到底解决了什么问题(1)
一文揭秘DDD到底解决了什么问题
308 0
|
消息中间件 测试技术 领域建模
DDD - 一文读懂DDD领域驱动设计
DDD - 一文读懂DDD领域驱动设计
39860 5
|
Java
ThreadLocal-内存泄露问题
在使用ThreadLocal时,如果没有及时清理ThreadLocal变量,就可能会导致内存泄漏问题。这是因为ThreadLocalMap中的Entry对象持有了对ThreadLocal对象的强引用,而ThreadLocal对象又持有了对变量副本的引用。如果没有手动调用remove()方法来清理ThreadLocal变量,那么Entry对象和变量副本就会一直存在于ThreadLocalMap中,无法被垃圾回收。
213 0
【刷穿 LeetCode】371. 两整数之和 : 使用「位运算」求解的两种方式
【刷穿 LeetCode】371. 两整数之和 : 使用「位运算」求解的两种方式
下一篇
oss教程