作者:焦方飞

大年初一,看完中国队 1:3 越南队的比赛,在考虑中国足球日薄西山的深层次原因之外,不由回想起这几年做过的一些大型企业数字化转型项目,有得有失,终究回归到根源“怎么规划和施行一个杂乱软件工程”这个问题上,趁着春节长假,把自己的一些对架构规划考虑和学习随笔写下来,写的匆促,期望能引起咱们一些启发和评论。当然本文所说的软件开发首要事务运用软件的开发,而中心件、数据库等技能组件开发的重视点则在其他一些方面,不在这儿打开。

怎么解决杂乱事务规划

软件架构规划本身便是一个杂乱的工作,但其实业界已有一个共同,那便是“经过组件化完结重视点的别离然后下降局部杂乱度”。其完结在咱们用的不管是容器、中心件、音讯、数据库等,在某种意义上都是组件化的产品。这样的优点是在不同的体系里可以复用。在云原生鼓起的今日,以通用的、组件化的服务办法更简略为咱们所用,所以说现在假如还不享用云原生技能盈利,那你就会被年代扔掉。

如何设计一个复杂的业务系统?从对领域设计、云原生、微服务、中台的理解开始

云原生满意非功用性质量需求

云原生在技能上可以最大程度的解决许多非功用性质量和技能需求(如上图),那作为一个企业级运用架构,天然会把专心点转移到事务运用功用性规划本身上来。现在来说关于一个杂乱事务架构进行规划,咱们要想做到又快又好,无非是两种状况:一是架构师本身对事务了解很深、才干超强、炉火纯青;二是原有的事务体系本身模型明晰,足够的“高内聚低耦合”,可以快速在其根底之上剖析事务改变构成新的事务架构规划。咱们应该追求的是第二种状况,这也就意味着从一开端的企业级模型建设,就要对模型规划、事务流程仔细对待,只有做到根底厚实,才干有后边的“快速迭代”。

咱们再回到架构规划的实质,即为什么咱们要在代码完结前做规划。规划首先是要解决问题的杂乱度。所以有人做了一个架构,交给了一个团队去完结,很快发现完结的架构和规划彻底是两回事。当然原因很明晰——缺少了交流和交流;其次是要树立团队协作交流的共同。即便咱们做好了一个团队都达到共同的架构规划,咱们都兢兢业业把规划变成了实践,一个长时间困扰软件职业的问题呈现了,需求总是在改变,不管预先规划怎么“精确”,总是发现下一个坑就在不远处,结果往往是状况越来越糟糕,也便是咱们常说的架构“堕落”了,最后咱们不得不承受重写。这些经历让咱们逐步明晰了软件架构规划的实质是经过中心问题的别离下降杂乱度,并让体系可以更快地响应外界事务的改变,并且使得体系可以持续演进。在遇到改变时不需求从头开端,确保完结本钱得到有用操控。

所以,我觉得从架构规划视点,以下三点是最为要害的:

  • 让咱们的模型、组件和事务区分尽量接近改变的实质,比方关于一般电商体系来说,便是用户、商品、买卖、支付等,这样的区分可以让咱们将改变“隔离”在必定的规模(事务模块)内,然后帮助咱们有用减少改变点。

  • 规划上,事务模型内部是高内聚,模型之间是低耦合,即各自完结的事务是相对独立的,不会由于一方掉线而牵连别的一方,比方商品引荐功用挂掉了,可是买卖和支付事务应该持续正常供给服务,或许提示用户暂时无法供给引荐服务,或许爽性降级为兜底策略。

  • 模型、组件在事务上尽或许是复用的,正是这样的复用才成就了今日的互联网级架构,咱们不会每做一个电商体系都从零做起。而被“复用”最多的事务模块显然会要点规划和运营,成为中心事务模块。当然架构上这样的电商体系必定也会比较强健。

上面的三点毫无疑问都指向了事务,从事务动身、面向事务改变是咱们现代架构规划成功的要害,所以说杂乱事务架构规划的中心实质是确保面对事务改变时咱们可以有足够快的响应才干。

范畴规划

前面说了事务软件开发的常见病:从一个小的项目不断开发演化变成一个大型事务体系,但随着新需求的不断添加,终究演化成了开发团队的噩梦。而这些噩梦大部分是源于软件的概念完好性(“概念完好性”一词来源于软件工程的经典著作《人月神话》)遭到了损坏。这些事务代码或许是一代又一代的开发人员各行其道的堆叠起来的(咱们又称之为“屎山”),而这个进程中没人有意识的去保护软件的概念完好性。而 DDD 范畴规划,特别是 DDD 供给的战略建模层面的概念,是保护软件概念完好性的良药。

“技能服务于事务、事务驱动技能”是现在大部分人的共同,尤其是对商业公司而言。而 DDD 范畴规划主张在软件规划中把事务范畴本身作为重视的焦点(换句话说便是软件开发人员要懂事务)十分契合这种思想;并且,DDD 供给了切实可行的面对杂乱事务软件规划的解决办法,这也是我十分提倡作为一个架构师去深化学习和评论 DDD 范畴规划的相关常识。

战略建模

在战略层面,DDD 十分强调对事务问题的剖析和分化,经过识别中心问题来下降问题的杂乱度。DDD 在战略层面保护模型的概念完好性的办法,最重要的两个概念便是鸿沟上下文(Bounded Context)和防腐层(Anti-Corruption Layer)。

  • 定义好鸿沟上下文

关于鸿沟上下文的定义,随便一本讲 DDD 的书上都会详细讲解,这儿我只想分享一下自己的一些了解。这时,有人会问:鸿沟上下文多大才干适宜呢,区分上下文有没有可以遵循的规矩呢?

区分上下文的规矩,无非便是放之四海而皆准的“高内聚、低耦合”,这么说或许还是太虚。其实真实让咱们感到纠结的是,不知怎么切分的那些东西之间所存在的相关,有的甚至爽性都归入到一个上下文里。其实,我以为与其重视上下文的“巨细”,不如重视模型的“质量”,重视概念的完好性是不是简略被损坏。我觉得,判断巨细是不是适宜,要结合运用开发团队的才干,看开发团队能在多大的一个规模内掌控软件的概念完好性。只需是开发团队没有问题,这个规模就算再大也都是可以的。

假如开发团队的水平在业界属于上游,那么保护上下文的规模往往是很大的;一些公司开发团队的水平参差不齐,所以在项意图施行进程中,或许需求区分相对小的上下文,尽或许减少“屎山”的不断堆积。

  • 做好防腐层

鸿沟上下文需求时间保护好自己所保护的鸿沟,以及鸿沟内概念的完好性,这时需求将某个上下文的概念转化为另一个上下文概念的地方就叫做“防腐层”。防腐层的完结有许多种,典型的比方作为适配器 Adaptor 来完结,别的广义上讲,Gateway 也是一个典型性的防腐层组件,当然,防腐层的代码和其他内部事务模型之间要存在显着的物理鸿沟(当然不必定说要把防腐层作为一个个独立布置的进程),至少咱们可以考虑把防腐层作为一个独立的类库来进行构建和保护,阿里内部的比方星环、其实便是这个思路。

如何设计一个复杂的业务系统?从对领域设计、云原生、微服务、中台的理解开始

一个典型的防腐层的规划

战术建模

DDD 在战术上最中心的概念便是实体和聚合,为了更好的了解什么是聚合、聚合根、聚合内部实体,下面举例阐明一下。想象一下一个电商体系的订单相关的模型,咱们或许会得到订单 Order、订单头 OrderHeader、订单行项 OrderItem 三个相互相关的概念:

  • 一个叫做 Order 的聚合。
  • 这个订单聚合的聚合根是一个叫做 OrderHeader 的实体,实体 OrderHeader 的 ID 叫做 OrderId(订单号)。
  • 经过 OrderHeader 实体,咱们可以访问 OrderItem 实体的一个聚合。OrderItem 这个实体的局部 ID 叫做 ProductId(产品 ID)。由于事务善变不允许在同一个订单的不同订单项内呈现同一个产品,所以咱们可以挑选产品 ID 作为订单项的局部 ID。

“聚合是数据修正的单元”,依据这个准则,咱们可以做到“聚合内强共同、聚合外终究共同”,比方,咱们可以不能承受一个订单内的一切订单项的金额之和不等于订单头的总金额,咱们就必须把订单头和订单行项这两个实体区分到同一个聚合内。

  • 规划聚合的准则

咱们不妨先看一下《完结范畴驱动规划》一书中对聚合规划准则的描述,原文是有点不太好了解的,我来稍微解释一下:

  1. 在共同性鸿沟内建模真实的不变条件。聚合用来封装真实的不变性,而不是简略地将目标组合在一同。聚合内有一套不变的事务规矩,各实体和值目标按照统一的事务规矩运转,完结目标数据的共同性,鸿沟之外的任何东西都与该聚合无关,这便是聚合能完结事务高内聚的原因。

  2. 尽量规划小的聚合。假如聚合规划得过大,聚合会由于包括过多的实体,导致实体之间的办理过于杂乱,高频操作时会呈现并发冲突或许数据库锁,终究导致体系可用性变差。而小聚合规划则可以下降由于事务过大导致聚合重构的或许性,让范畴模型更能适应事务的改变。

  3. 经过仅有标识引证其它聚合。聚合之间是经过相关外部聚合根 ID 的办法引证,而不是直接目标引证的办法。外部聚合的目标放在聚合鸿沟内办理,简略导致聚合的鸿沟不明晰,也会添加聚合之间的耦合度。

  4. 在鸿沟之外运用终究共同性。聚合内数据强共同性,而聚合之间数据终究共同性。在一次事务中,最多只能更改一个聚合的状况。假如一次事务操作涉及多个聚合状况的更改,应选用范畴工作的办法异步修正相关的聚合,完结聚合之间的解耦(相关内容我会在范畴工作部分详解)。

  5. 经过运用层完结跨聚合的服务调用。为完结微服务内聚合之间的解耦,以及未来以聚合为单位的微服务组合和拆分,应防止跨聚合的范畴服务调用和跨聚合的数据库表相关。

上面的这些准则是 DDD 的一些通用的规划准则,还是那句话:“适宜自己的才是最好的。”在体系规划进程时,你必定要考虑项意图具体状况,假如面对运用的便利性、高性能要求、技能才干缺失和大局事务办理等影响要素,这些准则也并不是不能打破的,总之全部以解决实践问题为动身点。

  • 规划聚合的进程

DDD 范畴建模通常选用相似工作风暴,一般经过用例剖析、场景剖析和用户旅程剖析等办法,经过头脑风暴列出一切或许的事务行为和工作,然后找出发生这些行为的范畴目标,并整理范畴目标之间的联系,找出聚合根,找出与聚合根事务严密相关的实体和值目标,再将聚合根、实体和值目标组合,构建聚合。

电商体系咱们都比较了解了,并且关于电商事务来说有许多比较老练的模型可以直接学习;那下面咱们以别的一个场景-稳妥投保事务为例,看一下聚合的构建进程首要都包括哪些进程,当然这个比如我是从其他的学习材料里看到的,比较典型,可以当作示例来进行阐明:

如何设计一个复杂的业务系统?从对领域设计、云原生、微服务、中台的理解开始

稳妥投保事务简略示例(From 学习材料)

  • 第一步:选用用例剖析或工作风暴等办法,依据事务行为,整理出在进程中发生这些行为的一切的实体和值目标,比方投保单、标的、客户、被保人等等。

  • 第二步:从许多实体中选出适宜作为目标办理者的根实体,也便是聚合根。判断一个实体是否是聚合根,上一章也说过,你可以结合以下场景剖析:是否有独立的生命周期?是否有大局仅有 ID?是否可以创立或修正其它目标?是否有专门的模块来管这个实体。图中的聚合根分别是投保单和客户实体。

  • 第三步:依据上一章说的规划聚合的准则,找出与聚合根相关的一切严密依靠的实体和值目标。构建出一个包括一个聚合根、多个实体和值目标的目标调集,这个调集便是聚合。在图中咱们构建了客户和投保这两个聚合。

  • 第四步:在聚合内依据聚合根、实体和值目标的依靠联系,画出目标的引证和依靠模型。这儿需求阐明一下:投保人和被保人的数据,是经过相关客户 ID 从客户聚合中获取的,在投保聚合里它们是投保单的值目标,这些值目标的数据是客户的冗余数据,即便未来客户聚合的数据发生了变更,也不会影响投保单的值目标数据。从图中咱们还可以看出实体之间的引证联系,比方在投保聚合里投保单聚合根引证了报价单实体,报价单实体则引证了报价规矩子实体。

  • 第五步:多个聚合依据事务语义和上下文一同区分到同一个限界上下文内。

那以上便是一个聚合诞生的完好进程了。

不同场景下的范畴建模策略

由于企业内状况千差万别,开展进程也不一样,有留传单体体系的微服务改造,也有全新未知范畴的事务建模和体系规划,还有留传体系局部优化的状况。不同场景下,范畴建模的策略也会有差异。下面咱们就分几类场景来看看怎么进行范畴建模。

新建体系

新建体系关于杂乱的事务范畴,范畴或许需求多级拆分后才干开端范畴建模。范畴拆分为子域,甚至子域还需求进一步拆分。比方:稳妥它需求拆分为承保、理赔、收付费和再保等子域,承保子域再拆分为投保、保单办理等子子域。杂乱范畴假如不做进一步细分,由于问题域太大,范畴建模的工程量会十分浩大。你不太简略经过工作风暴,完结一个很大的范畴建模,即便勉强完结,作用也不必定好。

关于杂乱范畴,咱们可以分三步来完结范畴建模和微服务规划。

  • 拆分子域树立范畴模型,依据事务范畴的特点,参考流程节点鸿沟或功用聚合模块等鸿沟要素。结合范畴专家和项目团队的评论,将范畴逐级分化为巨细适宜的子域,针对子域选用工作风暴,区分聚合和限界上下文,开始确定子域内的范畴模型。

  • 范畴模型微调整理范畴内一切子域的范畴模型,对各子域范畴模型进行微调。微调的进程要点考虑不同范畴模型中聚合的重组。同步考虑范畴模型和聚合的鸿沟,服务以及工作之间的依靠联系,确定终究的范畴模型。

  • 微服务的规划和拆分依据范畴模型和微服务拆分准则,完结微服务的拆分和规划。

单体留传体系

假如咱们面对的是一个单体留传体系,只需求将部分功用独立为微服务,而其余仍为单体,整体坚持不变,比方将面对性能瓶颈的模块拆分为微服务。咱们只需求将这一特定功用,了解为一个简略子范畴,参考简略范畴建模的办法就可以了。在微服务规划中,咱们还要考虑新老体系之间服务和事务的兼容,必要时可引进防腐层。

云原生年代下的挑战

随着云原生技能的鼓起,现在企业级架构就愈加的云化,而云化的架构风格有了新的重视点:弹性鸿沟。弹性鸿沟是一个云原生企业级运用架构的中心概念,它指把弹性作为最优先的考虑要素而划定的体系鸿沟,决议了咱们是否可以充分发挥云原生平台的全部才干。所以咱们就需求新的办法来弥补曾经事务模型的不足,以满意新的云原生化的需求。现在可以说,微服务基本上便是以云原生架构作为根底,而在固定弹性的平台上运用微服务架构,有极高的施行本钱。可以说,云原生实践上就应该是微服务的前置条件。

在云原生年代,咱们需求将弹性作为首要考虑的要素,归入建模的考量。那么弹性鸿沟,便是咱们区分体系的重要依据。并且,咱们还需求考虑弹性鸿沟间的依靠联系,尽量防止弹性耦合。关于事务建模来说,为了配合云原生年代的架构,我觉得要做到如下几点:

  • 建立一种模型结构可以反映弹性鸿沟,而这时分需求考虑不同弹性鸿沟的准则来区分鸿沟上下文;假如两个上下文显着具有不同的弹性诉求,那就应该拆分。而假如具有共同的弹性诉求,可以考虑先不拆。那这个时分拆分微服务究竟能多“微”呢?简略说便是“微”到可以更好的使用弹性来操控本钱的巨细。

  • 从异步模型的视角,去优化事务逻辑;典型便是 MQ 音讯行列体系,由于有 broker,所以生产者和顾客不用在同一时间都坚持可用性以及相同的吞吐量,并且生产者也不需求立刻比及回复。

  • 方位的松耦合:典型便是服务注册中心,消费端彻底不需求直接知道供给端的具体方位,而都经过注册中心来查找服务来访问。

  • 在弹性鸿沟切分事务上下文时,同一个弹性鸿沟内部保护事务强共同性。

  • 在异步调用发生中心态反常时,需求保护事务终究共同性。

不要忽视安排结构的影响

“康威定律”告诉咱们,安排结构会决议团队交流的结构,也会决议产品的结构。对安排结构的整理,在需求调研的时分会常常做。假如是信息收集而言,事务架构规划在这儿并没有什么特殊之处。差异在于,事务架构的目标是企业级的才干规划,期望可以打破壁垒、构成合力。正是这个原因,安排结构对事务架构规划的反作用力也是很大的,企业级数字化转型计划要与安排结构相匹配,不然落地的时分会困难重重。可以说,部门利益是做企业级架构的最大妨碍之一,跨过这个妨碍也是对架构师的才干的要求之一。当然,有些状况下,没有更好的解决计划时,不动也是一种挑选。

以我的经历,这种问题没有特别好的办法,无非是两种:一是有超强才干者主导,在最高层的支持下,强力推动这种决议计划,可是企业越大,尤其是以事务为主导地位的企业中,这种结构就愈难构成;二是加强企业内部的事务架构人员的才干和数量(最好各个部门都有相似的角色),让这些企业安排人员以合作伙伴的办法全程参与到项目中,在项意图施行进程中搭建起协作网络,提高决议计划功率,才干使安排结构不再是企业数字化转型的瓶颈。

SOA-微服务-中台:退让的艺术

多年前,这些传统的大型 ERP 事务软件,其实都是在一个很大的规模内保护事务概念的完好性。一个 ERP 安装结束后,数据库有七八百张表(也便是七八百个实体)处于同一个鸿沟上下文之内。可是这些 ERP 在这样一个巨大的鸿沟上下文内依然很好的保护了事务概念的完好性,真实令人敬佩。

然而完结它十分困难,可是损坏它却十分简略。一套 ERP 定制项目施行下来,数据库里或许又多了几百张表,更不用说不标准的命名看起来千奇百怪。这些厂商的 ERP 施行参谋和开发人员,废寝忘食的保护这个庞大的“屎山”。咱们不能让这些庞大的“单体运用”无限制的增加,所以咱们又一次祭起了“分而治之”的大旗。想 SOA 这样的软件组件化技能给咱们供给了拆分的东西。咱们把一个大的鸿沟上下文按照利于拆分红几个相对来说小一些的鸿沟上下文;在物理上,咱们把一个大的单体运用拆分红若干服务。

一般来说,咱们会让服务的物理鸿沟和鸿沟上下文的范畴鸿沟基本堆砌,一个鸿沟上下文对一个或多个可以独立布置的服务运用,服务运用包括了鸿沟上下文的中心事务逻辑的完结。SOA 的服务组件的物理鸿沟给服务间的调用添加了一些困难,这就使得开发人员简化目标之间的联系,编写愈加“高内聚、低耦合”的代码。当服务组件不多的时分,构建防腐层的工作量也不会很大,咱们只需处理好组件之间的代码即成就好了。

可是,咱们的架构师和开发人员太喜爱“分而治之”了,微服务的广泛运用甚至说是滥用,让咱们看许多微服务真的是很“微”,几乎是一个 DDD 的聚合就可以对应一个可以独立布置的微服务。这样的微服务单单靠本身做不了太多的事务,这就需求更多更多的微服务“聚合”起来一同才干对外供给事务服务。

当然,微服务技能根底设施的开展也为服务之间的调用供给了更多的便利,跨过微服务的鸿沟成为了常态;这个时分,事务开发人员区分“同一个上下文内的服务调用”和“上下文之间的防腐层”就要时间坚持头脑清醒,这时分的鸿沟上下文和微服务的物理鸿沟往往很难对齐,这就必定添加了保护每个鸿沟上下文概念完好性的难度。

既然保护一个个“微小”的独立的鸿沟上下文概念完好性越来愈难,那么咱们爽性将它们再聚合起来吧?将它们融合到一个巨细适度的鸿沟上下文,那这便是所谓的企业级事务架构,也便是咱们现在说的事务中台,终究意图可以说想要取得“企业级”的大和谐。

所以在必定程度上讲,软件工程便是退让的艺术,是“不偏不倚”。咱们要不要中台,要大的中台,不管企业的巨细,都应该结合本身的事务目标以及具有的资源,在“保护更大规模的概念完好性”和“保护更多的防腐层代码”之间做出平衡,那这也是一个企业级架构师所要做的最中心的工作之一。

咱们团队这些年确实做了一些“事务中台办法论”的积累和实践,并且在一些项目中做了实践,当然其中最魂灵的部分之一还是前面说的范畴规划。曾经许多人说 DDD 范畴规划乃至事务中台办法论最难的便是没有一个适宜的东西或许平台来实践,今日其实阿里开源的 COLA 以及内部运用的星环、BizWorks 都是很好的东西和平台。

结语

企业级运用架构是在不断的演进和迭代,可是我始终感觉企业运用架构的构成进程是在一种看起来科学的办法论下,可是又不彻底科学的进程中完结的。仔细想一下,做软件架构的其实很羡慕做修建架构的,由于修建架构有谨慎的力学根底作为基座,有许多可以精确计算的东西,而软件架构却没有多少可以精确计算出来的成分,所以,前面说的“不断的退让”不失是一种可行的规划思路和规划艺术;其实这也应验了那句“没有银弹”。

由于时间匆促,有些内容简略带过,有些本应该结合实例来阐明的地方在本文中也简略而过,后边有时间的话我会结合更多的实践案例来对本文说的观念进行补充。也期望本文可以激发咱们一同对现在云原生年代的企业级运用架构规划的考虑和评论,相互学习,共同进步。

发布云原生技能最新资讯、汇集云原生技能最全内容,定时举行云原生活动、直播,阿里产品及用户最佳实践发布。与你并肩探索云原生技能点滴,分享你需求的云原生内容。

重视【阿里巴巴云原生】公众号,获取更多云原生实时资讯!