本文根据柴华老师在〖deeplus直播第273期〗线上分享演讲内容整理而成。(文末有回放的方式,不要错过)
柴华
哈啰出行 交易中台团队技术负责人
2019年加入哈啰出行共享团队,期间完成了交易、保险、发票、评价等多个领域能力落地,且主导了哈啰出行核心业务线的接入。目前是哈啰出行交易中台团队技术负责人,致力于提升业务线交易域研发效率、降低交易域维护成本、提升交易和平台团队稳定性。
我们今天的主题《DDD在哈啰交易中台的实践》,最近几年中台微服务越来越火,DDD虽然作为一种契合中台微服务落地的设计基础,但它的成本极高,除了一些核心概念需要掌握外,对常用的设计思想、代码规范,都需要时间来熟悉和接受。通过这次分享,希望能完善和巩固大家对DDD的基本概念、设计流程和实践经验。
接下来从三个方面去介绍DDD。
一、DDD的基本概念和设计流程
1、DDD的概念
DDD的全称是领域驱动设计。
在百度百科里面领域的概念是:一种特定的范围或者区域。
而在业务场景下,领域是指业务边界,也是指指定范围内待解决的业务问题。在《领域驱动设计:软件核心复杂性应对之道》这本书里面,实际上对DDD的概念、基本流程做了比较明确的阐述。书中说DDD先对领域业务领域进行分析,建立领域模型,根据领域模型驱动代码设计,后面我会对DDD的设计流程去做详细的介绍。
2、使用DDD的原因和好处
第一,它是一套完整系统标准可落地的设计方法。
第二, DDD善于处理和领域相关的复杂度较高的业务产品,通过它可以建立一个核心而稳定的领域模型,有利于领域知识的传递,而这个传递不只是包括研发团队内部的传递,也包括整个领域链路的传递,包括全链路的产品、研发、各区各领域专家,同时也便于大家领域信息达成一致。
第三,他能强调团队和领域专家合作,能够帮你的团队建立一个比较良好的沟通氛围,构建统一的工作流程和节奏。
最重要的一点是,DDD是类似于微服务中台落地的指导思想,这也是DDD为什么这些年比较火的原因。
我们先来看一下DDD的基本概况。
在DDD里面提供了很多专用名词,像领域、子域、通用语言、限界上下文、领域服务、领域事件、实体、聚合等。
了解这些概念,不仅有助于我们了解DDD的基本思想,同时也更便于我们和其他团队的沟通。图中标识的实际上就是领域的父子或者层级关系,我们实际上通过这个图已经可以看出分治思想的体现了,而DDD实际上就是将大领域逐步的拆分细化的过程。
(1)领域、子域
下面我来介绍一下领域和子域,领域在业务场景下指的是业务边界,同时他也是指定范围内待解决的业务问题,而子域指的是更小、更细化的领域,而DDD通过分治的思想,通过不断的解决小领域,最终产生大领域的解决方案。
我们拿打车领域来举个例子,我们将打车领域细分成司乘域、交易域、结算域、评价域、与和用户增长域,而其中交易域又可以细分形成于形成域、匹配域、订单域和退款域,解决了此域并将此域的能力去做串联,打车领域的问题就自然而然的解决了。
下面我来介绍一下领域类型,在DDD中领域类型包括三种:核心域、通用域和支撑域。
核心域:就是公司和团队的核心竞争力。
通用域:指的是通用能力。
举个例子:比如说当前的公司有个交易团队,打车领域本身是有交易诉求的,那么在打车领域中,交易域可以作为通用域来提供交易的通用能力。
支撑域:指的就是非核心、非通用的领域。
需要强调的一点,即便是相同的领域,领域类型也不一定是相同的,这里需要区分产品形态,比如说我们从0~1去建立一个打车的产品,我们可能通过自建运力或者车主认证的方式去招募车主,这是一种产品形态,这种场景下可能交易域和结算域就属于核心领域。
那么第二种产品形态,可能是只做产品的聚合和决策,类似于现在的高德的业务。根据各种路由决策,决定具体这次行程是分配给哪一家运力公司来承接的。在这种产品形态下,它的匹配路由决策实际上是它的核心域。
(2)通用语言、限界上下文
下面我们来讲一下从通用语言和限界上下文。
通用语言比较好理解,就是通过团队的沟通达成共识,能够简单、清晰、明确地表述业务含义和规则的语言,可以列成一个领域的唯一件。
而限界上下文本身是一个领域,它需要在这个领域里去保证通用语言和领域对象没有二义性。
我针对二义性来举个例子,比如说新零售的场景下,C端的用户在现场去浏览商品,这是第一种场景;供应链流程里面涉及到商品的运输,这是第二种场景。
在这两种场景下,商品是否是属于相同的领域,如果不是,那商品这个词,其实在整个新零售的领域里面是存在二义性的,如果要解决这个问题,我们需要划分出两个上下文:交易上下文和供应链上下文。保证商品这个词在上下文中是没有唯一性的,而上下文实际上在DDD中是很重要的,它可以用来指导我们后面去做系统架构设计。
而限界上下文的一个基础原则有两点:第一点就是组织架构(不能跨领域架构);第二个就是要去除歧义(二义性)。
(3)实体、值对象、聚合
下面我们来讲一下实体值对象。
值对象其实是和实体是对标的,没有标识符或状态流转,承载多个相关领域、属性集合的一类对象。
实体、值对象实际上是领域模型的基础,类似于面向对象里面的类,而实体和值对象本身也是用类去做承载和表现。
聚合实际上是让实体和值对象协同工作的一个组织,是用来确定实体和值对象,在完成共同的业务领域过程中能保持数据的一致性。
举个例子来阐述一下:比如说我们在电商场景下,一个用户购买了多件商品,在这个场景下我们设计了主订单,然后我们是用主订单实体去承载买家信息,以及订单金额等属性,应用子订单去承载商品级别的信息。
在主订单实体中,买家信息实际上就可以作为一个值对象,因为这个值对象本身是不需要去做状态流转的,在这个场景里面也涉及到聚合,因为我们在创建订单的时候,本身是要将主订单实体和子订单实体一起创建,所以我们需要将主订单实体和子订单实体形成一个聚合,来提供一个创建清单的能力。
这里需要强调一点:指对象本身不是固定的。就拿刚才订单里面的买家信息来举例,买家信息在订单实体里面是作为一个值对象存在的,而在用户领域,用户其实是可以作为一个实体而存在的。
(4)领域事件
领域事件其实比较好理解的,就是当某个领域触发变更之后,通知其他领域的事件,而这个词虽然是在DDD中提出的,但实际上是跟一种架构思想(实践驱动设计)是一致的。
举个例子:比如说在交易场景下,订单支付成功之后,我们是需要增加用户积分的。在这种场景下,订单实体是需要发出订单支付成功的事件,用来通知用户的积分予以去做增长积分的一个行为。
我们再返回来看一下之前的图,在这个图里面领域和子域是N:1的,子域和限界上下文是N:1的,限界上下文和聚合是N:1的,聚合和实体、指对象也是N:1的。
相信通过这个图和前面的讲解,大家对DDD的基础概念有更清晰、更明确的认识。
在DDD里面会有两种设计:战略设计、战术设计。
战略设计指的是从业务视角里面,去划定领域边界和限界上下文;而战术设计是从技术的视角,去做实体、值对象、领域服务、领域事件等的设计。
3、DDD的设计流程
下面看一下DDD的设计流程。
在产品需求产出之后, DDD建议我们通过事件风暴的方式去做需求分析、领域梳理、确定限界上下文这三个步骤,这三个步骤实际上就是DDD设计的全部,而限界上下文确定之后,它可以用来指导我们系统架构设计,而领域梳理其实可以指导我们去做详细设计(包括数据模型的设计,接口设计等)。
事件风暴的参与者一般是希望当前领域所有的成员都可以去参加,包括研发、产品、测试以及领域专家,而在这里领域专家有可能是开发、测试、产品中的一员。
二、DDD在哈啰交易场景的实践
下面用三个实例去实现DDD的设计流程。
首先先来简单介绍一下哈啰的交易场景。哈啰的交易场景主要分成两大部分:出行场景、生活服务场景。
出行场景包括两轮出行、四轮出行、其他出行等,每一种方式会有其他形式的交易场景。
生活服务场景包括像本地生活(电商场景)、社区团购是(新零售场景),还要学车、酒店、租车、游戏等其他场景。
1、哈啰业务:打车场景
这里我们选取打车场景(电商场景)去做业务角度的第一个的实践。
(1)需求列表
首先我们先看一下需求列表,需求列表实际上是根据角色拆分为一系列的需求功能点,而公共点的序号表示一个用户在使用系统后的一个执行费,我们来串一下这些需求功能点。
在打车场景下乘客会去用户注册和登录,而如果想成为车主会去做车主认证,车主认证成功之后会做车辆的管理,平台则会定期去做营销投放,乘客会去抢券,当乘客有打车诉求,乘客会去发单,而平台根据当前的运力去做私生匹配,同时车主也可以主动接单。
当司乘匹配成功之后,他会去创建一个交易订单,同时会去针对订单去做投保。
同时会去将路径规划推送给车主,车主根据路径规划到达乘客的上车点,后面就是乘客上车,然后车主开车预约。
在这个过程中,如果涉及到危险,可以去做一键报警,而在整个流程中平台根据当前的交通状态计价,而车主也有权限去做改价(主要是高速费的场景)。到达下车点之后,乘客去支付。在订单完结之后,去做互相的评价,后面还会有一些其他的需求点,就不一一赘述了。
(2)需求分析
需求分析阶段主要产出的一些指标:包括实体、值对象、命令和事件。
但在做需求分析之前,我们希望将业务场景去做细化,细化的好处是便于我们更好的去找到实体和值对象。细化业务场景的方式是有多种的,比如说第一种就根据产品的PRD可以做细化。
第二去做角色的补全,就拿第一个乘客评价的业务场景来举例,乘客评价我们是——基于什么去做评价、为什么去做评价。细化后,实际就上是乘客是基于整个订单的交付过程、对司机的车辆整洁状态、对司机的服务态度去做评价。
这里呈现的实体和指对象比较明确,包括乘客、订单和评价记录,对应的命令包括新增评价记录,查询用户详情以及查询订单详情。
而事件在当前的业务场景下其实是没办法完全确定的。比如说在后面做评分计算的业务场景里面,我们发现评分计算实际上是依赖整个评价的业务场景,在这个阶段我们再去做事件的记录。
(3)领域梳理
在领域梳理这个阶段,我们要做4件事情,梳理实体和值对象、完善属性、能力和事件、构建依赖关系(实体和实体、实体和值对象等)、构建聚合。
我们拿乘客评价、更新评分的场景来举例。
首先我们去设计评价的实体,在评价实体里面包括:评价ID、评价类型,在具体的流程里,会去对车辆的整洁程度,以及对司机的服务态度去做评价,所以设计评价类型;而评价主体是指谁来评价,评价媒介是根据什么来做评价,以及评价时间,它可能还会有其他的属性在这里就不一一列举。
能力实际上就是在评价设计里面,新提供新增评价的能力,而事件我们刚才其实已经处理好了,后面的评分计算其实是要根据新增评价之间的消息推动的,所以我们可以先分离出来评价的实体。
而刚才讲到评价的实体的媒介是承担了实体,而评价的主体是用户实体,所以我在图中实际上关联了评价实体、清单实体和用户实体的关联关系。
完成评价之后,我们会去计算评分,在计算评分的功能上,我们实际上是需要根据评分计算策略实体、评价实体来计算评分。
所以我们针对于评分的计算,划分出了一个领域服务。在第三个阶段我们需要更新评分,因为我们需要同时的去变更评价主体、评价实体、评价历史记录实体,所以我们将评分和评分的历史记录作为一个聚合,共同完成更新评分的动作。
(4)确定上下文
而在确定上下文这个阶段,我们需要自底向上的由实体和聚合,去划分上下文,再由上下文去划分更上层次的领域。
有两个方法大家可以借鉴:第一种就是组合,第二种就是抽象。
这两个实际上都是面向对象的概念,可以拿下图来确定一下,我们在上下文的划分和领域的划分里面,是如何去做抽象和组合的。在这个阶段我们实际上是要根据实际情况而定,如果就拿评分域来举例(左下角):
组合:如果业务逻辑比较复杂,我们可以将评分划分成两个上下文,第一个是评价上下文,第二个是评分上下文,这两个上下文是存在依赖关系的,这两个上下文组合之后,实际上可以组成一个较完整的评价体系,所以我们通过组合的方式是可以去组合一个更上层领域,所以我们组合成了评价域。
同理还有中间的打车交易,打车交易里面会有5个上下文,分别是形成匹配、交易、营销、活动、支付,这5个上下文共同组成了从顾客发单到交易完成了流程,所以我们通过这5个上下文组成了打车交易域。
抽象:可以参考右下角的司乘安全域,司乘安全域本身里面会有告警上下文和风控上下文,因为告警上下文和风控上下文没有明确的归属关系或者依赖关系,所以我们将它去做了更层次的抽象,把它抽象成司乘安全域。
而在标准的DDD设计到这里就结束了,后面的系统设计、数据模型设计,以及其他的详细设计、编码等,本身是不属于地基设计规范的,但我会在最后的交易阶段会去介绍。
2、哈啰业务:电商场景
(1)需求列表
首先看需求列表,针对需求列表去串需求,因为我们本身做的是电商SAAS场景,所以肯定会有商家的线索跟进,消费者会注册、商家会入驻,在商家入驻之后,商家会去设置店铺的营业时间、上架商品、库存、营销活动等。
在这个过程中,如果有一些使用层面不知道的地方,它可以和平台去做商家答疑。
针对于消费者视角,消费者可以去进店、选品、加购,打开订单确认页,选券、填写收货地址、下单,而消费者本身也可以取消订单,商家端也可以取消订单。
当消费者支付成功之后,如果履约方式是核销,平台就需要生成核销码,而消费者可以做到店核销,商家核销完核销码之后,订单会是订单完成的状态;
而另一种履约方式是发货方式,商家可以构建这个商品去做发货,而消费者可以查看物流、确认收货,当所有的商品都收货之后,订单会去流转成订单完成状态。
(2)需求分析
下面看需求分析,我们只要拿商家发货场景举例。
首先我们根据PRD去细化业务场景,针对商家发货的业务场景,商家会先去进入到订单详情页,勾选要发货的订单的商品,选择物流公司、填写物流单号之后点击发货。
这里面实体和值对象包括商户、订单、子订单、履约单、履约子单、物流单和物流公司。
对应的命令包括查询订单信息、子订单信息;因为涉及到商家操作,所以要查询商户信息;因为我们需要勾选物流公司,所以我们需要查询物流公司列表,而典型发货的过程涉及到几个订单的创建:包括履约单、履约子单、物流单,真正的发货成功之后,会去更新订单信息和子订单信息。
而对应的事件,比如说后面的业务场景,会涉及到交易体系,会有商家发货的动作,会做APP内部的提醒或者短信的提醒,所以我们是需要订单开始履约之前消息的。
这里解释一下:为什么需要履约单这个模型?
因为一个订单里面的多个子订单可能会涉及到分批发货,所以这个订单会对应多个履约单,而针对于一个履约流程,我们会设计多段的物流配送,比如说第一阶段我们可能会去跨省配送,下一次让我们可以去做同城配送,做一个履约单会去对应多个物流单,就是履约单的一个场景。
(3)领域梳理
而回到这个领域梳理过程,在这个阶段我们需要查询订单和子订单信息,所以我们需要订单和子订单的聚合提供查询能力,我们需要物流公司实体去查询物流公司列表,我们点击发货的时候,我们去生成履约单,而履约单的多个商品是需要履约子单去承载的,所以生成履约单的时候,会去依赖履约单和履约子单的聚合,去完成创建履约单的业务功能,而物流单实体提供的是和物流公司的交互、进度、进度的变更以及通知能力,最后同时还依赖订单和子订单,更新订单状态以及子订单发货的能力,所以这里还是需要订单和子订单的聚合。
(4)确定上下文
我们在确定上下文这个阶段,我们一共拆分了11个领域,通过组合的方式去组装成了商户域,商户域是由商户上下文和店铺上下文组合而成的,同时还会有商品域、评价域、用户域、用户增长率和电商结算率等。
在这里需要提醒大家的是,如果我们已尝试组合或者抽象,但没有一个好的解决方案的时候,或者说我们没办法抽象和组合成为一个更高级别的领域的时候,我们可以考虑将上下文和领域按1:1去做设计,而上下文的划分本身也和当前的需求列表、实际情况去对应的。
当一个领域或者上下文业务复杂度较高、能力较多或者视角不同的时候,上下文的划分方式也是不一样的,如我们后面会讲的交易域的划分,及电商域的划分都是不一样的,但是我们划分方式就是一致的,都是通过组合和抽象的方式去做设计。
3、哈啰中台:交易
(1)交易的定义
交易是指双方以货币和商品作为媒介,根据约定,完成价值交换的过程。在这个过程中涉及到4个核心要素:第一个就是参与双方,第二个约定或合同,第三是媒介,第四是交易等价物。
我们来看一下打车场景里面,以及电商场景里面的一些交易核心要素。
(2)打车场景和电商场景的交易
打车场景里面:参与的双方是司机和乘客,约定是以订单作为约定;订单里面会去记录起止点、路线以及初估的订单金额;媒介是货币;而交易等价物实际上就是司机的驾车服务;我们将这个流程串联起来了,串联起来之后就是乘客通过货币购买司机的驾车服务,到达约定终点的过程。
电商场景里面:参与的双方包括买家和商家;约定是在订单里面,获取记录订单的金额以及发货方式;媒介还是货币,而交易的等价物是实物商品和虚拟商品。我们同样串联起来的结论就是,买家通过货币购买商家的实物和虚拟商品,通过发货和履约的方式完成价值交换的过程。
以上就是交易的概念。
(3)需求列表
需求列表我在这里就不串联了,因为我在这里面列举实际上是电商场景的交易能力,前面在讲解电商需求列表的时候,我已经串联过了。
(4)需求分析
下面我们来看一下需求分析,我拿创建订单作为一个业务场景来讲解,在创建订单里面实际上细化的业务场景包括两个阶段:第一个阶段包括拆单,而系统根据拆单策略去组成拆单结果;第二个阶段就是根据拆单结果,去校验商品的上下架信息、用户是否被风控、店铺的营业状态,再锁定库存之后,创建清单。
而在这个阶段,我们沉淀的实体和值对象,包括拆单策略、拆单结果、用户店铺、商品库存、订单和子订单,而对应的命令其实也是比较多的,有查询拆单策略列表、生成多个查单结果、查询店铺详情、查询用户详情、查询商品详情、占用库存、创建订单、创建子订单。
而针对事件,比如说创建错误30分钟之后会自动取消订单,这种方式主要是针对于超时未付款的场景,而这种场景实际上依赖于订单创建成功事件消息。
(5)领域梳理
下面我们来看一下领域的梳理阶段,我们在这个阶段分成两个步骤,我来先来介绍一下订单和子订单,订单里面实际上记录的包括订单的唯一ID、买家信息、卖家信息、订单状态、订单金额,提供的能力实际上包括创建订单、订单实体,以及我们刚才梳理好的领域事件消息,而子订单实际上记录是子订单的ID、订单的ID、商品信息、优惠信息、数量等。
而在整个领域过程梳理阶段,我们第一阶段是要根据领域拆单策略,可以计算出拆单的结果是子对象列表,所以在上图的最左边,我把它定义成了一个领域服务。
在第二阶段,它在创建订单的过程,实际上要依赖库存实体、店铺实体、商品实体,而在创建时因为同时要创建定订单实体和子订单实体,所以订单和子订单实体形成了一个聚合。
(6)确定上下文
接下来看一下上下文和领域划分,那么通过抽象的方式,将购物车上下文抽象成了交易售前域;而我们将订单的发货核销这个能力,抽象成了正向的履约上下文。
同时我们在这个阶段做了组合,我们将正向的履约上下文、逆向的履约上下文以及电子凭证上下文,共同组成了交易的售后域,而且我们将交易的售前、售中、售后共同组成的交易域,这个实际上就是我们确定上下文的一个过程。
(7)系统架构设计
下面来讲一下系统架构设计。
因为上下文设计其实是系统架构的一个决定因素,我们通过刚才的上下文设计中,我们可以看到我们的战略设计实际上只有一个订单上下文,我们在系统架构设计里面设计了两个微服务,第一个就是订单服务,第二个就是订单的查询服务。
在系统架构设计实际上不只是要考虑领域这个事情,还需要考虑多个维度,比如说领域的划分,实际上是DDD可以指导我们做的;同时还要考虑比如说组织架构,团队规模、服务的稳定性。
我们将定位中心服务拆分成两个微服务的一个考虑点是服务稳定性,因为下单会承载整个哈啰的交易流量,所以下单是属于S1服务,而订单查询是属于S2服务,它主要是用于C端的订单列表、订单详情,同时他会去和多个数据进行打交道,放在一起的时候,有可能就会出现当订单查询出现慢查询的场景,影响下单。
下面讲解:微服务落地时如何去做服务内的分层?
上图是DDD的4层架构,DDD的4层架构实际上建议领域层作为最低层,去依赖其他层来保障领域层的稳定性。
同时它也会有其他的架构,就是比方洋葱架构、六边形架构,在我视角里面看,他们的核心思想是一样的,综合性思想包括两个点,第一点是都包含领域层,第二点领域层会内聚业务能力,所以他们最终的目标实际上都是高内聚和低耦合,我前面说分层在行业内实际上没有办法达到一个一致的标准,不过在公司内部或者团队内部,从管理和约定的角度来说,实际上还是有必要的,否则可能会出现5个研发有5套规范的情况。
我的逻辑方案实际上就是DDD的4层架构。包括用户接口层主要包括API、DTP、Constants的定义;应用层主要是做领域的串联和帮辅;领域层是内驱领域能力的,分成实体、值对象、领域服务、领域事件、聚合,同时定义了仓储;而在基础设施层会对仓储做实现,包括RPC的交易,以及中间件的交易。
三、DDD的实践建议
1、DDD的核心
DDD的第一核心永远是设计,包括战略设计和战术设计,而不是说代码如何分层、如何实现等。我们目前也发现了团队中的一些系统的问题,比如说他们那个领域层可能是包装了实体的,没有聚合,也没有领域服务,应用层做的也很重,领域能力散落在领域层、应用层中。
我给他们的建议实际上是去真正的理解DDD,确定是否要使用DDD去做设计,同时要确认是否要使用系统架构去做代码落地,不然思想和实际代码落地实际上是不匹配的,而他们这种状态下使用4种架构实际上是突破工作量的。
2、DDD的弊端
DDD不是万能的。
第一,它有熟悉成本,它的基本概念、设计流程都是需要熟悉和掌握的;
第二,它有实现成本,思想和编码习惯的转化,以及分层的增加,都会带来工作量的增加;
第三,它的适用场景是有限的,它只适用于解决一些领域问题,以及业务复杂度较高的问题。如果说你当前的团队这三点实际上都不符合的话,我建议是不使用DDD。
下面我来讲一下DDD和面向对象,因为DDD和面向对象实际上是匹配的,可以说DDD是面向对象细化版的方法论,从我们前面的讲解可以知道,实体和值对象实际上是类的延伸,而上下文的划分方法是组合和抽象,组合抽象实际上也是面向对象的概念,所以可以说DDD是面向对象细化版的方法论。
这里给大家提一个思考题:我们在做对象设计的时候经常会用到UML,UML实际上包括类图、状态图、组件图等等。如果我们把UML和DDD结合起来,我们在做DDD的战略设计、战术设计的时候,应该插在面向对象的流程的哪个阶段?
3、DDD的设计流程
下面讲一下DDD的设计流程,很多人实际上都说我们先去做战略设计,然后再去做战术设计,因为战略设计会去划分上下文,而战术设计会偏向于技术的细节。
但实际上最开始拿到的需求,是有一堆需求列表的,如果我们通过需求列表直接产出上下文,这样划分的领域,以及上下文其实都是不够准确的。一般有领域经验的人会按这种流程设计,如果没有领域经验的前提下,这样去做上下文的划分是非常容易出错的。
就以《领域驱动设计:软件核心复杂性应对之道》这本书前两章的一个印刷电路板的案例来说,我当时在看这本书的时候,对这个领域实际上是我们没有概念,所以如果在这个阶段直接划分上下文是很危险的。
前面我们也讲了DDD的设计流程,针对这种场景下,我们可以做根据需求列表去做需求分析,去做领域梳理,在领域梳理这个阶段我们去梳理一个实体、值对象,以及他们的属性、命令和领域事件,实体和实体的依赖关系,实体和实体的聚合等。
然后在第三个阶段,我们通过实体和值对象去反推上下文和领域的划分,具体的方法就是组合和抽象,然后再进一步的去做详细的技术方案以及代码的落地。
4、DDD、微服务、中台和平台之间的关系
首先我先讲一下中台和平台,平台的概念是解决公共能力的复用问题,防止公司重复造轮子;中台的概念实际上就是将各个能力去串联成一个平台产品,为前端提供一个业务需求方案。“中台是企业级能力复用平台”这句话,我认为是比较中肯的。
拿交易平台来举例,交易平台提供售前、售中、售后能力,而业务线去串联我们各个域的能力,去完成他们的业务流程,这是交易平台要做的事情,而交易中台是依赖交易平台的基础能力,在两个方面其实做了改进:
第一点是在流程编排上,在流程编排上为前台提供一个从售前到售中到售后能力的一个串联,它是跨服务的。
第二点是接入的便利性维度上,提供了从前端到后端可配置、可扩展的一个便利的交易解决方案,这是我对交易中台的一个理解。
最后我们来看一下第一DDD、微服务、平台、中台的关联关系。首先平台和中台在业务架构上,实际上更多的是偏向于业务模型的,而形成平台和中台的过程,实际上也是业务领域不断细分的一个过程。
那么在这个阶段要将通用能力不断的去做聚合、建立领域模型,这个过程实际上和DDD的战略设计实际上是很匹配。
当平台和中台完成领域建模之后,我们就需要通过微服务去完成系统架构,而此时DDD的架构设计和微服务的设计是完美契合的,所以可以说平台、中台以及微服务是DDD的一个落地的最佳场景,这也是DDD最近比较火爆一个原因。
>>>>
Q&A
Q1:领域服务是否可以领域服务是否可以直接调用Repository层,这样的话领域服务不是更加内聚吗?
A1 :我拿这个图来举例,这个图里面所表述的领域层里面的领域服务,本身就可以调用存储层的接口,存储层本身是在基础设施层实现的,所以你的这个问题是可以的,领域服务是可以去直接调用存储层的。
Q2:间限界上下文的识别对业务的场景是否会有影响?
A2:首先在标准DDD的设计过程中,限界上下文对业务的场景是一定会有影响的,因为正常的限界上下文是用来去指导系统设计的,如果你系统架构设计本身会设计的不一致的话,对业务的场景是一定会有影响的。
Q3:识别实体和实体关系之后,划分上下文的依据是什么?
A3:
我可以先看一下这个图,我们在上一步已经去做了实体和聚合的分析和设计,所以我们是通过实体和聚合去往上拆分上下文的,也可以从上下文去往上去划分成更高层的领域。这个方法主要是两种,第一种就是组合,第二个就是抽象。
前面讲了一个确定上下文的例子,我们可以通过两种方式去做上下文的梳理,第一个是我们实体和实体之间是否存在依赖关系,如果他们存在依赖关系,且组合之后可以形成一个更高层次的领域,就可以通过组合的方式去形成。
而另一种比如说像告警和风控,它本身是没有太大的关联关系的,所以我们通过抽象去向上划分。
Q4:请教下,DDD适合做游戏开发的服务架构吗?感觉微服务化影响的RT,而且分布式事务也不好做。
A4:其实我在最后讲过这个问题, DDDD本身和微服务只是有指导关系。
DDD其实是可以指导微服务的落地的,但并不代表只有通过微服务才能做DDD的设计,它们是没有反向的推导关系的。
DDD的落地其实不一定是要通过微服务的方式去做落地,而且DDD本身是一个设计的概念,我们可以不用纠结DDD和代码的最终落地。你讲的影响RT、分布式事务,这些实际上都是微服务的问题。
获取本期PPT,请添加群秘微信号:dbachen
推荐一本DDD最新力作《解构领域驱动设计》
张逸,高质量编码实践者、领域驱动设计布道师、微服务系统架构师、大数据平台架构师、敏捷转型咨询师,曾就职于中兴通讯、惠普、思特沃克(ThoughtWorks)、民航(成都)信息等企业,致力于大型软件企业的分布式架构设计、领域驱动设计、大数据平台架构设计以及垂直领域的企业架构规划与建设,并为国内外多家企业提供技术培训与咨询服务。
本书全面阐释了领域驱动设计(domain-driven design,DDD)的知识体系,内容覆盖领域驱动设计的主要模式与主流方法,并在此基础上提出“领域驱动设计统一过程”(domain-driven design unified process,DDDUP),将整个软件构建过程划分为全局分析、架构映射和领域建模3个阶段。除给出诸多案例来阐释领域驱动设计统一过程中的方法与模式之外,本书还通过一个真实而完整的案例全面展现了如何进行领域驱动设计统一过程的实施和落地。为了更好地运用领域驱动设计统一过程,本书还开创性地引入了业务服务、菱形对称架构、领域驱动架构、服务驱动设计等方法与模式,总结了领域驱动设计能力评估模型与参考过程模型。本书提出的一整套方法体系已在多个项目中推广和落地。
本书适合希望领会软件架构本质、提高软件架构能力的软件架构师,希望提高领域建模能力、打磨软件设计能力的开发人员,希望掌握业务分析与建模方法的业务分析人员,希望学习领域驱动设计并将其运用到项目中的软件行业从业人员阅读参考。
↓点这里可回看本期直播