Advertisement

DDD 到底是银弹还是垃圾

阅读量:

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

在工作单位的时候有一群人声称要运用增量设计方法对老系统的进行改造以彻底消除核心业务流程规模化的所带来的维护难题但这种设想并没有实质性的效果实现因为项目的复杂性依然较高而在此之前一篇介绍系统重构的文章中所展示的那个状态正是将增量设计应用到项目重构之前的混乱局面

尽管每个人都非常聪明,在这个新需求的确切方向上却鲜有人知。一群架构师聚集在一起研习DDD理念,在这段时间里他们不断探讨并整理出了新的认识。经过半年多的时间,他们最终取得了一些初步成果——其中一部分子项目已经完成了基于DDD理念的重构工作,并将在年末时分……令人欣慰的是这些努力终于得到了认可,在未来的工作中我们相信这一探索将为团队带来更多的成长机会

年末的时候部门内匿名的小纸条在年末末期被几位架构师抛出直球:'为什么用了DDD之后代码会变得更难懂?' 当时许多DDD拥护者感到十分尴尬,并不得不含糊其辞地作了解答。

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

在某公司任职期间,直到离任前我系统性地阅读并研读了市面上所有与DDD相关的书籍。通过深入学习其理论体系并反复思考其精髓所在,在此过程中总体而言这套理论仍具有一定的应用价值。值得注意的是DDD理论自诞生以来便已逐步发展成熟而微服务的发展趋势是在随后逐渐发展起来的现象。具体而言,在DDD框架中所提到的bounded context这一概念恰好能够对应于服务粒度的需求这一特性使得DDD方法论得以并最终成为众多企业采用的核心业务方法

虽然技术人员普遍不以为然于这类话题,但事实上,并非技术实力与商业成功之间存在必然联系。同样地,方法论是否正确也并非直接决定项目能否取得成功。一些大公司的技术负责人经常分享他们的技术路线,但这些负责人往往对自己项目的成功原因却未必清楚,因此指望能直接适用于当前场景的可能性可能并不存在。不过适当时候获取些借鉴意见倒也不失为一种明智的做法

作为工程方法论之一,在目前的技术条件下难以有效反驳。从宏观角度来看,在过去几年中大量采用人工电池堆砌的企业仍能实现盈利与成长。值得注意的是,在这些案例中"员工"的态度与精神面貌直接影响企业的核心竞争力。当某家公司在全球范围内首次成为市值最高的企业时,则往往伴随着显著的技术创新突破。通过高强度的工作模式实现了突破"的人工智能技术往往能够快速转化为市场优势。因此"员工"的态度与精神面貌直接影响企业的核心竞争力。”

不过作为一个拘谨的技术人员,在批判方法论时最好能深入了解一下敌人。

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

战术设计与战略设计

从系统性视角来看,DDD的方法体系主要包含两大核心模块:战术设计与战略设计。通过常识可知,在这两大体系中,''战术设计''属于微乎其微的小模块,''战略设计''则是包罗万象的大模块。

  • 战术设计其实就是专注于单个模块级的设计问题,并且这些都属于纯技术领域的内容。DDD则提供了具体的代码命名规范以及模块化设计的原则。
  • 战略设计则涉及大项目中的模块划分问题。由于一线程序员的工作内容与这一领域关联不大(主要关注的是BU之间的资源分配问题),因此主要关注的是公司内部如何在BU之间合理划分资源以及如何在同一个BU内部将团队进行分工与协作。

如今许多应届毕业生在求职过程中往往会遭遇一些与面向对象编程(OOP)相关的面试问题。常见的三大核心特征和五大基本准则便是这类问题的核心考察点之一。然而,在软件系统设计中可作为参考的重要原则不仅仅是这些——虽然《clean code》与《clean architecture》这两本书的作者通常被称作'Uncle Bob'(白须爷爷),但其战术定义则主要围绕着单模块内的命名规范与设计策略。需要注意的是,《clean architecture》这本著作并未提及'DDD'这一概念及其相关理论体系

公司的业务如何分配给各个部门去完成? 通常是CTO或GM负责的事情。 部门内的项目如何分配以及各个团队负责的内容是什么? 这属于战略规划的范畴。 DDD强调战略规划需要系统的方法论基础。 这部分内容也是许多程序员认为是最无价值的部分。

战术设计

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

贫血模式与充血模式:DDD建议你在编写代码时采用对象导向的方式。具体来说就是按照对象导向编程的思想进行抽象处理,并将各个行为分配到对象身上。这与传统的纯过程式编程方法形成对比。DDD声称的充血模式的优势在于通过将各种行为封装到对象内部从而使阅读流程化的代码时会更加直观清晰地呈现step 1 step 2 step 3的过程。然而即便不采用严格的OOP组织方式也能实现对不同业务步骤的有效封装与复用功能。有些公司可能会将业务拆分成非常微小的部分从而使得在DDD框架下所声称的优势并不如其描述中那样明显

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

复制代码
    type person struct {
      age int
      name string
    }

就是值对象;当我们对这个person添加一个ID字段时,则可以让其能够唯一标识该person的存在

复制代码
    type person struct {
      id  int
      age int
      name string
    }

那它就是实体了。

这些术语仅仅将日常用品简单地划分为几个类别,并没有实质意义

聚合根 :在DDD框架中所指的就是事务粒度中的实体概念。具体而言,在我们进行数据库db的操作时,则必须为该事务分配一个特定的聚合根。当在一个事务中涉及多个实体的数据表进行操作时,则必须与每个相关联的数据表配对分配一个独立的聚合根。

聚合根既可以是一个 single entity 也可以是由 multiple entities 构成;具体来说,在你完成一次 database 事务时涉及的相关对象数量即为该事务对应的 aggregate roots 的数量;这些相关对象通常会形成一个或多个 aggregate roots。

六边形架构:我们常说的六边形架构,则是将所有外部的变化都抽象为adapter interface来进行适配。它将所有外部的变化都转化为adapter interface来进行相应的适配工作。如果你对依赖反转有一点了解的话,那么你知道如何实现这种抽象吗?如果没有相关知识储备,请及时转向其他领域学习吧!

六边形架构这一概念之所以引人注目,主要源于其名称的确切性.在《Clean Architecture》一书中,Uncle Bob也提供了一幅图解.

由于外链图片无法正常显示,请先将图片保存到本地设备后再进行上传操作以确保能够顺利显示

由Thoughtworks员工撰写的《evolutionary architecture》一书中包含了插件化架构体系,其中许多人赞赏采用的插件化架构。

外部链接中的图片无法正常加载,请检查该来源是否存在防盗链设置,并尝试将图片保存后再重新上传至该来源。

Repo Pattern:DDD 理论认为我们业务项目的存储这一层是可能经常变化的。因此专门提取了存储层的所有接口设计并命名为 Repo Pattern。这个概念其实没什么特别之处。比如 find、getlist、save 这些常见的操作,在具备基本 ORM 知识后都能熟练掌握。

情况表明,在 2021 年已经过去一段时间后,“更换存储系统”的想法变得不再现实且难以实施更换。即便如此,“这些新型的社区存储解决方案都兼容 MySQL 格式”。然而,“任何企图入侵代码库的行为”都是绝对不允许的,“这种行为完全不可接受”。

领域事件:其实就是实现上下游解耦的 Kafka message, 使用 domain event 可以让表述更加专业和优雅

领域服务:Domain Service Name suggests, by the very name, it is also applicable to your department or team's subnet API gateway.

总的来说,在大公司工作两年以上的程序员遇到这些事情应该是家常便饭了。这些知识对于熟悉技术的人来说应该不难掌握。没啥特别需要注意的地方。如果你是为了在架构师大会上展示自己的能力而不是为了取悦别人,请确保你的表现足够专业。

战略设计

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

Core Domain : 对于贵公司而言,在其经营活动中实现价值创造的核心在于销售商品与服务;而这一核心经营环节正是与其他主要竞争对手之间的竞争焦点。这即是公司运营的核心领域——核心经营活动。为何那么多行业精英都蜂拥而至的核心领域?因为这里的利润空间明显优于周边其他次要经营区域。

SubDomain :你们公司的销售模块(即卖货功能),但顾客无法接受付款,则该功能也无法继续进行。而支付处理则是独立于整个系统的另一个重要环节。

Supporting Domain :你们的企业主要以销售货物为主,在这种情况下,客户通常希望查看一些关键指标来辅助决策。因此必须具备相应的支持系统来满足这些需求。这可能涉及编写和维护与数据库相关的SQL系统作为支撑性功能模块。

Generic Domain :你在管理公司时会关注哪些事务呢?对于员工的入职与离职以及薪资发放等事务而言,在线系统往往会提供相应的支持功能。这些事务就属于通用域范畴。

除了第一个Domain外,在其余四个Domain中重要性依次降低,并且这种趋势表明,在公司进行裁员时通常会先从较低层级的人员开始裁减

部分程序员认为DDC策略设计无用。你对自己所在团队的工作职责对公司的重要性缺乏清晰认识,请切记,在被裁时请不要悲伤。

统一语言:这一概念更容易被理解。举个例子来说吧——那么所谓的跳水实际上指的是这个

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

你们讨论的主题涉及工作,在这种情况下DDD强调采用统一语言进行领域划分工作的可行性。经过这种划分后,在同一背景下,“同一领域的术语使用一致”。这即是 Bounded Context ,也可能涉及多个领域。

既然划分后,在同一领域内实施的话,那么完成业务流程就成为必要。不同情境下的协作方式则被称为 Context Maps 或 Integration Type

这种名词令人感到不愉快,但具体的方法仅限于两种:一是两个微服务之间采用RPC协议进行通信,二是基于MQ协议实现通信。

在采用RPC通信的情况下,通常情况下callee就是caller的父节点。但凡callee出现故障往往会波及到caller(当然也有熔断等技术防止两者同时崩溃)

若采用MQ通信方案,则通常会使得上层依赖方出现严重问题;由于一旦上层架构发生重构, 会影响广泛爆发, 最终导致统一配置信息变得混乱无章;而现实中许多系统的统一配置往往仍需人工干预

父子之间存在一种典型的 Conformist 关系模式。若父亲能够充分体谅子嗣的需求,则可发展出 Customer-Supplier 的互动模式。尽管顾客在本质上仍可被视为至高无上的存在。当涉及不同系统间的共享定义时,在实际操作中发现,在不同系统的代码库中可能存在一些共通的数据规范与流程标准。这种方法被称为 Shared-Kernel 模型,在某些情况下采用该模型可能导致整个团队出现重大冲突。

最后分析可知,在某些情况下我们可以采用名为ACL的技术来阻止上游的一些修改行为对我们业务逻辑的侵入

防护层 :Anti-Corruption-Layer, 其实就是我要阻止外部系统发生变更通过对接层传递到我的核心系统中去, 以此保证我对整个系统的控制不受外界干扰。

现在说到核心的知识点时,在座的人都已经复习了一遍。如果说DDD没有任何实用价值的话,我也不同意你的观点。看完这些书籍后,在我的理解中现在已经清楚如何找到能够赚取更多资金的地方。

请添加图片描述

全部评论 (0)

还没有任何评论哟~