优存科技获数千万元B轮融资,由亿达资本领投
06-18
几年后,随着云原生、微服务、大中型平台等一系列技术术语的诞生,一个熟悉的术语“域驱动”也开始被推上了神坛。笔者第一次听说域驱动是在参加一个技术分享会的时候。
我当时的直观感觉是,好像在说什么,又好像什么也没说。很多概念非常“形而上”,飘在空中,无法落地。
。十年过去了,中间平台已经过时,微服务回归单一实体一度成为技术圈的热门话题。
曾经笼罩在神坛上云雾缭绕的DDD,在今天还有讨论的意义吗?在过去一两年的实践中,笔者对DDD有了更深的理解。本文将阐述我的一些观点。
如果还有不明白的地方,希望同学们共同讨论。 01.领域驱动的概念。
领域驱动的概念是由大师Eric Evans在发布其名著《Domain Driven Design:Tackling the Complexity in the Heart of Software》时首次提出的。从标题我们可以直观地知道DDD是为了解决软件系统的复杂性问题,是一种降低软件系统复杂性的方法。
对于业务系统复杂性的方法论,很多同学认为领域驱动程序很难理解,因为它提出了很多抽象概念。我们不妨先抛开这些概念,了解一下它解决问题的方式。
1.1 统一语言和模型 对于一个开发来说,我们的工作就是一句话:用代码来实现需求。在实施过程中,不同的人、不同的团队可以有不同的做法。
域驱动就是其中一种实现方式。小路。
领域驱动尝试在需求和代码之间建立一座桥梁。桥的名称是统一的语言和模型。
什么是统一语言?软件开发的核心难点在于处理隐藏在业务知识中的复杂性。如果想要应对这种复杂性,首先需要打破业务和技术之间的沟通障碍。
在一个项目中,不仅有开发人员,还有测试人员。 、运维、产品、PM等。
能把事情做好的前提是能把事情讲清楚。我们知道,中华文化博大精深,一句话在不同的环境、场合有完全不同的含义。
统一语言的想法是促进团队内部的持续沟通,确保业务领域中的术语或概念具有独特且清晰的语义。那么什么是模型呢?我总结为:一种将复杂简单化的抽象。
抽象的目的是把问题简单化,先忽略细节,从顶层思考问题。抽象并不关心形式的表达,而是取决于如何看待问题、分析问题的视角。
让我们举个例子: 举几个例子: 把一头大象放进冰箱需要几步?总共三步,打开冰箱->把大象放进去->关上冰箱。虽然这是一个玩笑,但我不得不说这是一个很好的面向过程的抽象。
程序=数据结构+算法。这已经成为计算机科学中最基本的原理,即任何程序都可以分解为算法+数据结构。
虽然程序要解决的问题还没有确定,但是思考问题已经有了方向。类图、流程图、架构图……对于一个相对复杂的系统,我们很难用几句话解释清楚。
这时,绘画就成了一种很好的表达方式,绘画是一种抽象。根据您想要的抽象角度,使用不同类型的图表。
比如,如果有人让你讲一个购物网站是做什么的,你可以把问题简化一下,用下图来描述用户、商家、平台之间的关系。这正是面向对象建模的思想,领域驱动本质上也是一种面向对象的建模方式。
引入统一语言和模型抽象的思想后,从需求到实现的流程可以用下图来表示。技术和业务相关的学生通过统一的语言沟通和交流需求,通过模型抽象描述需求,最后根据模型实现。
相应的代码,领域驱动的一大目标是:修改需求就意味着修改统一语言,修改统一语言就意味着修改模型,修改模型就意味着修改代码,这也实现了从需求到代码的有效信息传递。 1.2 分而治之:我们再来谈谈归并排序 这里为什么要讲归并算法,因为域驱动所倡导的解决问题的思维方式和归并排序算法是一模一样的,可以概括为一一句话:自上而下的分裂,自下而上的合并。
我们简单回顾一下归并排序的思想:明确主函数的功能、输入、输出;分解问题并确定分解后的子函数的函数、输入和输出;合并子函数的返回值。伪代码如下: 代码语言:javascript copy //主函数 void mergeSort(std::vector
问题的定义:当我们面对复杂的场景时,首先需要确定我们面临的是什么问题?问题的边界(有界上下文)在哪里,我们很容易理解解决问题带来的价值,但很容易忽略定义问题带来的价值。在项目实践中,不知道大家是否遇到过这样的场景:技术同学根据产品同学的描述,会立即陷入技术实现,等到验收过程才说:“哦,原来如此”你只要实现这个需求就行了”感叹,这说明核心问题还没有找到。
分解问题:定义问题就明确了问题的边界,我们可以在边界内划分问题。领域驱动的核心思想是分而治之,即以“清晰的边界”分割子问题,然后解决子问题。
。这里分解问题的思路也和分解微服务的思路类似(说到微服务,这里提出了两个有趣的问题。
第一:领域驱动是2003年提出的一个概念,为什么会出现这么久了?大概15年才逐渐被大家知道;第二:微服务和领域驱动之间的关系相信看完这篇文章你心里就有了答案)合并结果:仅仅解决子问题是不够的。如何将信息组合起来 串起来是困难的部分。
穿线过程中会出现耦合问题。这又让我们回到了软件实践中的一个常见问题:如何实现“高内聚、低耦合”。
其实细心的朋友已经发现,这里分解问题的目标对应的是高内聚,而合并结果的目标则是低耦合。 02.那些晦涩难懂的术语。
上一节我们阐述了领域驱动要解决的问题:降低系统复杂度,以及其解决问题的思路:统一语言、模型抽象、分而治之。明确了这两点之后,我们再来看看一些抽象的概念。
相信你会有更深刻的理解。 2.1 在边界内做事:领域和子领域 从概念上讲,领域是指从事专门活动或职业的范围。
这里的关键是范围这个词,也就是边界。无论我们解决什么问题,问题总是有边界的。
边界越清晰,解决问题的思路就越清晰。简单来说,领域就是一个边界内要解决的问题。
对于一个复杂的问题,利用分而治之的思想,可以将其进一步划分为子问题。这种研究问题的想法其实是老生常谈了。
如果我们要研究人体,那么人就是问题的研究对象。我们可以根据不同的方法将问题分解为子问题。
下面是两种不同的想法。左图是根据“系统”来划分的,右图是根据“构图”来划分的。
如何分解,没有所谓的标准答案。不同的分解方式其实可以说从抽象的角度来看是不同的。
由于抽象视角不同,研究方法也会不同。例如,中医研究人体,注重整体与部分的关系,而西医则注重定量分析。
我们不能说它是好还是坏。我们只是从不同的角度看问题,这是抽象的。
当分解过程完成后,我们正在为子问题寻找相应的解决思路。这个过程就是从问题域到解决方案域的过程。
下图可以帮助你更直观的理解。 2.2 域按照功能进一步划分:核心域、通用域、支撑域。
在不断划分的过程中,子域还可以根据功能的不同再次划分为:核心域、通用域和支撑域。这里需要强调的是,子域的划分完全是基于对业务的理解,基于业务,而不是技术。
核心领域是指竞争领域。不同的人对竞争力有不同的理解。
例如,我们以人为例。身体、认知、财富哪一个是人的核心?说到竞争力,认为身体为核心的人会注重运动、健身;认为认知为核心的人,会注重阅读和学习;认为财富重要的人会关注事业……总的来说,你不能说谁对谁错,只是看待问题的方式不同而已。
对于企业来说也是如此。我们看到很多企业的业务和产品表面上很相似,但实际上却有完全不同的商业模式。
以电商平台为例。他们的一些核心领域是物流服务和高端品质;一些核心区域的商品更便宜、更容易使用。
对于企业来说,定义核心区域实际上决定了资源投入的方向,用好钢材在刀刃上提供差异化??价值。服务。
复用性高的通用领域或者没有太多个性化需求的领域。例如,所谓“中台??”概念,是指集成所有底层能力、快速迭代前端功能的高度可重用的模块化服务。
支撑域 支撑域是支撑核心域但不是业务核心竞争力的部分。这部分业务规则比较简单,通常不需要深入了解业务需求。
只需要满足基本的业务需求即可。 2.3 实体和值对象 什么是实体?业务中存在具有独特身份的对象。
例如,在电子商务场景中,项目对象可以是实体。该项目具有唯一标识符(项目 ID)。
项目的业务绩效可能会发生变化,但标识符在整个业务周期中保持一致。例如,一个商品在购买前是商品,但购买后就变成了需要发货的商品。
如果需要退款,则成为需要召回的商品,但该商品的标识符不会改变。什么是价值对象?对于实体对象来说,仅有唯一标识符是不够的。
仅仅描述对象的特征是不够的,所以还有属性。例如,产品的属性一般包括名称、价格、图片、生产地点等,而价值对象则是企业实体属性的集合。
在实践中,业务实体通常对应于一个实体类,该实体类具有唯一的标识符、属性及其所有业务方法。领域驱动提倡使用拥塞模型,即在类中实现所有相关的业务方法,而不是仅仅将数据直接暴露给外部。
这样可以很好的保证业务数据的一致性和封装特性。以下是项目对象的类实现。
代码语言:javascript copy // Entity // Item 类 public class Product { private String ProductId; // 唯一主键唯一标识符 private String ProductName;私有字符串productUrl;私有字符串产品价格;私有地址productAddress; // 属性集合 // 获取设置业务行为... public function () {}} // 值对象 // 仓库地址类(无主键id) public class ProductAddress { private String Province;私人弦城;私人弦乐区; } 2.4 聚合和聚合根 当我们需要完成一项业务功能时,往往不是一个人完成的,而是大家共同努力完成目标。在领域驱动中,实体就像我们每个人,聚合是一个允许我们一起工作的组织。
聚合根他是这个组织的领导者,所以聚合实际上是业务逻辑密切相关的实体和值对象的集合。每个聚合都有唯一的聚合根和业务边界。
聚合通常按照单一业务责任和高内聚性的原则进行设计。以确定需要包含哪些业务实体和价值对象。
我们以购物车场景为例来理解聚合和聚合根的含义。在购物车中,添加到购物车的商品列表形成一个聚合。
购物车id是聚合根。通过购物车id,外界可以访问购买的商品。
列出信息、状态、订单总金额等。如果我们想用代码来实现这个简单的场景,我们自然会想到在微服务中实现购物车的相关逻辑。
事实上,在领域驱动的实践中,往往通过一个微服务来实现一组相关的业务聚合。 。
初步了解了域驱动的相关概念后,我们来梳理一下它们之间的关系,如图。03.拆分与合并。
在上一节中,我们解释了领域驱动中的一些重要概念。本节我们将介绍分治和合并思想在领域驱动中的实现。
接下来我们将分别讨论这两个过程。 。
3.1 拆分和微服务架构我们回到归并排序的案例,思考一下我们平时写的代码和归并排序有什么相似之处。我们简单对归并排序代码进行一些修改,如下: 代码语言:javascript copy void mergeSort(std::vector
这不就是微服务的分层架构吗?领域驱动的最终实现形式是微服务。至此,我们就可以回答上面提出的问题了。
为什么领域驱动的概念在2002年就被提出,却在15年后才为人所知?这是因为云原生和微服务。架构的发展发生在15年左右,这为领域驱动概念的生存提供了土壤;相反,领域驱动也为微服务的设计提供了必要的方法论。
熟悉微服务架构的同学一定知道:微服务架构设计的难点之一就是服务的拆分强度。如果拆分太多,运维难度会成倍增加。
如果拆分太少,就会回到单体架构模型,这是不够的。灵活性,中层需要一个方法论来指导,这个方法论可以是领域驱动的。
对比领域分析模型和微服务架构,你会发现它们其实是一一对应的,只不过一个是从业务角度描述问题,一个是从技术实现角度描述问题,而这也是两者的结合。理论与实践。
。 3.2 合并最佳实践:在描述业务的过程中,领域事件往往有这样的描述:当某个事件发生时,会触发后续事件或者进一步的用户行为操作。
在领域驱动程序中,这种具有明显因果逻辑的事件被称为领域事件。在领域事件中,你会发现不同的事件往往属于不同的领域服务。
例如,用户购买商品并成功支付后,就会触发发货流程。这里的支付和发货属于不同的域,逻辑上是相关的。
顺序。对于上述事件,领域驱动提倡领域事件的数据通信方式采用事件发布和订阅的方式进行,而不是直接同步调用。
事件发布的本质是一种低耦合的异步数据通信方式。同步调用需要考虑两个问题:分布式事务和时间消耗。
对于事务问题,一般需要引入第三方组件或者在业务层处理各种超时失败等异常场景。可以说相当复杂,维护成本也很高。
在分布式系统中,时间消耗问题会被放大。一个请求可能跨越十几个甚至几十个服务。
高并发场景下,超时风险会增加,上游接口可能会被拖死。这些都是同步调用需要考虑的问题。
在领域事件的场景中,有一个更好的技术选择,那就是使用事件发布订阅的方式,或者以用户购买商品并支付送货的场景为例,看一下实现过程:用户支付后并下单,支付域创建事件,持久化事件状态,支付成功后发布事件,支付行为结束。配送域订阅支付事件。
收到用户支付成功事件后,触发用户购买的商品发货,并持久化事件状态,然后结束。用户收到发货成功的通知,正在等待收货。
领域事件的本质是通过分析用户旅程,找到领域之间的因果逻辑链,然后利用事件发布和订阅机制实现流程解耦。那么我们如何找到领域事件呢?最佳实践是在领域专家的领导下与项目相关的学生进行头脑风暴,将与业务相关的所有事件关联起来。
然而,这里的困难不是如何发散,而是如何将发散后的事件聚合起来。融合的本质是对事件的有效分类,这需要能够理解业务本质的人才。
所以这就是为什么域驱动程序中有一个角色称为域专家。我也用图表来表示这个过程。
04.总结一下,以上是我对领域驱动的一些简单看法。如果你看完之后还是觉得领域驱动有点形而上,也没关系。
只要记住,无论是技术还是生活,遇到事情时多沟通,先分解复杂的问题。
版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
标签:
相关文章
06-18
06-18
06-17
06-18
06-18
06-18
06-18
最新文章
【玩转GPU】ControlNet初学者生存指南
【实战】获取小程序中用户的城市信息(附源码)
包雪雪简单介绍Vue.js:开学
Go进阶:使用Gin框架简单实现服务端渲染
线程池介绍及实际案例分享
JMeter 注释 18 - JMeter 常用配置组件介绍
基于Sentry的大数据权限解决方案
【云+社区年度征文集】GPE监控介绍及使用