P8 课程 - 领域驱动模型设计与微服务架构落地

P8 课程 - 领域驱动模型设计与微服务架构落地

引语:在我多年的职业生涯中,我发现就算是互联网公司,大部分部门也是由业务驱动,业务决定了我们的技术选型以及代码边界。也就是说我们并不是一定需要对于所谓的架构标准进行墨守成规。并且市面上大多数项目并不能直接体现出架构专业度以及架构特性。不过领域驱动设计又是我们互联网大厂必问的这样一个问题。所以我希望能够将领域驱动设计结合业务场景进行解析。这里补充说明一句,DDD(领域驱动设计)实际上是一套软件架构设计的方法论,我们可以在此之上更好的理解业务。并且我们可以根据这套方法论进行架构风格填充,包括微服务架构,面向服务架构,REST风格架构以及六边形架构等等。并且我们还能够将上述的架构风格进行结合使用。架构风格本质上就是一组架构约束。也就是说他其实就是规则

  • 领域驱动本身不涉及任何的技术栈,很多同学很喜欢聊微服务,那是因为微服务本身就有实现以及落地,但是领域驱动这么多年以来,其实并没有一个实现以及落地。
  • 其实来领域驱动设计DDD的各位同学,其实你们也应该发现了,当你们浅浅的去看领域驱动设计的时候,你会感觉领域驱动设计好像非常契合我们的业务场景,并且感觉非常的规范,但是我不得不说这是你们的错觉。每一个程序员刚接触到DDD的时候都是这个感觉。
  • 建议学习这门课程的同学最好拥有2年以上开发经验,并且对于业务非常熟练。你的业务经验越丰富,实际上你的理解越深入
  • 领域驱动设计并没有一个完整的规范或者说约束,现今市面上你所看到的所有资料都是基于(Eric Evans)埃里克·埃文斯的《领域驱动设计-软件核心复杂性应对之道》这本书进行衍生,本课程是我对于领域驱动设计的理解。所以不要拿这里的概念与市面上一些概念进行对比。

1.领域驱动模型不得不说的秘密

1.1 业务决定技术边界,业务边界定义领域模型

1.1.1 什么是领域驱动设计
什么是领域驱动设计

实际上领域驱动设计的英文是Domain-Driven Design[dɪˈzaɪn].

为什么会出现一个这样的概念呢?这是由于软件其实对于行业并没有什么非常高的要求,因为软件本身就是为了能够帮助某一些业务进行更好的发展。软件本身其实是赋能以及变革。软件具有行业兼容性,同时又带来固有的复杂性。

比如医疗行业跟金融行业,都能够去使用软件进行业务开发,但是他们的业务完全不一样,这个时候我们就需要进行大量的业务梳理,甚至需要专门的岗位(产品经理)去完成这个工作。而完成这项工作之后,我们才会进行软件的设计层面,在软件设计的时候,由于信息层层传递,就有可能会导致信息的失真以及遗失,从而导致产品预期以及产品落地会产生较大的差异性。

img

大家应该都有过这样的经历,比如我们去开发一个项目,由于需求的不断变动,导致你不得不去改动你原本的代码来保证功能的完备性。

但是这样导致了代码复杂度的增加,以至于这种项目最终都将面临重构。

举例

比如一个电商项目,我们可能需要跟产品经理预先进行沟通,比如,我们预先定好了,整个项目最终可能需要承受1W的并发量,但是运行一段时间后,公司的效益很好,可能能够到达了10万并发,在你没有考虑线性扩容方案的情况下,这个时候你该怎么拓展,是不是可能你们整个项目都需要进行大的改动,甚至重构。

为了解决这个问题,领域模型的概念就被提了出来。其实,对于领域模型大家也不陌生,甚至可能你正在使用这种方式,只不过你没有意识到,比如早期的领域模型其实就是数据库设计。

比如,我们早期的设计方式是直接建表,然后针对表去进行对象的建立,但是在我们的开发过程中,我们会发现很多问题,比如表字段建立不合理,有些字段少了,或者说有些字段冗余了,然后再不断的进行调整,最后再上线。

建表 – > 根据表来建立对象

大家看到这个方式之后,就会发现问题所在。

首先,这个模型的业务逻辑非常重,可能会导致故障级联。而且这样的业务会越来越复杂,最终导致耦合度变高。

所以,我们认为,依赖数据库去进行领域模型的建立可能有点问题,或者说不满足越来越快的开发节奏

因为,原本我们是瀑布式开发,我们使用数据库进行领域建模是没有问题的。因为我们的需求已经确定了,在这个版本完成之前我不会去考虑其他的需求。

但是由于互联网进入了快节奏,敏捷开发实际上成为了我们的常态。而敏捷开发实际上带来的问题就是,我的需求实际上是在不断的变的,同时,你整个生命周期其实都处于一个实验的阶段。并且你在不断的发布新的版本。这样带来的问题就是,昨天定好的东西,可能今天就会发生改变。

所以为了更加契合敏捷开发。我们就在考虑一件事。能不能不使用数据库做为领域模型的建立依据。因为数据库字段的不断增加与修改,是基于物理表结构的。物理表结构只要有改动,就避免不了耦合的产生。

那么这个时候我们能不能用更加抽象的东西做为我们领域建模的依据呢??

而就在外界还在讨论这个问题的时候,其实我们的软件设计流程已经发生了巨大的改变。

我们需要去预先定义咱们的业务边界,也就是说,咱们的项目,比如数据库,承载数据的上线是多少,比如有10TB数据,我们应该如何设计数据库才能够满足我们的要求,是否需要分库分表,单表过大要进行分表,磁盘负载过大要进行分库。是否要做主备,我们预先需要准备多少机器,设计是否能够支持线性扩容。我们现在需要采购多少机器等等,预算是否充足等等。

缓存,消息引擎,各个模块也要进行相关的设计,这就是我们的架构设计应该做的事情。架构师本质上就是文档与图形的载体。

所以我们定义了这样的一个流程以及阶段。

项目开发流程图

在这里插入图片描述

大家可以看一下这张图,我们会将我们软件上线之前的流程划分成为8个阶段,而每一个阶段都会对应的文档给到对应的人员。

产品经理

很多的同学其实认为领域驱动设计很虚,觉得我看不到东西或者说对于领域驱动的概念非常模糊,这是因为你不清楚领域驱动的本质,**领域驱动的本质是模型,并且是业务模型。**他一定是基于你对于业务非常熟练的情况下,才能够定义出合理的模型。

1.2 让领域驱动设计占据你的大脑

市面上有非常多跟大家聊DDD概念的书籍以及课程,并且也会附上相应的场景,但实际上并没有对于领域驱动进行落地。因为一般这种讲解都是基于某一个小的场景,而这类小的场景实际上并不能够将DDD进行淋漓尽致的体现。

比如我们的软件开发流程的第一个阶段,范围定义,它实际上是属于领域驱动落地设计中概念设计的部分。

整个概念设计会包含第一第二第三,三个阶段,而每个阶段我们都应该有相应落地的概念关联图,概念类文档,领域类图以及填充完毕属性的概念类。这个阶段是高级开发人员(架构师)与产品方以及运营方进行共同设计。

而中级开发人员应该能够看到这些图,并且能够根据这些图来设计业务逻辑,建立业务模型,抽取可复用的业务逻辑。所以,如果你的项目真的运用了领域驱动设计思想,那么在这个阶段,你也应该能够看到业务建模相关的文档资料。

包括业务用例视图,用例规约,业务规则,对象模型,以及业务用例场景等。

这个阶段应该是中级开发人员(技术专家,技术经理)以及产品方还有架构师以及项目模块核心开发人员共同完成。

最后,进入物理设计阶段后,就是所有开发人员进行共同设计,不过这个阶段才是最重要的阶段,可能前期的逻辑设计会有漏洞,我们需要弥补漏洞,甚至有的时候我们为了性能可能会推翻模型。在这个阶段,我们会完成数据存储问题,索引,视图,分区等一系列问题。并且会对异常进行统一处理。还会使用不同的架构风格进行填充,比如使用到了REST架构风格,那么在这个阶段我们便会将模型落地为REST风格的API,如果使用的是微服务架构,我们就会进行微服务构件设计。我们可以使用多种风格进行糅合,具体使用各种架构风格是根据逻辑设计阶段系统特定所定。

其实大家听我讲完了之后,是不是发现,我们的领域驱动设计并非想象中全是概念。

那么我们很多同学的项目为什么并没有用上领域驱动设计呢?

因为我们的领域驱动设计有几个要求

首先,对于项目中架构师的技术要求非常高。并且,架构师不仅仅应该对于各个组件,框架了如指掌。更需要对于业务有非常强的掌控力。
其次,整个项目中,各个角色都应该非常专业,有相当的专业度。

比如:技术专家不懂领域驱动,不能够协助架构师完成逻辑设计阶段。那么项目进度就会停滞。

不过,对于非核心开发并没有过多的限制,反而,底层开发难度会降低。因为全部都定义好了,只需要CRUD就行了。

最后,如果项目没有到达一定的体量,那么做这样的设计反而会拉长整个开发周期。因为很明显,如果完整的按照需求进行设计,前期的概念设计阶段以及逻辑设计阶段必然需要大量的时间。很多的公司尤其是创业型公司并没有这么多所谓的时间来进行所谓的标准化生产。

很多公司宁可先花费少量的时间出一个产品,后期再进行迭代。

所以,大家会发现,自己所在的公司好像根本就没用提到过领域驱动的概念。但是去大厂面试又会发现,这是必备的基础功底。因为大厂的很多项目从一开始就会进行这样的考虑。

这正是由于场景不一样,所导致出来的技术差异性。所以,很多的同学能够很明显的感受到,大公司与小公司之间技术的迥异。
而我们的课程会将各种各样的软件设计之道与领域驱动设计相结合,根据你自己的项目情况,总结出一套适合你自己的可供实践的理论指导。并且我们可以根据这套理论建立一套属于你自己的复杂业务场景设计方案。

1.3领域驱动与微服务

2004年,我们的埃里克·埃文斯(Eric Evans)发表了《领域驱动设计-软件核心复杂性应对之道》这本书,并且确定了领域驱动设计的核心思想:即通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性。

但是,提出来这个概念之后,DDD一直处于概念火,但是并没有落地方案的阶段。直到微服务的出现。

微服务自2015年开始,一下子在软件开发领域成为了当红辣子鸡,包括他还能够解决在集群架构下的很多问题,比如拓展性,比如弹性伸缩,比如小规模团队的敏捷开发等等。不过随之而来的,微服务架构的问题也暴露了出来,比如微服务的微,到底应该拆多小呢?不同的人会根据自己的理解而拆出不同的微服务,并且每个人都会觉得自己说的还很有道理。

实际上在我们微服务落地的过程中,我们也遇到过很多项目在进行服务拆分的时候会有这样的困惑,很多的项目甚至是沿用的SOA架构的服务拆分思想,进行专业领域划分,比如订单,商品,这样进行划分。而这样的划分实际上会导致哪怕用上了微服务架构以及技术,实际上原本的面向服务跟微服务差异性也体现不出来。

还有一些项目拆分的粒度可能太细,导致整体项目被拆分成上百个小的服务,但是运维部署的难度呈几何倍数增加,最终在上线前流产。

那么是不是有什么理论或者架构方法论能够帮助我们进行微服务架构设计呢?

其实这就是最近两年领域驱动突然火起来的原因,我们能够通过领域驱动设计,去定义我们的领域模型,划分领域边界,然后再根据我们的领域边界从业务角度去进行微服务边界定义。并且很多人尝试使用这种这种方式之后发现,好像这样划分出来的微服务,不管是业务边界还是技术边界都很合理,还能完美的契合咱们的微服务核心思想。“高内聚,低耦合”的思想,所以,很多的人又开始重新的学习咱们的DDD,并且还将DDD做为微服务设计的指导思想。觉得这两个东西很搭。

现在,很多的一线互联网公司已经将领域驱动设计做为微服务设计的指导思想了。所以现在大厂面试也会经常问到这样的点。但并不是说我们的DDD就不适用于我们的单体架构设计了,单体架构依然可以选择DDD做为我们架构设计的指导思想,而微服务,仅仅只是跟我们的DDD恰好搭配。什么意思呢?

打个比方,你有一个手机充电线,Type - C 接口一直以来这跟充电线都是充你的华为手机的。这个时候,突然,有个人招你借数据线,借完之后发现你的数据线刚好合适,他的手机也是华为,并且是最新款,很火。所以连带着你这根数据线也火起来了,但是你能说他不能给老款华为充电吗?也可以的吧。 等以后最新的手机出来之后,说不定其他数据线也火了呢?所以,技术永远要成为我们手上的工具。不然说不定什么时候就更新换代了。

那么DDD怎么帮助我们确定业务边界以及技术边界呢?

  • 围绕着业务边界,我们可以从业务角度进行出发,建立业务领域模型,合理的划分业务边界,建立泛语言的限界上下文,而这里的限界,就可以帮助我们做为微服务设计的业务边界。这个叫战略设计。
  • 而我们的技术边界,则可以从技术角度进行出发,并且我们在这个阶段会围绕着战略设计所定义的领域模型进行技术实现,并完成软件的开发以及落地,包括聚合根,实体,值对象,领域服务,应用服务以及资源库等代码逻辑进行设计。

1.4 战略设计

1.4.1 领域

首先,既然我们的DDD是领域驱动设计。那么领域必然是我们的重中之重,那么什么是领域呢?

**一个领域本质上可以理解为就是一个问题域,只要是同一个领域,那问题域就相同。所以,只要我们确定了系统所属的领域,那这个系统的核心业务,即要解决的关键问题、问题的范围边界就基本确定了。**通常我们说,要成为一个领域的专家,必须要在这个领域深入研究很多年才行。因为只有你研究了很多年,你才会遇到非常多的该领域的问题,同时你解决这个领域中的问题的经验也非常丰富。

同时大家从字面上的意思也能够知道,领域其实就是我们的范围,而范围实际上就是我们的边界,我们做什么,做到什么程度,最低多少 ,最高多少。而范围定义下来之后,我们根据这个范围去计划我们要做的事情。这不就是领域驱动设计吗??

比如你现在要去做一个电商网站,那么你的进货,优惠规则,物流仓储,销售报表,这些直接跟你的业务相关的东西都归属于领域,而所谓的领域驱动设计就是你**需要预先把领域中所涉及到的数据,流程以及业务规则搞清楚,然后再通过面向对象的方式为他去建立一个模型,这个模型就叫做领域模型。**我们再去选择合适的技术去对他进行实现。

1.4.2 子域

那么这个时候可能有同学会问,老师,按照你的说法,我们好像只需要建立一个大的领域模型,而建立完成这个大的领域模型之后,我如果说有一些小的功能点希望进行修改,这个时候我应该怎么操作呢?因为本身我们的DDD就是用来处理高度复杂的领域的设计思想,你都高度复杂了,我还用一个东西把你装起来。说要用一个领域将你全部装起来,是不是有点不合理啊。

那么我们的DDD是怎么做的呢?我们的DDD使用了一种非常简单的方式,大事化小,既然你整个领域太过于复杂,业务太过于分散,那么这个时候我们做一个拆分如何,你的电商系统很复杂,那么我单独将他拆分成比如一个个的模块,订单,商品,库存是不是会好处理一些呢?甚至我们的模块还能进行细分,比如库存,可以分为本地库,异地库,三方托管库。当然,这里只是类比,因为我们还在学概念的阶段。这里希望大家能够去理解这个概念。这一个个的模块,实际上在我们的领域驱动设计中还有好听的名字,叫做子域。

**那么这个时候,我们可以一个个的去研究我们的子域,当我们所有的子域搞定了之后,是不是我们整个领域也就搞定了。**当然是这样,因为原本我们的子域集合,就是我们的领域嘛。聊到这里,大家是不是觉得有点像微服务了,当然,本质上我们的微服务架构与领域驱动模型没有任何的关系。一个是思想,一个是架构风格。但是他们的目的都是一致的,都是希望能够将复杂的事情简单化。

那么随着我们划分子域,我们发现我们的子域的划分我们已经慢慢的掌握了,但是我发现不同的子域重要性以及功能属性完全不一样。所以我们又会将子域分为核心域、通用域和支撑域

为什么要将这些子域进行单独的定义呢?

实际上是因为我们的公司在建设项目的时候,会有非常多的限制,比如预算,比如人员,但是这些资源我如果平均分配在每一个子域,就有可能会导致其中一些子域关注度不够。比如你们公司的核心业务。可能就会因为得不到足够的资源,导致项目失败。

所以,我们对应不同的子域应该采取不同的态度。

其实很多的同学会觉得,相同行业的领域模型是可以复制的,但是我告诉大家,这是错误的。

比如淘宝跟京东。一个是C2C,一个是B2C。那么,显而易见的,C2C更加注重于服务,当然,这是对于买卖双方的服务。所以,你们会发现,淘宝所有的一切,都是为了保证卖家能够好好的卖出去货,买家能够把货收到。那么这样一单完成,钱到手。所以,我们还会对于商品进行展示,甚至直播展示,所以会有淘直播。所以这种模式核心在交易保证。

而B2C呢,其实卖的是口碑,如果说C2C你需要直接保证交易,而B2C实际上会更加关注产品的质量,为什么这么说呢?因为我们的B2C实际上如果你产品质量不好,那么我就会直接找到你的B方,也就是商家端。所以他的生命线实际上是质量。包括同学们聊起京东,肯定第一反应是质量。这已经做为了产品属性标签。

可能有同学会说,淘宝就不用做质量了吗?或者说京东就不做交易保证吗?所以这就是我们的兼顾,我们的业务力量需要放在刀刃上,并不是说其他的地方我们不会兼顾。

这个时候可能有些同学会有一些问题,老师,京东跟苏宁是不是同一种商业模式啊,我去进行设计的时候能不能进行同类分析啊。

包括我们去进行子域划分的时候是不是可以Copy。

这里我告诉大家,肯定是不行的。苏宁实际上强调的是线下选货,线上卖货,他们的核心在于线下。是由典型的线下往线上走,这种方式其实看重的是线下的服务,包括他们核心的源头在于你线下要有足够的流量。你才能慢慢打通线上。

所以,其实大家会发现,**我们的商业模式的不同,我们的侧重点不一样。**所以我们去进行软件设计的时候方式也会不一样。如果是中小公司的架构,跟不懂技术的老板应该聊的是这些东西,而不是具体的技术栈。

核心域
那么什么是核心域呢?实际上他就是当前领域的最核心的竞争力,也就是业务核心,

**核心域是整个业务系统的核心,所有的业务都要围绕着核心业务域展开。**如何明确核心域呢?

比如我们的淘宝,按照淘宝的模式,那么在交易保证的情况下,交易双方的属性必定就是我们的核心,比如返利,比如商户系统。

而京东则不一样,在京东自营模块而言,他们更加注重质量,这里的产品质量保证实际上不仅仅是产品本身,产品运输过程中也会导致质量问题。包括采购系统,包括仓储,物流,供应链才是他们的核心。

通常明确核心的方式是精炼业务域。精炼是一个持续的过程,具体来说有以下几种方式:

  • 领域愿景说明(Domain Vision Statement)

比如某里,实际上他们的愿景,让天下没有难做的生意。就充分说明了他们的愿景。

其实这里有同学可能会不理解,说白了,就是你们项目最初立项的目的是什么,目标是什么。为什么要做这个项目。

很多同学会认为,我们立项的目的是赚钱。可是我用什么手段赚钱呢?比如客户交易手续费,或者说信息差,或者流量费用,打广告。

  • 突出核心(Highlighted Core)

    我们通过“领域愿景说明”可以明确什么是核心域,但这是从一个较为宽泛的角度对核心域进行说明的。我们明确核心域的目的是为了形成核心领域模型,此时我们需要突出核心。

    突出核心域中的领域模型有两种方式:

    • 精炼文档
    • 标明核心(Core)

问题:

1、文档可能得不到维护.
2、文档可能没人阅读.
3、由于有多个信息来源,文档可能达不到简化复杂性的目的.
不过最起码你有文档,才能够让需要接手项目的人能够去找到参考物

  • 内聚机制(Cohesive Mechanism)

这个是什么意思呢?其实当你的项目越来越大的时候,你的修改可能会越来越多,这个时候你的代码可能会在原本的代码上增加很多,那么就有可能导致你原本的代码

  • 分离的核心(Segregated Core)
    • 将核心域中的非核心元素(模型)分离出去。
    • 将非核心域中的核心元素(模块)移动到核心域中。

非核心的动作其实你可以稍微的关注度放低,比如物流,其实不属于交易保证范围之内,那么他就可以做为我们的支撑子域。

  • 抽象核心(Abstract Core)

当不同模块的子领域之间有大量交互时,要么需要在模块之间创建很多引用(在很大程度上抵消了划分模块的价值),要么就必须间接的实现这些交互,而后者会使模型变得晦涩难懂.

因此,把模型中最基本的概念识别出来,并分离到不同的类,抽象类或接口中.设计这个抽象模型,使之能够表达出重要组件之间的大部分交互.把这个完整的抽象模型放到它自己的模块中,而专用的详细的实现类则留在由子领域定义的模块中.

核心域的范围并不一定是一次就能确认的,可能需要迭代很多次,每一次都有可能扩大或缩小。

通用域
接下来就是我们的通用域,通用域这个概念其实也很好理解,整个领域都能够用到的子域,比如我们的认证,权限等等相关的模块,这就是我们的通用域,你不需要定制化,只要能够去解决问题就OK了。

支撑域
什么是支撑域呢?

支撑域实际上就是不包含核心竞争力的功能,也不包含通用的功能,但是又是必须的支撑。比如限时拼团功能,没有他电商网站能够正常运行吗,可以,但是为了配合活动,他能够辅助我们成单。但是在某些专门的拼团电商中他又是必须的核心。所以我们必须根据当前的情况来进行分析。

总结:

你会发现,**领域驱动的核心思想就是将问题慢慢细化,同时找出最核心的问题点,倾斜资源保证核心资源不出问题,同时也可以通过领域的细分,去慢慢的缩小我们的子域所要解决的问题,并且构建合适的领域模型,**到这

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东心十

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值