每过一段时间,就会有人跳出来批判 DDD,这东西到底是垃圾还是银弹?

在某某公司干活的时候,有一批人声称要用 DDD 改造老旧系统,彻底解决核心流程规模化之后,项目难以维护的问题。之前某篇文章里的这张图,就是在用 DDD 做项目重构之前的烂摊子:

大家都很聪明,聪明到最后没人知道这新需求到底该往哪里写了。架构师们聚在一起学习 DDD 精神,产出学习报告,大半年过去,终于出了一些成果,有些子项目完成了用 DDD 进行的重构,年底可以拿来在酒会上邀功了,这下我们跟上了业界业务开发的主流方法论,可喜可贺,可喜可贺啊。

年末的时候部门内匿名提问的小纸条却向架构师们发直球:“ 为什么用了 DDD 以后,代码更难懂了 ?”,当时引得各位 DDD 推手尴尬无比,只能搪塞过去。

所以你觉得我是要批判么?那倒不是。

在某某公司工作期间,到离职前,我把市面上所有 DDD 相关的书全部看了一遍。对其理论体系进行了完整的了解,可以说这套理论还是有些用处的,DDD 的理论诞生时间比较早,微服务的趋势是后来才爆发的。但微服务刚开始没有明确的拆分指导,人们发现 DDD 里的 bounded context 好像看着正好和服务的粒度是可以做个对应的,DDD 就成为了很多公司做业务的绝对主流方法论。

虽然很多技术人员不爱听,但是技术优劣和商业成败其实没什么必然的联系。同样的,方法论的对错和项目的成功与否也没有必然的关系。很多大公司做业务的人出来讲他们的技术方法论,这些人可能连自己的项目为啥成功都不一定知道,你指望能对你的场景产生直接帮助那可能是想多了。只是当听个乐,得个借鉴那可能还没什么问题。真的当金科玉律去执行,那撞一头包也正常。

DDD 和其它的工程方法论一样,没有办法证伪。放眼望去,纯粹堆砌的人肉电池,不用 DDD 的项目也那么多成功的,大家的屁股还是在跟着公司的市值跑,哪家公司市值涨到中国第一了,那他们的技术就牛逼,这叫看市值决定价值观。如果一家公司靠 996 成功了,那 996 就是商业致胜的法宝,不学你就落后了。屁股可以决定脑袋嘛。

不过作为一个矜持的技术人员,我们在批判方法的时候,还是应该要先对敌人有一些了解。

所以这一篇,我就简单带你们看看 DDD 那些鬼名词都是什么意思。

战术设计与战略设计

整个 DDD 的方法论可以划分为两个大模块,战术设计、战略设计。这个你顾名思义,战术是小,战略是大。

  • 战术设计指的就是单模块级的设计,基本都是纯技术范畴的东西,只DDD 给代码命名和模块设计给出了一些指导方法

  • 战略设计指的是大项目的模块拆分,这个和一线程序员关系不大,主要是公司那怎么在 bu 之间切蛋糕,bu 内怎么在 team 之间分赃

现在很多校招程序员可能或多或少都会碰到一些问题 OOP 方面的面试题,比如三大特性五大原则之类的, 这些原则是设计项目的时候可以参考的原则, DDD 的战术设计就是在单模块上的各种命名规则和设计方法 。只不过 OOP 这些原则的发明人(严格的说应该是汇总人)是 uncle bob,就是 《clean code》,《clean architecture》 的作者,这位白胡子爷爷大概率是和 DDD 社区是尿不到一个壶里的,所以 《clean architecture》 这本书里只字未提 DDD。

公司的业务要怎么分派给不同的人 bu(部门)去完成,这个一般是公司 CTO 或者 GM 要做的事情, 部门内的项目要怎么分,哪些组做哪些事情。这是战略设计的范畴 。DDD 声称战略设计也是要有方法的。这部分也是很多程序员认为最没用的一部分,我们后面来批判一下这些程序员。

战术设计

战术设计是纯技术范畴的东西,最让人头痛的就是里面的名词。

贫血模式和充血模式:DDD 推荐你用充血模式写代码,也就是按照 OOP 的方式去做抽象,然后把行为挂在对象上,而不是以纯过程式 的方法去写代码。所谓的充血,就是对象本身有很多关联的行为,而不只是一个单纯的数据库的表的字段映射。DDD 声称的充血模式的优势是,大部分的行为被封装到了对象内部,这样我们在阅读流程代码的时候,是一目了然的,直接能看到 step 1,step 2,step 3。但实际上即使我们不用 OOP 来组织行为,一样可以把不同的业务 step 做好封装和复用。有些公司的服务粒度拆得特别细,比如只有 5000-10000 行代码,在 DDD 里声称的充血模式的优势没有那么明显。

值对象和实体:这个也挺离谱的,值对象就是纯粹的数值、文本类型,比如:

type person struct {age intname string
}

就是指对象,如果我们给这个 person 加一个 id,让它能表示 person 的唯一性了;

type person struct {id  intage intname string
}

那它就是实体了。

这两个概念只是给我们日常用的对象们进行了一个简单的分类,没什么大用处。

聚合根:DDD 所谓的聚合根是事务粒度的 entity,也就是说,如果我们对 db 进行存取,那么我们就需要有一个聚合根,如果在一个事务里需要操作多张表,那么就需要给多张表关联一个单独的聚合根。

聚合根本可以由一个 entity 组成,也可以由多个 entity 组成,就是你完成一个任务 db 事务的时候有多少关联的对象 ,那可能就有多少在同一个聚合根下面的 entity。

六边形架构:这个所谓的六边形架构,就是除了业务以外的所有外部变化都抽象成 adapter interface 做适配。如果你稍微理解一点点点依赖反转,那应该知道怎么样去做这种抽象。如果你一点都不了解,那我建议你去看看 go-micro 的代码。如果看不懂,建议还是尽早转行吧~

六边形架构这东西主要是名字实在起得太奇怪,在 《clean architecture》那本书里,uncle bob 也给过一张图:

《evolutionary architecture》这本书出自造词大本营 thoughtworks 的员工之手,里面有一个 plugin architecture,就是有些人特别喜欢说的插件化架构:

Repo Pattern:DDD 理论认为我们业务项目的存储这一层是可能经常变化的,所以就专门存储层的 interface 设计单独拿出来,称为 Repo Pattern,这东西实在没啥可说的,find,getlist,save,你只要有一点点 orm 经验,里面有啥接口应该自己都可以默写出来。

事实是在 2021 年,我们的存储系统基本是不太可能做切换的了,即使切换,那些新兴的社区存储系统也会支持 MySQL 协议,基础设施想要侵入代码,那简单是大逆不道啊。

领域事件:其实就是做上下游解耦的 kafka message,我们用 domain event 显得会更洋气一些。

领域服务:Domain service,顾名思义,你认为是自己部门或者组内的局部 api gateway 也是可以的。

综上,如果你是在大公司一线工作了两三年的程序员,上面这些东西应该马上就能理解,没有啥值得说的。如果是为了去架构师大会上秀一秀,你总得包装一下让自己显得没那么土吧?

战略设计

Domain:领域,你们公司是干啥的,你都不知道吗?

Core Domain:你们公司的卖货的,那卖货就是你们与其它竞争对手的关键竞争环节。这就是核心域,就是核心业务,为啥聪明人都往核心业务挤?核心业务的汤也比边缘业务的饭好啊。

SubDomain:你们公司的卖货的,但是用户没法付钱,那也没法干,支付就是子领域。

Supporting Domain:你们公司是卖货的,但是客户想看一些指标,你总得有系统能支持吧?可能就是些写写 SQL 的系统。支持域。

Generic Domain:你管你们公司干什么呢?员工的在职离职,工资发放总得有系统能支持吧,这些就是通用域。

除了第一个 Domain ,其余四个 domain 重要性逐级递减,递减的意思是,如果公司要裁员,那是从下面往上面裁。

前面我说有些程序员觉得 DDD 战略设计没用,你连自己所在的组,从事的工作职责对于公司来说重不重要都不清楚,那被裁的时候也别哭哦。

统一语言:这个就更好理解了,比如跳水这个词,你说跳水的时候指的是这个:

而你同事说跳水的时候指的是这个:

这里你们聊的是工作,那说明你们一定不是在同一个上下文里工作,可能你们俩一个在体育赛事部门,另一个可能是在金融部门, DDD 认为可以用统一语言来进行领域划分工作。划分后在同一个上下文内,同一个名词大家说出来意思一致。这就是 Bounded Context, ain。

既然拆分了,如果我们还在同一个 domain 内,那完成业务流程是需要协作的,这个不同 Context 的协作方式就叫 Context Maps 或者 Integration Type。

名词很恶心,但具体的方法就两种,两个微服务要么通过 RPC 通信,要么通过 MQ 通信。

如果通过 RPC 通信,那 callee 一般是 caller 的爹,很多时候 callee 挂了是要影响 caller 的(当然也有熔断之类的方法避免一起死)。

通过通过 MQ 通信,那上游一般是下游的爹,因为上游一个重构,下游们可能就都炸了,最终一致都是屁话,多少公司的最终一致都是靠人肉修的。

这种爹和儿子的关系就是 Conformist 。如果爹能多考虑一下儿子的需求,那就是 Customer-Supplier 关系,毕竟顾客名义上还是上帝。如果跨系统有一些需要共享的定义,比如公司里的业务分类,可能大家都要从某个系统的 PHP 文件里解析出来在自己的系统里去用,那这时候可能得去使用别人的代码,这种叫 Shared-Kernel,Kernel 一改,大家一起死。

最后,有时候我们可以用一个叫 ACL 的东西拦住上游的一些修改对我们的业务逻辑侵入:

防腐层:Anti-Corruption-Layer,就是我要把外部系统的变化拦截在对接层,不要让别人的屎甩到我身上。

讲到这里,基本的概念我们已经都过一遍了,你要说 DDD 一点用处都没有,那我也是不同意的,至少看完了这些书,我知道去哪里能赚到更多的钱了。

原文链接:https://mp.weixin.qq.com/s?__biz=MjM5NDM4MDIwNw==&mid=2448836593&idx=1&sn=bd223c8ff27fb3c97455621e0ad21a60&utm_source=tuicool&utm_medium=referral

如果觉得本文对你有帮助,可以关注一下我公众号,扫描下方二维码关注“w的编程日记”获取更多Java资料

用了 DDD 以后,代码更难懂了?看完这篇你就明白了相关推荐

  1. 程序异常异常代码: 0xc0000005_Java基础:看完这篇你还怕碰到异常吗?

    前言 在日常的开发以及平时的学习练习中,异常相信对于大家来讲并不陌生,但是对于异常的具体使用.底层实现以及分类等等可能并不是很了解.今天我就抽出了一点时间系统的整理了异常的各个知识点,希望能够帮助到大 ...

  2. 和对象一起运动更快乐!看完这篇正经研究,找对象的理由又多了一个

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 萧箫 发自 凹非寺 量子位 报道 | 公众号 QbitAI 还在自己 ...

  3. 为什么用了 DDD 以后,代码更难懂了?

    每过一段时间,就会有人跳出来批判 DDD,这东西到底是垃圾还是银弹? 在某某公司干活的时候,有一批人声称要用 DDD 改造老旧系统,彻底解决核心流程规模化之后,项目难以维护的问题.之前某篇文章里的这张 ...

  4. 新手入门,数控刀具上的代码怎么认?看完就懂了!

    新手入门,数控刀具上的代码怎么认?看完就懂了! 按照不同的刀具类型对刀具分组: 类别组1 xxyyy(铣刀类): 110 球面铣刀 (圆柱型铣刀,其后的字母y代表铣刀直径,以下略同) 120 立铣刀 ...

  5. Python代码执行顺序,看完你就明白了

    文章目录 前言 一.Python代码执行时,遵循以下原则 二.运算符基本分类以及运算规则 总结 活动地址:CSDN21天学习挑战赛 前言 如果你对代码执行的顺序不是很熟悉,那你可以仔细看看这篇文章.如 ...

  6. 看完这篇你们团队的代码也很规范

    最近重构项目组件,看到项目中存在一些命名和方法分块方面存在一些问题,结合平时经验和 Apple官方代码规范 在此整理出 iOS 工程规范.提出第一个版本,如果后期觉得有不完善的地方,继续提出来不断完善 ...

  7. 编程猫python课程结束后哪里再学更高级别的_@正在选编程猫的家长,先别急,看完这篇测评再报也不迟!...

    最近有个家长咨询鱼sir要不要给孩子报编程课?大概意思就是身边同事朋友都报了,他也不甘人后,想给孩子报一个.于是就来问问鱼sir有没有好的编程课推荐. 诚然,学习少儿编程可以锻炼孩子的逻辑思维能力和想 ...

  8. 【C++】Clang-Format:代码自动格式化(看这一篇就够了)

    文章目录 Clang-format格式化C代码 1.引言&安装 1.1引言 1.2 安装 2. 配置字解释 2.1 language 编程语言 2.2 BaseOnStyle 基础风格 2.3 ...

  9. 看完这篇文章再也不用担心代码格式不对无法合并了

    本文由RT-Thread论坛用户@RTT_逍遥原创发布:https://club.rt-thread.org/ask/article/3121.html GITHUB仓库: git_auto_scri ...

  10. 贝叶斯网络python代码_贝叶斯网络,看完这篇我终于理解了(附代码)!

    1. 对概率图模型的理解 概率图模型是用图来表示变量概率依赖关系的理论,结合概率论与图论的知识,利用图来表示与模型有关的变量的联合概率分布.由图灵奖获得者Pearl开发出来. 如果用一个词来形容概率图 ...

最新文章

  1. MIT自然语言处理第三讲:概率语言模型(第一、二、三部分)
  2. 提示用户输入一个高考_2020年湖南省高考成绩查询方式及录取动态查询方式
  3. C语言设备管理器作业,你知道到吗,C语言竟是如何调用硬件的?
  4. python中三种分支结构的_python 运算符与分支结构
  5. 单用户修改root密码--redhat7.2 or centos7
  6. Java模板方法中规定传的参数,java – 如何在Kotlin中实现模板方法设计模式?
  7. C++头文件中定义全局变量在多次引用时出现变量多次定义符号冲突的解决办法...
  8. istio组件介绍和启动流程
  9. 解决算法问题的思路总结
  10. Python3.0 我的DailyReport 脚本(四)发送日报
  11. 7.java基本数据类型转换包含哪两类?
  12. .mcs与.bin文件格式有什么区别?
  13. 大数据-Redis基础
  14. Docker一探究竟
  15. 易语言服务器调试输出为假,跟我入门易语言 7 调试输出与输出调试文本
  16. Android4.1
  17. hx711c语言程序,STM32写的HX711程序
  18. java xmap_xml和java Bean的直接转换,Xmap
  19. Linux ps指令介绍
  20. win10计算机自带的游戏怎么打开方式,win10自带游戏及应用打不开,应用商店闪退无法使用...

热门文章

  1. 传世单机架设,账号登陆后,无法选择服务器,点击无效,无法进入游戏。
  2. Eslint的严格模式
  3. 【CVPR 2021】 Lifelong Person Re-Identification via Adaptive Knowledge Accumulation
  4. 最新联发科Helio X30(mt6799)芯片处理器详细资料(datasheet)
  5. 解决:香橙派orangepi3lts网口用不了 网口灯不亮 没反应
  6. 数据库之MySQL日志管理、备份与恢复
  7. QT5写一个复数计算器(附源码)
  8. python的eval函数
  9. Python爬虫进阶教程(五):数据存储
  10. SCI 期刊、SCIE 期刊和 ESCI 期刊的比较