0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

为什么需要DDD?DDD怎么解决问题?

马哥Linux运维 来源:尚弟的小笔记 2023-01-30 10:19 次阅读

为什么需要DDD?

没有实施DDD的情况下,我们经常会遇到什么问题?

开发人员热衷于技术而不是深入了解业务。这是技术人员的职责使然,一个不高级的开发,通常他的业务经验不重要;一个高级的开发,通常因为竞业,也无法继续干类似的业务。所以开发人员对业务天然的没有足够的兴趣。但是开发过程中,对业务不够熟悉,很容易发现开发做了半天得到的,并不是用户和产品想要的;或者下次再有需求的时候,技术上的改动特别大,成本很高。

业务协作不畅,一个需求提到好几个团队都能做,但是开发过程你推我我推你,需求一拖再拖,有时候项目中期还得找其他团队求资源。

对项目工时的估计占用了不少精力,还不准确。估时这件事能成为管理层和开发人员之间的拉锯战。

服务之间紧耦合,牵一发而动全身,一个非核心的业务抖一抖,客户都说没法用。

那么 DDD 怎么解决这些问题?

找到边界:让设计系统的人知道一个业务的边界在哪里。只有知道边界在哪里,才能在需求到来的时候,轻易地找到相关团队,各个业务之间也才能真正解耦,降低非核心功能对核心功能的影响。

知识获取:保证设计系统的人能够低成本地了解业务,让大家在怎么做,怎么验收方面达成一致。在此基础上,还可以免费得到一款评估时间的工具,项目的交付就更有把握。

但是在此我要多说一下,我们现实实践中已经有一部分领域概念的影子了——谁能说他不知道自己的组织是干啥的?或者说哪个组织没有业务重心呢?可是为什么大家没有获得上边说的这诸多好处呢?那是因为DDD实践过程中巧妙地将设计模型落地成为开发的模型,让需求方和实施方说一种语言,才能真正跨越了需求和实现之间的鸿沟。所以实践DDD,绝不是只有开发写写代码就行,而是要跟产品,设计以及领域专家一起完成设计,才能得到DDD的好处。

DDD是什么呢?

我们先看几个*DD:

TDD 驱动测试开发

BDD 行为驱动开发

ADD 不是单词Add,而是 API 驱动开发

DDD 领域驱动设计

前面几个概念落脚点都是开发,而DDD,是设计。

它有三个关键词:领域,驱动,设计。领域,是要探索业务的边界;驱动,表示前者是后者的决定性因素;设计,包括产品设计,UIUE设计,软件设计。它不仅仅是开发架构的方案,而是完整的解决方案实施思路。正是因为它是完整的方案,才能让领域专家,产品和研发真正在同一个角度去思考和沟通,避免推诿扯皮,含糊不清。

那么怎么做DDD呢?

实施DDD一般有两步,并且需要开发,产品和领域专家的通力合作。为了实施速度有所保障,还有一些项目加速和项目管理工具:

战略设计

战术设计

战略设计

战略设计可以说是搭建了业务思想上的框架。这个阶段要做这么几件事:

使用限界上下文分离领域模型

在限界上下文发展通用语言

使用子域处理遗留系统

使用上下文映射来集成多个限界上下文

限界上下文分离领域模型

限界上下文这个名字乍一看,每个字我都认识,但是这个词是啥意思?原文说它是语义和语境上的边界,我的理解是,它是在描述组织交付出来,面向客户的交付边界。如果是在SaaS场景,一个限界上下文应该是一个独立交付的软件;在PaaS场景,它应该说的是一个独立售卖的模块。它的含义是找到一个边界,要把这个边界以外的当成是无法改变的客观环境,不要幻想这个边界以外的人会配合你一起完成交付。那这一步设计就很好理解了,就是找到你业务对外承诺的边界,你要发展的业务在这个边界内,而不在此之外。如果你是对内交付的系统,那么你对其他同事交付的业务边界,就是你的业务限界上下文。

一个组织里,最核心的限界上下文被称为核心域。通常除了它,还有通用子域和支撑子域。通用子域是很成熟的业务,通常可以外包或者购买现成的解决方案,比如搜索子域可以通过ES来支持;支撑子域通常没有现成产品,但是它没有核心域重要,因此也可以一定程度的外包,避免在核心域之外浪费资源,比如大多数公司的数据库中间件是在开源产品上做了一些定制开发和维护。

限界上下文这个概念的目的是为了在业务扩展的时候,防止向领域内注入概念,导致业务变得没有边界,纠缠在一起。

在做这一步的时候,DDD要求以领域专家意见为准,正所谓领域驱动嘛。当实施了DDD方法以后,不论是领域专家还是开发,都应该拒绝向领域注入与业务无关的概念,比如存储方式等。这与我们日常工作从如何存储开始构建业务系统是完全不同的。只有把这些技术概念放到业务之外,我们的业务核心往往才能足够集中,易于迁移,而且不论采用什么东西存储,用什么东西展示,它的逻辑都可以不变。

这个过程中我们通常可以得到这样一个模型:

7caf2e2e-a03d-11ed-bfe3-dac502259ad0.png

限界上下文发展通用语言

当我们有了业务的限界上下文以后,就需要在这个限界上下文中发展一种语言用于表达软件模型,这个语言就叫做这个限界上下文里的通用语言。它可以是任何计算机语言、人类语言或者图形,只要能让团队内的每个人都能看懂。

通用语言不止是名词,它应该使用一系列具体的模型场景来描述领域模型。它描述了各种业务组件(不是技术组件)做什么,而不是用例或者用户故事。

比如微信朋友圈点赞这个场景,通用语言可能是:用户可以通过点赞,使得某个朋友圈的Feed发出人收到被点赞的通知,达到互动的目的。

但是到这一步,我们怎么能验证领域模型能与领域专家的心智保持一致呢?那就是为这个模型写验收测试,并交由领域专家评估。一种做法是验收测试采用given-when-then语法(中文可以用假如-当-那么),便于阅读理解。验收测试也可以用脑图,文字来描述,甚至DDD不反对采用单元测试框架写验收测试,只要领域专家能够阅读并理解写出的验收测试。

这一步做完后我们的模型图形其实没什么变化,但是现在,开发能够更充分的了解业务了。

使用子域处理遗留系统 我们代码不是在真空里运行,它们免不了会跟一些遗留系统打交道,这些遗留系统的边界并不清晰。因此我们会将遗留系统放到一个子域里,把它们的问题放到我们的设计之外。这一步做完后我们的图案与之前没有本质上的区别,无非是多了一点子域。

7cbd14d0-a03d-11ed-bfe3-dac502259ad0.png

使用上下文映射来集成多个限界上下文

上下文映射是两个限界上下文之间的连线,表示了这两个概念之间的关系,也表示这这两个概念的通用语言的翻译。通常来说,不同的限界上下文是不同的团队在维护,那么此时它也代表着两个团队之间合作的关系。

我们常见的映射关系是RPC接口。然而在领域设计里,限界上下文之间使用RPC是有风险的方案,因为会承受网络风险,还意味着两个限界上下文之间存在紧耦合。如果系统A阻塞请求系统B,B又请求C,就很容易导致集成火车事故:火车里某一节车厢有问题就会变成整列火车的问题。

最好的限界上下文映射关系采用事件的订阅,但是这要求领域专家在设计的时候就考虑不同领域之间通知的延迟对于业务的影响,以及如何消除影响。如果不采用DDD的方式,领域专家通常无法意识到领域之间的同步成本,技术人员也很容易一头撞进集成火车里。这就是我说的:DDD的目标是找到边界和促进学习知识,不仅仅是开发学习业务,领域专家也是在学习系统的边界与设计。

战术设计

在战术设计阶段包括如下设计:

把一些实体和值对象放一起,称为聚合

利用领域事件通知相关系统。

聚合怎么设计

一个限界上下文里通常有多个聚合,聚合逻辑上是相对独立的。怎么理解聚合的概念呢?在DDD实践中,聚合是事务的边界;聚合之间并不保证事务,只能用最终一致性。任何需要事务保护的逻辑都应该在一个聚合内。在限界上下文里,将其他聚合能力整合在一起对外提供能力的聚合,被称为聚合根;其他聚合也被称为实体。

此外,一个限界上下文里还有值对象,它也代表了某种相对独立的概念。怎么区分实体和值对象呢?这取决于业务。如果一个名词,具有多种动词去操作它,那么它应该是一个实体;如果一个名词,在系统里只是被传递而没有业务逻辑,那么它就是值对象。

由于聚合是事务的边界,那么每个聚合在设计阶段,最重要的是找到业务的不变性,也就是说,在事务提交前后,数据的约束条件。比如说,你在知乎对一条回答点赞,那么这条回答的点赞数量必须立刻多1,那么点赞的动作和点赞的计数,就应当在一个聚合内。

领域专家必然希望任何事情都能在触发后立刻完成,所以在沟通的过程中要不断质疑,如果不实时地做一件事,会不会有问题。甚至可以用一个夸张到显然无法接受的时间长度来质疑,以促成领域专家对此认真思考。

在聚合被设计出来以后,我们的模型图看起来会是这样的:

7cc1bd78-a03d-11ed-bfe3-dac502259ad0.png

领域事件怎么设计

我们说聚合之间要采用最终一致性,而通常的做法是采用领域事件实现最终一致性。领域事件的名称应该采用通用语言命名,才能符合领域专家的心智。完整的时间名词应该是名词和动词构成的,动词应该是过去时。领域事件的名字和属性应该能够完整描述这个事件的含义。

事件里通常至少包含业务动作和其业务参数,也可以增加更多的下游关注的事件信息,避免下游为了完成处理还需查询。

领域事件会持久保存在专门的数据表中,用来表示领域事件的因果关系。

有一种专门的存储方式是事件溯源,它不需要存储数据当前是什么,而是从历史事件中按顺序应用重建,得到当前的数据。这样写入时的成本只有校验后持久化,也没有增加和删除的能力。如果事件很多,性能问题很大,也可以加上缓存和快照,优化性能。这种方案通常会与CQRS方案一起做。

进度加速和项目管理工具

在这本小册子里,Evans提出了两个工具,分别用于加速设计阶段和评估工时。

事件风暴

事件风暴是快速的设计技术,让领域专家和开发人员都可以参与学习,目的是在有限的时间里尽可能多地完成设计,也就是加速设计阶段。

事件风暴要先做如下准备:

邀请领域专家和开发人员

每个成员都应该以开放的心态参与讨论,不必追求正确和速度。

各种颜色便利贴,正方形的。一般一个便利贴只会写几个词。

每个人都有黑色的马克笔。

最好有一面至少10米长的墙并且铺上白纸。最好建模的几天时间内保持每次讨论的结果一直保留并供下次讨论使用。

事件风暴的基本步骤:

在便利贴上写领域事件,梳理出业务流程,一般是橘色。

创建领域事件强调我们首要关注的是业务流程,而不是数据和结构

把每个领域事件写在一张便利贴上,应该是动词的过去式。

把写好的便利贴按照时间顺序放到建模平面上,从左往右逐步发生。

并行发生的领域可以上下排列,不明白时机的事件可以单放在某个单独的位置。

如果发现了问题点,可以用红色的便利贴上,并用一段文字解释是什么问题。

领域事件最终会触发一个执行的流程,每个流程都应该命名并记录在浅紫色的便利贴。需要从领域事件画个箭头指向这个流程。支队核心域中非常重要的细粒度事件进行建模。

创建导致领域事件发生的命令,命令应该是指令式的。

创建领域事件的便利贴是浅蓝色的。

触发事件的便利贴放在触发的事件左边,会有很多成对出现的命令和事件。但是也有不是命令触发的事件,比如时间触发的事件。

如果存在一个执行动作的特定角色,那么可以在命令左下角使用亮黄色的便利贴记录角色名称。

命令也可以触发流程。

在命令和事件之间画出线条

按照时间顺序,将命令和事件的关系处理好

一个命令可以带来多个事件

把命令和领域事件通过实体、聚合联系起来。由于建模没完,因此没有真正的实体和聚合,而是领域专家思想里的业务概念和概念群。用淡黄色的便利贴来表示聚合,其左下角是命令,右下角是事件。聚合的名字应该是名词。

在建模平面上画出边界和事件流动的箭头。

识别用户执行操作所需的各种视图,以及客户不同用户的关键角色。

4和5是事件风暴的关键。

时间评估工具

时间评估工具是如下的一个经验表格:

领域内的组件类型 简单 适中 复杂
领域事件 0.1 0.2 0.3
命令 0.1 0.2 0.3
聚合 1 2 3

作者Evans在原始表格里使用的单位是人时,然而根据我的经验,这个地方用人天还差不多……

这个表格的好处是系统里关于业务的部分都很明确了,虽然时间还是经验得出的,但是实际上已经相对精细了,而且在领域内的部分,估时会更准确一些, 而且它的复杂度与业务方的预估不会差太多。

常见的DDD误区:

DDD一定要用微服务?不,其实多个域在同一个进程也没问题,只要满足一个聚合在一个事务内保护就没有问题。

DDD的架构是稳定的?这么问的人一定没有理解什么叫做领域驱动。当领域发生演化的时候,系统的改变肯定不会小。比如电商系统里收货地址,可能一开始只是没有业务意义的值对象,但是后续有了管理,比如家庭,公司,然后反过来绘制画像,精准推荐……地址有了管理系统,那就不再是值对象了。

但是DDD能保证在每期迭代中,需要做的工作都是最贴合当前需求的,并且当下一迭代到来的时候,做的改造工作量也是各方可以理解的。与之相反的所谓提前规划,通常会演化为把之后若干迭代的部分放到当前迭代,而且当未来没有按照预定的方式改变时,这些工作可能还是无效的。







审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • API
    API
    +关注

    关注

    2

    文章

    1495

    浏览量

    61938
  • RPC
    RPC
    +关注

    关注

    0

    文章

    111

    浏览量

    11528
  • ddd
    ddd
    +关注

    关注

    0

    文章

    23

    浏览量

    2923

原文标题:走近DDD

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    ddd

    谁有java版的OA源码
    发表于 07-31 10:46

    真心求助 为什么我的程序生成时钟后会死机啊

    程序目的是血型配对指示器,匹配符合要求T灯亮不符合要求F灯亮entity ddd is Port ( a : inSTD_LOGIC_VECTOR (3 downto 0);b
    发表于 12-20 18:20

    谁能帮我解释下这个程序吧,,,,谢谢了,,这是一个六个舵机控制机器人走路的程序

    ,ddd,eee,fff;//angle1,angle2为电机PWM变化打角unsigned int a1,a2,a3,a4,a5;//angle1,angle2为电机PWM变化打角void delay
    发表于 10-21 22:27

    黑客攻防入门与进阶ddd

    黑客攻防入门与进阶ddd黑客攻防入门与进阶ddd
    发表于 02-23 15:45 9次下载

    DDD_RH137K_FAB地段10008104.1 W7修订版2

    DDD_RH137K_FAB地段10008104.1 W7修订版2
    发表于 05-24 16:18 0次下载
    <b class='flag-5'>DDD</b>_RH137K_FAB地段10008104.1 W7修订版2

    "Scalable, Distributed Systems Using Akka, Spring Boot, DDD, and Java--转"

    "Scalable, Distributed Systems Using Akka, Spring Boot, DDD, and Java--转"
    发表于 12-01 18:06 6次下载
    "Scalable, Distributed Systems Using Akka, Spring Boot, <b class='flag-5'>DDD</b>, and Java--转"

    工业机器人到底需要什么样的连接器?

    很多机械、机器人和自动化的应用场景中,节省空间的连接器解决方案都尤为重要,这正是浩亭推动高插针密度和小尺寸的Han DDD连接器的原因所在。与以前标准 Han DD相比,Han DDD的插针密度最高提高了130%,但并没有降低额定电压,依旧保持着相同的尺寸和电气特性。
    的头像 发表于 10-20 11:32 1048次阅读

    为什么需要Repository?什么才是好的Repository ?

    DDD 着重于将业务领域中的概念和对象映射到对象中,使对象模型能够更好地反映业务的真实情况,从而使设计更具可理解性和可维护性。
    的头像 发表于 03-07 09:11 861次阅读

    用好DDD必须先过Spring Data这关

    DDD 是一种领域驱动的设计方法,旨在通过建立对领域模型的清晰理解来解决业务问题。和事务脚本不同,DDD 使用面向对象设计来应对复杂的业务场景。
    的头像 发表于 03-07 09:38 2132次阅读

    一文理解DDD领域驱动设计

    2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity in the Heart of Software (领域驱动设计),简称Evans DDD
    的头像 发表于 05-25 14:21 948次阅读
    一文理解<b class='flag-5'>DDD</b>领域驱动设计

    DDD驱动如何设计?如何进行领域建模?

    DDD是Eric Evans在2003年出版的《领域驱动设计:软件核心复杂性应对之道》(Domain-Driven Design: Tackling Complexity in the Heart
    的头像 发表于 07-18 14:11 1130次阅读
    <b class='flag-5'>DDD</b>驱动如何设计?如何进行领域建模?

    谈谈后端架构的演进过程:N-Layered和DDD架构介绍

    在本文中,我们讨论了 N-layered、DDD、六边形、洋葱和清洁架构。这些只是众多存在的架构中的一部分,是一些比较出名的架构。你可能还听说过 BCE、DCI 等。
    发表于 08-16 10:08 624次阅读
    谈谈后端架构的演进过程:N-Layered和<b class='flag-5'>DDD</b>架构介绍

    DDD是什么?DDD核心概念梳理

    DDD 是什么,DDD 的英文全称是 Domain-Driven Design,翻译过来就是领域驱动设计。
    的头像 发表于 09-07 11:12 8693次阅读
    <b class='flag-5'>DDD</b>是什么?<b class='flag-5'>DDD</b>核心概念梳理

    DDD学习与感悟——向屎山冲锋

    软件系统是通过软件开发来解决某一个业务领域或问题单元而产生的一个交付物。而通过软件设计可以帮助我们开发出更加健壮的软件系统。因此,软件设计是从业务领域到软件开发之间的桥梁。而DDD是软件设计中的其中
    的头像 发表于 09-24 13:31 206次阅读
    <b class='flag-5'>DDD</b>学习与感悟——向屎山冲锋

    在DVEVM上通过ddd运行Demo

    电子发烧友网站提供《在DVEVM上通过ddd运行Demo.pdf》资料免费下载
    发表于 10-15 10:05 0次下载
    在DVEVM上通过<b class='flag-5'>ddd</b>运行Demo