This commit is contained in:
louzefeng
2024-07-09 18:38:56 +00:00
parent 8bafaef34d
commit bf99793fd0
6071 changed files with 1017944 additions and 0 deletions

View File

@@ -0,0 +1,146 @@
<audio id="audio" title="06 | 领域事件:解耦微服务的关键" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/c8/03/c875221a1ec671cee3417b26e8b0e903.mp3"></audio>
你好我是欧创新。今天我们来聊一聊“领域事件Domain Event”。
在事件风暴Event Storming我们发现除了命令和操作等业务行为以外还有一种非常重要的事件这种事件发生后通常会导致进一步的业务操作在DDD中这种事件被称为领域事件。
这只是最简单的定义,并不能让我们真正理解它。那到底什么是领域事件?领域事件的技术实现机制是怎样的?这一讲,我们就重点解决这两个大的问题。
## 领域事件
领域事件是领域模型中非常重要的一部分,用来表示领域中发生的事件。一个领域事件将导致进一步的业务操作,在实现业务解耦的同时,还有助于形成完整的业务闭环。
举例来说的话,领域事件可以是业务流程的一个步骤,比如投保业务缴费完成后,触发投保单转保单的动作;也可能是定时批处理过程中发生的事件,比如批处理生成季缴保费通知单,触发发送缴费邮件通知操作;或者一个事件发生后触发的后续动作,比如密码连续输错三次,触发锁定账户的动作。
**那如何识别领域事件呢?**
很简单,和刚才讲的定义是强关联的。在做用户旅程或者场景分析时,我们要捕捉业务、需求人员或领域专家口中的关键词:“如果发生……,则……”“当做完……的时候,请通知……”“发生……时,则……”等。在这些场景中,如果发生某种事件后,会触发进一步的操作,那么这个事件很可能就是领域事件。
那领域事件为什么要用最终一致性而不是传统SOA的直接调用的方式呢
我们一起回顾一下 [[第05讲]](https://time.geekbang.org/column/article/154547) 讲到的聚合的一个设计原则:在边界之外使用最终一致性。一次事务最多只能更改一个聚合的状态。如果一次业务操作涉及多个聚合状态的更改,应采用领域事件的最终一致性。
领域事件驱动设计可以切断领域模型之间的强依赖关系,事件发布完成后,发布方不必关心后续订阅方事件处理是否成功,这样可以实现领域模型的解耦,维护领域模型的独立性和数据的一致性。在领域模型映射到微服务系统架构时,领域事件可以解耦微服务,微服务之间的数据不必要求强一致性,而是基于事件的最终一致性。
回到具体的业务场景,我们发现有的领域事件发生在微服务内的聚合之间,有的则发生在微服务之间,还有两者皆有的场景,一般来说跨微服务的领域事件处理居多。在微服务设计时不同领域事件的处理方式会不一样。
### 1. 微服务内的领域事件
当领域事件发生在微服务内的聚合之间,领域事件发生后完成事件实体构建和事件数据持久化,发布方聚合将事件发布到事件总线,订阅方接收事件数据完成后续业务操作。
微服务内大部分事件的集成都发生在同一个进程内进程自身可以很好地控制事务因此不一定需要引入消息中间件。但一个事件如果同时更新多个聚合按照DDD“一次事务只更新一个聚合”的原则你就要考虑是否引入事件总线。但微服务内的事件总线可能会增加开发的复杂度因此你需要结合应用复杂度和收益进行综合考虑。
微服务内应用服务,可以通过跨聚合的服务编排和组合,以服务调用的方式完成跨聚合的访问,这种方式通常应用于实时性和数据一致性要求高的场景。这个过程会用到分布式事务,以保证发布方和订阅方的数据同时更新成功。
### 2. 微服务之间的领域事件
跨微服务的领域事件会在不同的限界上下文或领域模型之间实现业务协作,其主要目的是实现微服务解耦,减轻微服务之间实时服务访问的压力。
领域事件发生在微服务之间的场景比较多,事件处理的机制也更加复杂。跨微服务的事件可以推动业务流程或者数据在不同的子域或微服务间直接流转。
跨微服务的事件机制要总体考虑事件构建、发布和订阅、事件数据持久化、消息中间件,甚至事件数据持久化时还可能需要考虑引入分布式事务机制等。
微服务之间的访问也可以采用应用服务直接调用的方式,实现数据和服务的实时访问,弊端就是跨微服务的数据同时变更需要引入分布式事务,以确保数据的一致性。分布式事务机制会影响系统性能,增加微服务之间的耦合,所以我们还是要尽量避免使用分布式事务。
## 领域事件相关案例
我来给你介绍一个保险承保业务过程中有关领域事件的案例。
一个保单的生成,经历了很多子域、业务状态变更和跨微服务业务数据的传递。这个过程会产生很多的领域事件,这些领域事件促成了保险业务数据、对象在不同的微服务和子域之间的流转和角色转换。
在下面这张图中,我列出了几个关键流程,用来说明如何用领域事件驱动设计来驱动承保业务流程。
<img src="https://static001.geekbang.org/resource/image/23/93/23e38df6e78c0a10ddf27f8a254c0093.jpg" alt="">
**事件起点:客户购买保险-业务人员完成保单录入-生成投保单-启动缴费动作。**
1.投保微服务生成缴费通知单,发布第一个事件:缴费通知单已生成,将缴费通知单数据发布到消息中间件。收款微服务订阅缴费通知单事件,完成缴费操作。缴费通知单已生成,领域事件结束。
2.收款微服务缴费完成后,发布第二个领域事件:缴费已完成,将缴费数据发布到消息中间件。原来的订阅方收款微服务这时则变成了发布方。原来的事件发布方投保微服务转换为订阅方。投保微服务在收到缴费信息并确认缴费完成后,完成投保单转成保单的操作。缴费已完成,领域事件结束。
3.投保微服务在投保单转保单完成后,发布第三个领域事件:保单已生成,将保单数据发布到消息中间件。保单微服务接收到保单数据后,完成保单数据保存操作。保单已生成,领域事件结束。
4.保单微服务完成保单数据保存后,后面还会发生一系列的领域事件,以并发的方式将保单数据通过消息中间件发送到佣金、收付费和再保等微服务,一直到财务,完后保单后续所有业务流程。这里就不详细说了。
总之,通过领域事件驱动的异步化机制,可以推动业务流程和数据在各个不同微服务之间的流转,实现微服务的解耦,减轻微服务之间服务调用的压力,提升用户体验。
## 领域事件总体架构
领域事件的执行需要一系列的组件和技术来支撑。我们来看一下这个领域事件总体技术架构图,领域事件处理包括:事件构建和发布、事件数据持久化、事件总线、消息中间件、事件接收和处理等。下面我们逐一讲一下。
<img src="https://static001.geekbang.org/resource/image/b2/8f/b221ed4011c23720ebe9f48ba8eee38f.jpg" alt="">
### 1. 事件构建和发布
事件基本属性至少包括:事件唯一标识、发生时间、事件类型和事件源,其中事件唯一标识应该是全局唯一的,以便事件能够无歧义地在多个限界上下文中传递。事件基本属性主要记录事件自身以及事件发生背景的数据。
另外事件中还有一项更重要,那就是业务属性,用于记录事件发生那一刻的业务数据,这些数据会随事件传输到订阅方,以开展下一步的业务操作。
事件基本属性和业务属性一起构成事件实体,事件实体依赖聚合根。领域事件发生后,事件中的业务数据不再修改,因此业务数据可以以序列化值对象的形式保存,这种存储格式在消息中间件中也比较容易解析和获取。
为了保证事件结构的统一,我们还会创建事件基类 DomainEvent参考下图子类可以扩充属性和方法。由于事件没有太多的业务行为实现方法一般比较简单。
<img src="https://static001.geekbang.org/resource/image/33/ec/3331c2d87d4dc0e68ec99fc9e02b44ec.jpg" alt="">
事件发布之前需要先构建事件实体并持久化。事件发布的方式有很多种,你可以通过应用服务或者领域服务发布到事件总线或者消息中间件,也可以从事件表中利用定时程序或数据库日志捕获技术获取增量事件数据,发布到消息中间件。
### 2. 事件数据持久化
事件数据持久化可用于系统之间的数据对账,或者实现发布方和订阅方事件数据的审计。当遇到消息中间件、订阅方系统宕机或者网络中断,在问题解决后仍可继续后续业务流转,保证数据的一致性。
事件数据持久化有两种方案,在实施过程中你可以根据自己的业务场景进行选择。
- 持久化到本地业务数据库的事件表中,利用本地事务保证业务和事件数据的一致性。
- 持久化到共享的事件数据库中。这里需要注意的是:业务数据库和事件数据库不在一个数据库中,它们的数据持久化操作会跨数据库,因此需要分布式事务机制来保证业务和事件数据的强一致性,结果就是会对系统性能造成一定的影响。
### 3. 事件总线(EventBus)
事件总线是实现微服务内聚合之间领域事件的重要组件,它提供事件分发和接收等服务。事件总线是进程内模型,它会在微服务内聚合之间遍历订阅者列表,采取同步或异步的模式传递数据。事件分发流程大致如下:
- 如果是微服务内的订阅者(其它聚合),则直接分发到指定订阅者;
- 如果是微服务外的订阅者,将事件数据保存到事件库(表)并异步发送到消息中间件;
- 如果同时存在微服务内和外订阅者,则先分发到内部订阅者,将事件消息保存到事件库(表),再异步发送到消息中间件。
### 4. 消息中间件
跨微服务的领域事件大多会用到消息中间件实现跨微服务的事件发布和订阅。消息中间件的产品非常成熟市场上可选的技术也非常多比如KafkaRabbitMQ等。
### 5. 事件接收和处理
微服务订阅方在应用层采用监听机制,接收消息队列中的事件数据,完成事件数据的持久化后,就可以开始进一步的业务处理。领域事件处理可在领域服务中实现。
## 领域事件运行机制相关案例
这里我用承保业务流程的缴费通知单事件,来给你解释一下领域事件的运行机制。这个领域事件发生在投保和收款微服务之间。发生的领域事件是:缴费通知单已生成。下一步的业务操作是:缴费。
<img src="https://static001.geekbang.org/resource/image/89/11/89321072afd996c6a90fa9774f769e11.jpg" alt="">
**事件起点:出单员生成投保单,核保通过后,发起生成缴费通知单的操作。**
1.投保微服务应用服务调用聚合中的领域服务createPaymentNotice和createPaymentNoticeEvent分别创建缴费通知单、缴费通知单事件。其中缴费通知单事件类PaymentNoticeEvent继承基类DomainEvent。
2.利用仓储服务持久化缴费通知单相关的业务和事件数据。为了避免分布式事务,这些业务和事件数据都持久化到本地投保微服务数据库中。
3.通过数据库日志捕获技术或者定时程序,从数据库事件表中获取事件增量数据,发布到消息中间件。这里说明:事件发布也可以通过应用服务或者领域服务完成发布。
4.收款微服务在应用层从消息中间件订阅缴费通知单事件消息主题,监听并获取事件数据后,应用服务调用领域层的领域服务将事件数据持久化到本地数据库中。
5.收款微服务调用领域层的领域服务PayPremium完成缴费。
6.事件结束。
提示:缴费完成后,后续流程的微服务还会产生很多新的领域事件,比如缴费已完成、保单已保存等等。这些后续的事件处理基本上跟 16 的处理机制类似。
## 总结
今天我们主要讲了领域事件以及领域事件的处理机制。领域事件驱动是很成熟的技术在很多分布式架构中得到了大量的使用。领域事件是DDD的一个重要概念在设计时我们要重点关注领域事件用领域事件来驱动业务的流转尽量采用基于事件的最终一致降低微服务之间直接访问的压力实现微服务之间的解耦维护领域模型的独立性和数据一致性。
除此之外领域事件驱动机制可以实现一个发布方N个订阅方的模式这在传统的直接服务调用设计中基本是不可能做到的。
## 思考题
思考一下你公司有哪些业务场景可以采用领域事件驱动的设计方式?
欢迎留言和我分享你的思考,你也可以把今天所学分享给身边的朋友,邀请他加入探讨,共同进步。
<img src="https://static001.geekbang.org/resource/image/7b/33/7b1a917aff0ec923b78a54e81ed90733.jpg" alt="unpreview">

View File

@@ -0,0 +1,137 @@
<audio id="audio" title="07 | DDD分层架构有效降低层与层之间的依赖" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a3/25/a3eaba495b572cce3d747d7d81580925.mp3"></audio>
你好我是欧创新。前面我们讲了DDD的一些重要概念以及领域模型的设计理念。今天我们来聊聊“DDD分层架构”。
微服务架构模型有好多种例如整洁架构、CQRS和六边形架构等等。每种架构模式虽然提出的时代和背景不同但其核心理念都是为了设计出“高内聚低耦合”的架构轻松实现架构演进。而DDD分层架构的出现使架构边界变得越来越清晰它在微服务架构模型中占有非常重要的位置。
那DDD分层架构到底长什么样DDD分层架构如何推动架构演进我们该怎么转向DDD分层架构这就是我们这一讲重点要解决的问题。
## 什么是DDD分层架构
DDD的分层架构在不断发展。最早是传统的四层架构后来四层架构有了进一步的优化实现了各层对基础层的解耦再后来领域层和应用层之间增加了上下文环境Context五层架构DCI就此形成了。
<img src="https://static001.geekbang.org/resource/image/d6/e1/d6abc3e4f5837cd51b689d01433cace1.jpg" alt="">
我们看一下上面这张图在最早的传统四层架构中基础层是被其它层依赖的它位于最核心的位置那按照分层架构的思想它应该就是核心但实际上领域层才是软件的核心所以这种依赖是有问题的。后来我们采用了依赖倒置Dependency inversion principle,DIP的设计优化了传统的四层架构实现了各层对基础层的解耦。
我们今天讲的DDD分层架构就是优化后的四层架构。在下面这张图中从上到下依次是用户接口层、应用层、领域层和基础层。那DDD各层的主要职责是什么呢下面我来逐一介绍一下。
<img src="https://static001.geekbang.org/resource/image/d0/9d/d02e92626dd8d6b077002ab6b977159d.png" alt="">
1.**用户接口层**
用户接口层负责向用户显示信息和解释用户指令。这里的用户可能是:用户、程序、自动化测试和批处理脚本等等。
2.**应用层**
应用层是很薄的一层,理论上不应该有业务规则或逻辑,主要面向用例和流程相关的操作。但应用层又位于领域层之上,因为领域层包含多个聚合,所以它可以协调多个聚合的服务和领域对象完成服务编排和组合,协作完成业务操作。
此外,应用层也是微服务之间交互的通道,它可以调用其它微服务的应用服务,完成微服务之间的服务组合和编排。
这里我要提醒你一下:在设计和开发时,不要将本该放在领域层的业务逻辑放到应用层中实现。因为庞大的应用层会使领域模型失焦,时间一长你的微服务就会演化为传统的三层架构,业务逻辑会变得混乱。
另外应用服务是在应用层的它负责服务的组合、编排和转发负责处理业务用例的执行顺序以及结果的拼装以粗粒度的服务通过API网关向前端发布。还有应用服务还可以进行安全认证、权限校验、事务控制、发送或订阅领域事件等。
3.**领域层**
领域层的作用是实现企业核心业务逻辑,通过各种校验手段保证业务的正确性。领域层主要体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。
领域层包含聚合根、实体、值对象、领域服务等领域模型中的领域对象。
这里我要特别解释一下其中几个领域对象的关系,以便你在设计领域层的时候能更加清楚。首先,领域模型的业务逻辑主要是由实体和领域服务来实现的,其中实体会采用充血模型来实现所有与之相关的业务功能。其次,你要知道,实体和领域服务在实现业务逻辑上不是同级的,当领域中的某些功能,单一实体(或者值对象)不能实现时,领域服务就会出马,它可以组合聚合内的多个实体(或者值对象),实现复杂的业务逻辑。
4.**基础层**
基础层是贯穿所有层的,它的作用就是为其它各层提供通用的技术和基础服务,包括第三方工具、驱动、消息中间件、网关、文件、缓存以及数据库等。比较常见的功能还是提供数据库持久化。
基础层包含基础服务,它采用依赖倒置设计,封装基础资源服务,实现应用层、领域层与基础层的解耦,降低外部资源变化对应用的影响。
比如说,在传统架构设计中,由于上层应用对数据库的强耦合,很多公司在架构演进中最担忧的可能就是换数据库了,因为一旦更换数据库,就可能需要重写大部分的代码,这对应用来说是致命的。那采用依赖倒置的设计以后,应用层就可以通过解耦来保持独立的核心业务逻辑。当数据库变更时,我们只需要更换数据库基础服务就可以了,这样就将资源变更对应用的影响降到了最低。
### DDD分层架构最重要的原则是什么
在《实现领域驱动设计》一书中DDD分层架构有一个重要的原则每层只能与位于其下方的层发生耦合。
而架构根据耦合的紧密程度又可以分为两种严格分层架构和松散分层架构。优化后的DDD分层架构模型就属于严格分层架构任何层只能对位于其直接下方的层产生依赖。而传统的DDD分层架构则属于松散分层架构它允许某层与其任意下方的层发生依赖。
那我们怎么选呢?综合我的经验,为了服务的可管理,我建议你采用严格分层架构。
在严格分层架构中,领域服务只能被应用服务调用,而应用服务只能被用户接口层调用,服务是逐层对外封装或组合的,依赖关系清晰。而在松散分层架构中,领域服务可以同时被应用层或用户接口层调用,服务的依赖关系比较复杂且难管理,甚至容易使核心业务逻辑外泄。
试想下,如果领域层中的某个服务发生了重大变更,那该如何通知所有调用方同步调整和升级呢?但在严格分层架构中,你只需要逐层通知上层服务就可以了。
## DDD分层架构如何推动架构演进
领域模型不是一成不变的,因为业务的变化会影响领域模型,而领域模型的变化则会影响微服务的功能和边界。那我们该如何实现领域模型和微服务的同步演进呢?
1.**微服务架构的演进**
通过基础篇的讲解,我们知道:领域模型中对象的层次从内到外依次是:值对象、实体、聚合和限界上下文。
实体或值对象的简单变更,一般不会让领域模型和微服务发生大的变化。但聚合的重组或拆分却可以。这是因为聚合内业务功能内聚,能独立完成特定的业务逻辑。那聚合的重组或拆分,势必就会引起业务模块和系统功能的变化了。
这里我们可以以聚合为基础单元,完成领域模型和微服务架构的演进。聚合可以作为一个整体,在不同的领域模型之间重组或者拆分,或者直接将一个聚合独立为微服务。
<img src="https://static001.geekbang.org/resource/image/7f/7c/7f1e3891c9c11abce96020e0bf20d67c.jpg" alt="">
我们结合上图以微服务1为例讲解下微服务架构的演进过程
- 当你发现微服务1中聚合a的功能经常被高频访问以致拖累整个微服务1的性能时我们可以把聚合a的代码从微服务1中剥离出来独立为微服务2。这样微服务2就可轻松应对高性能场景。
- 在业务发展到一定程度以后你会发现微服务3的领域模型有了变化聚合d会更适合放到微服务1的领域模型中。这时你就可以将聚合d的代码整体搬迁到微服务1中。如果你在设计时已经定义好了聚合之间的代码边界这个过程不会太复杂也不会花太多时间。
- 最后我们发现在经历模型和架构演进后微服务1已经从最初包含聚合a、b、c演进为包含聚合b、c、d的新领域模型和微服务了。
你看,好的聚合和代码模型的边界设计,可以让你快速应对业务变化,轻松实现领域模型和微服务架构的演进。你可能还会想,那怎么实现聚合代码快速重组呢?别急,后面实战篇会详细讲解,这里我们先感知下大的实现流程。
2.**微服务内服务的演进**
在微服务内部,实体的方法被领域服务组合和封装,领域服务又被应用服务组合和封装。在服务逐层组合和封装的过程中,你会发现这样一个有趣的现象。
<img src="https://static001.geekbang.org/resource/image/9a/76/9a602b741c222b19c7cc4780da79cf76.jpg" alt="">
我们看下上面这张图。在服务设计时你并不一定能完整预测有哪些下层服务会被多少个上层服务组装因此领域层通常只提供一些原子服务比如领域服务a、b、c。但随着系统功能增强和外部接入越来越多应用服务会不断丰富。有一天你会发现领域服务b和c同时多次被多个应用服务调用了执行顺序也基本一致。这时你可以考虑将b和c合并再将应用服务中b、c的功能下沉到领域层演进为新的领域服务b+c。这样既减少了服务的数量也减轻了上层服务组合和编排的复杂度。
你看,这就是服务演进的过程,它是随着你的系统发展的,最后你会发现你的领域模型会越来越精炼,越来越能适应需求的快速变化。
## 三层架构如何演进到DDD分层架构
综合前面的讲解相信DDD分层架构的优势你心里也有个谱了。我们不妨总结一下最最重要两点。
首先由于层间松耦合我们可以专注于本层的设计而不必关心其它层也不必担心自己的设计会影响其它层。可以说DDD成功地降低了层与层之间的依赖。
其次,分层架构使得程序结构变得清晰,升级和维护更加容易。我们修改某层代码时,只要本层的接口参数不变,其它层可以不必修改。即使本层的接口发生变化,也只影响相邻的上层,修改工作量小且错误可以控制,不会带来意外的风险。
**那我们该怎样转向DDD分层架构呢不妨看看下面这个过程。**
传统企业应用大多是单体架构,而单体架构则大多是三层架构。三层架构解决了程序内代码间调用复杂、代码职责不清的问题,但这种分层是逻辑概念,在物理上它是中心化的集中式架构,并不适合分布式微服务架构。
DDD分层架构中的要素其实和三层架构类似只是在DDD分层架构中这些要素被重新归类重新划分了层确定了层与层之间的交互规则和职责边界。
<img src="https://static001.geekbang.org/resource/image/16/a1/1680723ca91aa57d719d5cdbc1d910a1.jpg" alt="">
我们看一下上面这张图分析一下从三层架构向DDD分层架构演进的过程。
首先你要清楚三层架构向DDD分层架构演进主要发生在业务逻辑层和数据访问层。
DDD分层架构在用户接口层引入了DTO给前端提供了更多的可使用数据和更高的展示灵活性。
DDD分层架构对三层架构的业务逻辑层进行了更清晰的划分改善了三层架构核心业务逻辑混乱代码改动相互影响大的情况。DDD分层架构将业务逻辑层的服务拆分到了应用层和领域层。应用层快速响应前端的变化领域层实现领域模型的能力。
另外一个重要的变化发生在数据访问层和基础层之间。三层架构数据访问采用DAO方式DDD分层架构的数据库等基础资源访问采用了仓储Repository设计模式通过依赖倒置实现各层对基础资源的解耦。
仓储又分为两部分仓储接口和仓储实现。仓储接口放在领域层中仓储实现放在基础层。原来三层架构通用的第三方工具包、驱动、Common、Utility、Config等通用的公共的资源类统一放到了基础层。
最后我想说传统三层架构向DDD分层架构的演进体现的正是领域驱动设计思想的演进。希望你也感受到了并尝试将其应用在自己的架构设计中。
## 总结
今天我们主要讲了DDD的分层架构它作为微服务的核心框架我想怎么强调其重要性都是不过分的。
DDD分层架构包含用户接口层、应用层、领域层和基础层。通过这些层次划分我们可以明确微服务各层的职能划定各领域对象的边界确定各领域对象的协作方式。这种架构既体现了微服务设计和架构演进的需求又很好地融入了领域模型的概念二者无缝结合相信会给你的微服务设计带来不一样的感觉。
## 思考题
请结合你的业务场景中,思考一下领域层会有哪些领域对象,应用层会有哪些领域对象?
欢迎留言和我分享你的思考,你也可以把今天所学分享给身边的朋友,邀请他加入探讨,共同进步。
<img src="https://static001.geekbang.org/resource/image/7b/33/7b1a917aff0ec923b78a54e81ed90733.jpg" alt="unpreview">

View File

@@ -0,0 +1,134 @@
<audio id="audio" title="08 | 微服务架构模型:几种常见模型的对比和分析" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/05/7e/056e3777014519d51340309d94330c7e.mp3"></audio>
你好,我是欧创新。
在上一讲中我重点介绍了DDD分层架构同时我也提到了微服务架构模型其实还有好多种不知道你注意到了没这些架构模型在我们的实际应用中都具有很高的借鉴价值。
那么今天我们就把DDD分层架构详情介绍如有遗忘可回看 [[第07讲]](https://time.geekbang.org/column/article/156849) )、整洁架构、六边形架构这三种架构模型放到一起,对比分析,看看如何利用好它们,帮助我们设计出高内聚低耦合的中台以及微服务架构。
## 整洁架构
整洁架构又名“洋葱架构”。为什么叫它洋葱架构?看看下面这张图你就明白了。整洁架构的层就像洋葱片一样,它体现了分层的设计思想。
在整洁架构里,同心圆代表应用软件的不同部分,从里到外依次是领域模型、领域服务、应用服务和最外围的容易变化的内容,比如用户界面和基础设施。
整洁架构最主要的原则是依赖原则,它定义了各层的依赖关系,越往里依赖越低,代码级别越高,越是核心能力。外圆代码依赖只能指向内圆,内圆不需要知道外圆的任何情况。
<img src="https://static001.geekbang.org/resource/image/fc/42/fc8208d9f4cfadb7949d6e98a8c18442.png" alt="">
在洋葱架构中,各层的职能是这样划分的:
- 领域模型实现领域内核心业务逻辑,它封装了企业级的业务规则。领域模型的主体是实体,一个实体可以是一个带方法的对象,也可以是一个数据结构和方法集合。
- 领域服务实现涉及多个实体的复杂业务逻辑。
- 应用服务实现与用户操作相关的服务组合与编排,它包含了应用特有的业务流程规则,封装和实现了系统所有用例。
- 最外层主要提供适配的能力,适配能力分为主动适配和被动适配。主动适配主要实现外部用户、网页、批处理和自动化测试等对内层业务逻辑访问适配。被动适配主要是实现核心业务逻辑对基础资源访问的适配,比如数据库、缓存、文件系统和消息中间件等。
- 红圈内的领域模型、领域服务和应用服务一起组成软件核心业务能力。
## 六边形架构
六边形架构又名“端口适配器架构”。追溯微服务架构的渊源,一般都会涉及到六边形架构。
六边形架构的核心理念是应用是通过端口与外部进行交互的。我想这也是微服务架构下API网关盛行的主要原因吧。
也就是说在下图的六边形架构中红圈内的核心业务逻辑应用程序和领域模型与外部资源包括APP、Web应用以及数据库资源等完全隔离仅通过适配器进行交互。它解决了业务逻辑与用户界面的代码交错问题很好地实现了前后端分离。六边形架构各层的依赖关系与整洁架构一样都是由外向内依赖。
<img src="https://static001.geekbang.org/resource/image/85/6c/85fb9fb2782b343d45b4ca18c8f21e6c.png" alt="">
六边形架构将系统分为内六边形和外六边形两层,这两层的职能划分如下:
- 红圈内的六边形实现应用的核心业务逻辑;
- 外六边形完成外部应用、驱动和基础资源等的交互和访问对前端应用以API主动适配的方式提供服务对基础资源以依赖倒置被动适配的方式实现资源访问。
六边形架构的一个端口可能对应多个外部系统,不同的外部系统也可能会使用不同的适配器,由适配器负责协议转换。这就使得应用程序能够以一致的方式被用户、程序、自动化测试和批处理脚本使用。
## 三种微服务架构模型的对比和分析
虽然DDD分层架构、整洁架构、六边形架构的架构模型表现形式不一样但你不要被它们的表象所迷惑这三种架构模型的设计思想正是微服务架构高内聚低耦合原则的完美体现而它们身上闪耀的正是以领域模型为中心的设计思想。
<img src="https://static001.geekbang.org/resource/image/b2/71/b2e4dad1040857b5aedf0b1675ae4171.png" alt="">
我们看下上面这张图,结合图示对这三种架构模型做一个分析。
请你重点关注图中的红色线框,它们是非常重要的分界线,这三种架构里面都有,它的作用就是将核心业务逻辑与外部应用、基础资源进行隔离。
红色框内部主要实现核心业务逻辑,但核心业务逻辑也是有差异的,有的业务逻辑属于领域模型的能力,有的则属于面向用户的用例和流程编排能力。按照这种功能的差异,我们在这三种架构中划分了应用层和领域层,来承担不同的业务逻辑。
领域层实现面向领域模型,实现领域模型的核心业务逻辑,属于原子模型,它需要保持领域模型和业务逻辑的稳定,对外提供稳定的细粒度的领域服务,所以它处于架构的核心位置。
应用层实现面向用户操作相关的用例和流程对外提供粗粒度的API服务。它就像一个齿轮一样进行前台应用和领域层的适配接收前台需求随时做出响应和调整尽量避免将前台需求传导到领域层。应用层作为配速齿轮则位于前台应用和领域层之间。
可以说,这三种架构都考虑了前端需求的变与领域模型的不变。需求变幻无穷,但变化总是有矩可循的,用户体验、操作习惯、市场环境以及管理流程的变化,往往会导致界面逻辑和流程的多变。但总体来说,不管前端如何变化,在企业没有大的变革的情况下,核心领域逻辑基本不会大变,所以领域模型相对稳定,而用例和流程则会随着外部应用需求而随时调整。把握好这个规律,我们就知道该如何设计应用层和领域层了。
架构模型通过分层的方式来控制需求变化从外到里对系统的影响,从外向里受需求影响逐步减小。面向用户的前端可以快速响应外部需求进行调整和发布,灵活多变,应用层通过服务组合和编排来实现业务流程的快速适配上线,减少传导到领域层的需求,使领域层保持长期稳定。
这样设计的好处很明显了,就是可以保证领域层的核心业务逻辑不会因为外部需求和流程的变动而调整,对于建立前台灵活、中台稳固的架构很有帮助。
看到这里,你是不是已经猜出中台和微服务设计的关键了呢?我给出的答案是:领域模型和微服务的合理分层设计。那么你的答案呢?
## 从三种架构模型看中台和微服务设计
结合这三种微服务架构模型的共性,下面我来谈谈中台和微服务设计的一些心得体会。
中台本质上是领域的子域它可能是核心域也可能是通用域或支撑域。通常大家认为阿里的中台对应DDD的通用域将通用的公共能力沉淀为中台对外提供通用共享服务。
中台作为子域还可以继续分解为子子域在子域分解到合适大小通过事件风暴划分限界上下文以后就可以定义微服务了微服务用来实现中台的能力。表面上看DDD、中台、微服务这三者之间似乎没什么关联实际上它们的关系是非常紧密的组合在一起可以作为一个理论体系用于你的中台和微服务设计。
### 1. 中台建设要聚焦领域模型
中台需要站在全企业的高度考虑能力的共享和复用。
中台设计时我们需要建立中台内所有限界上下文的领域模型DDD建模过程中会考虑架构演进和功能的重新组合。领域模型建立的过程会对业务和应用进行清晰的逻辑和物理边界微服务划分。领域模型的结果会影响到后续的系统模型、架构模型和代码模型最终影响到微服务的拆分和项目落地。
因此,在中台设计中我们首先要聚焦领域模型,将它放在核心位置。
### 2. 微服务要有合理的架构分层
微服务设计要有分层的设计思想,让各层各司其职,建立松耦合的层间关系。
不要把与领域无关的逻辑放在领域层实现,保证领域层的纯洁和领域逻辑的稳定,避免污染领域模型。也不要把领域模型的业务逻辑放在应用层,这样会导致应用层过于庞大,最终领域模型会失焦。如果实在无法避免,我们可以引入防腐层,进行新老系统的适配和转换,过渡期完成后,可以直接将防腐层代码抛弃。
微服务内部的分层方式我们已经清楚了,那微服务之间是否也有层次依赖关系呢?如何实现微服务之间的服务集成?
有的微服务可以与前端应用集成,一起完成特定的业务,这是项目级微服务。而有的则是某个职责单一的中台微服务,企业级的业务流程需要将多个这样的微服务组合起来才能完成,这是企业级中台微服务。两类微服务由于复杂度不一样,集成方式也会有差异。
**项目级微服务**
项目级微服务的内部遵循分层架构模型就可以了。领域模型的核心逻辑在领域层实现服务的组合和编排在应用层实现通过API网关为前台应用提供服务实现前后端分离。但项目级的微服务可能会调用其它微服务你看在下面这张图中比如某个项目级微服务B调用认证微服务A完成登录和权限认证。
通常项目级微服务之间的集成发生在微服务的应用层由应用服务调用其它微服务发布在API网关上的应用服务。你看下图中微服务B中红色框内的应用服务B它除了可以组合和编排自己的领域服务外还可以组合和编排外部微服务的应用服务。它只要将编排后的服务发布到API网关供前端调用这样前端就可以直接访问自己的微服务了。
<img src="https://static001.geekbang.org/resource/image/b4/9e/b4231550cfbd56c15ccb3795d1062f9e.png" alt="">
**企业级中台微服务**
企业级的业务流程往往是多个中台微服务一起协作完成的,那跨中台的微服务如何实现集成呢?
企业级中台微服务的集成不能像项目级微服务一样,在某一个微服务内完成跨微服务的服务组合和编排。
我们可以在中台微服务之上增加一层,你看下面这张图,增加的这一层就位于红色框内,它的主要职能就是处理跨中台微服务的服务组合和编排,以及微服务之间的协调,它还可以完成前端不同渠道应用的适配。如果再将它的业务范围扩大一些,我可以将它做成一个面向不同行业和渠道的服务平台。
我们不妨借用BFF服务于前端的后端Backend for Frontends这个词暂且称它为BFF微服务。BFF微服务与其它微服务存在较大的差异就是它没有领域模型因此这个微服务内也不会有领域层。BFF微服务可以承担应用层和用户接口层的主要职能完成各个中台微服务的服务组合和编排可以适配不同前端和渠道的要求。
<img src="https://static001.geekbang.org/resource/image/ee/3b/eeb66579c1725817d0e9185161f1843b.png" alt="">
### 3. 应用和资源的解耦与适配
传统以数据为中心的设计模式,应用会对数据库、缓存、文件系统等基础资源产生严重依赖。
正是由于它们之间的这种强依赖的关系,我们一旦更换基础资源就会对应用产生很大的影响,因此需要为应用和资源解耦。
在微服务架构中,应用层、领域层和基础层解耦是通过仓储模式,采用依赖倒置的设计方法来实现的。在应用设计中,我们会同步考虑和基础资源的代码适配,那么一旦基础设施资源出现变更(比如换数据库),就可以屏蔽资源变更对业务代码的影响,切断业务逻辑对基础资源的依赖,最终降低资源变更对应用的影响。
## 总结
今天我们详细讲解了整洁架构和六边形架构并对包括DDD分层架构在内的三种微服务架构模进行对比分析总结出了它们的共同特征并从共性出发梳理出了中台建模和微服务架构设计的几个要点我们后面还会有更加详细的有关设计落地的讲述。
**那从今天的内容中我们不难看出:**DDD分层架构、整洁架构、六边形架构都是以领域模型为核心实行分层架构内部核心业务逻辑与外部应用、资源隔离并解耦。请务必记好这个设计思想今后会有大用处。
## 思考题
在系统设计时,你是如何避免外部需求对核心业务逻辑的影响的?有什么具体方法可以分享给大家吗?
欢迎留言分享,你也可以把今天所学分享给身边的朋友,邀请他一同交流、打卡。

View File

@@ -0,0 +1,137 @@
<audio id="audio" title="09 | 中台:数字转型后到底应该共享什么?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/03/cb/03fa222d5317007746f78dec5e8e06cb.mp3"></audio>
你好,我是欧创新。
在上一讲中我们了解了分层架构的设计思想,并提到了这种设计思想对中台建设十分有利,那么今天我就来讲一讲中台。
中台是数字化转型的一个热门话题。继阿里提出中台概念后,很多人又提出了各种各样的中台。今天我们主要讨论业务中台和数据中台。作为企业数字化中台转型的整体,我也会顺带聊一聊前台和后台的一些设计思路。
不少企业其实在很多年前就有了建大平台的实践经验,那在中台被热议时,我相信你一定听过很多质疑声。比如,有人说:“中台就是个怪名词,它不就是已经做了好多年的平台吗?”确实,中台源于平台,但它的战略高度要比平台高很多。
学完这一讲,你就会清楚地知道平台与中台的差异在什么地方?中台到底是什么?传统企业的中台建设方式是否应该和阿里一样…
## 平台到底是不是中台?
阿里提出中台战略后,很多企业开始拿着自己的系统与阿里的中台对标。有的企业在十多年前就完成了大一统的集中式系统拆分,实现了从传统大单体应用向大平台的演进,他们将公共能力和核心能力分开建设,解决了公共模块重复投入和重复建设的问题。
那这是不是阿里所说的中台呢?在回答这个问题之前,我们不妨先了解一下阿里的中台到底是什么样的。
阿里业务中台的前身是共享平台,而原来的共享平台更多的被当作资源团队,他们承接各业务方的需求,并为业务方在基础服务上做定制开发。 阿里业务中台的目标是把核心服务链路(会员、商品、交易、营销、店铺、资金结算等)整体当作一个平台产品来做,为前端业务提供的是业务解决方案,而不是彼此独立的系统。
下面我们分析一下传统企业大平台战略和阿里中台战略的差异。
平台只是将部分通用的公共能力独立为共享平台。虽然可以通过API或者数据对外提供公共共享服务解决系统重复建设的问题但这类平台并没有和企业内的其它平台或应用实现页面、业务流程和数据从前端到后端的全面融合并且没有将核心业务服务链路作为一个整体方案考虑各平台仍然是分离且独立的。
平台解决了公共能力复用的问题,但离中台的目标显然还有一段差距!
## 中台到底是什么?
“一千个读者就有一千个哈姆雷特”,这句话形容技术圈对中台的定义再合适不过了,说法很多。
先看一下阿里自己人对中台的定义:“中台是一个基础的理念和架构,我们要把所有的基础服务用中台的思路建设,进行联通,共同支持上端的业务。业务中台更多的是支持在线业务,数据中台提供了基础数据处理能力和很多的数据产品给所有业务方去用。业务中台、数据中台、算法中台等等一起提供对上层业务的支撑。”
再看一下思特沃克对中台的定义:“中台是企业级能力复用平台。”
综上,我们可以提炼出几个关于中台的关键词:共享、联通、融合和创新。联通是前台以及中台之间的联通,融合是前台流程和数据的融合,并以共享的方式支持前端一线业务的发展和创新。
我认为,中台首先体现的是一种企业级的能力,它提供的是一套企业级的整体解决方案,解决小到企业、集团,大到生态圈的能力共享、联通和融合问题,支持业务和商业模式创新。通过平台联通和数据融合为用户提供一致的体验,更敏捷地支撑前台一线业务。
中台来源于平台,但中台和平台相比,它更多体现的是一种理念的转变,它主要体现在这三个关键能力上:对前台业务的快速响应能力;企业级复用能力;从前台、中台到后台的设计、研发、页面操作、流程服务和数据的无缝联通、融合能力。
其中最关键的是快速响应能力和企业级的无缝联通和融合能力,尤其是对于跨业经营的超大型企业来说至关重要。
## 数字化转型中台应该共享什么?
相对互联网企业而言传统企业的渠道应用更多样化有面向内部人员的门店类应用、面向外部用户的互联网电商以及移动APP类应用。这些应用面向的用户和场景可能不同但其功能类似基本涵盖了核心业务能力。此外传统企业也会将部分核心应用的页面或API服务能力开放给生态圈第三方相互借力发展。
为了适应不同业务和渠道的发展过去很多企业的做法是开发很多独立的应用或APP。但由于IT系统建设初期并没有企业级的整体规划平台之间融合不好就导致了用户体验不好最关键的是用户并不想装那么多 APP。
为了提升用户体验实现统一运营很多企业开始缩减APP的数量开始通过一个APP集成企业内的所有能力联通前台所有的核心业务链路。
由于传统企业的商业模式和IT系统建设发展的历程与互联网企业不是完全一样的因此传统企业的中台建设策略与阿里中台战略也应该有所差异需要共享的内容也不一样。
<img src="https://static001.geekbang.org/resource/image/09/45/09d70aae8b66092bc692ac30510f9145.jpg" alt="">
由于渠道多样化传统企业不仅要将通用能力中台化以实现通用能力的沉淀、共享和复用这里的通用能力对应DDD的通用域或支撑域传统企业还需要将核心能力中台化以满足不同渠道的核心业务能力共享和复用的需求避免传统核心和互联网不同渠道应用出现“后端双核心、前端两张皮”的问题这里的核心能力对应DDD的核心域。
这就属于业务中台的范畴了,我们需要解决核心业务链路的联通和不同渠道服务共享的问题。除此之外,我们还需要解决系统微服务拆分后的数据孤岛、数据融合和业务创新等问题,这就属于数据中台的范畴了,尤其是当我们采用分布式架构以后,我们就更应该关注微服务拆分后的数据融合和共享问题了。
综上,在中台设计和规划时,我们需要整体考虑企业内前台、中台以及后台应用的协同,实现不同渠道应用的前端页面、流程和服务的共享,还有核心业务链路的联通以及前台流程和数据的融合、共享,支持业务和商业模式的创新。
## 如何实现前中后台的协同?
企业级能力往往是前中后台协同作战能力的体现。
如果把业务中台比作陆军、火箭军和空军等专业军种的话,它主要发挥战术专业能力。前台就是作战部队,它需要根据前线的战场需求,对业务中台的能力进行调度,实现能力融合和效率最大化。而数据中台就是信息情报中心和联合作战总指挥部,它能够汇集各种数据、完成分析,制定战略和战术计划。后台就是后勤部队,提供技术支持。下面我们分别来说说。
### 1. 前台
传统企业的早期系统有不少是基于业务领域或组织架构来建设的,每个系统都有自己的前端,相互独立,用户操作是竖井式,需要登录多个系统才能完成完整的业务流程。
<img src="https://static001.geekbang.org/resource/image/76/91/76c677ccc83912dbc4d09d62c259b391.jpg" alt="">
中台后的前台建设要有一套综合考虑业务边界、流程和平台的整体解决方案,以实现各不同中台前端操作、流程和界面的联通、融合。不管后端有多少个中台,前端用户感受到的就是只有一个前台。
<img src="https://static001.geekbang.org/resource/image/ba/2b/ba2049c9a3696bbebbd9d60e496df72b.jpg" alt="">
在前台设计中我们可以借鉴微前端的设计思想,在企业内不仅实现前端解耦和复用,还可以根据核心链路和业务流程,通过对微前端页面的动态组合和流程编排,实现前台业务的融合。
前端页面可以很自然地融合到不同的终端和渠道应用核心业务链路中,实现前端页面、流程和功能复用。
### 2. 中台
传统企业的核心业务大多是基于集中式架构开发的而单体系统存在扩展性和弹性伸缩能力差的问题因此无法适应忽高忽低的互联网业务场景。而数据类应用也多数通过ETL工具抽取数据实现数据建模、统计和报表分析功能但由于数据时效和融合能力不够再加上传统数据类应用本来就不是为前端而生的因此难以快速响应前端一线业务。
业务中台的建设可采用领域驱动设计方法,通过领域建模,将可复用的公共能力从各个单体剥离,沉淀并组合,采用微服务架构模式,建设成为可共享的通用能力中台。
同样的,我们可以将核心能力用微服务架构模式,建设成为可面向不同渠道和场景的可复用的核心能力中台。 业务中台向前台、第三方和其它中台提供API服务实现通用能力和核心能力的复用。
<img src="https://static001.geekbang.org/resource/image/26/81/261b05056ae6056ff406f7dadf7ac081.jpg" alt="">
但你需要记住这一点:在将传统集中式单体按业务职责和能力细分为微服务,建设中台的过程中,会产生越来越多的独立部署的微服务。这样做虽然提升了应用弹性和高可用能力,但由于微服务的物理隔离,原来一些系统内的调用会变成跨微服务调用,再加上前后端分离,微服务拆分会导致数据进一步分离,增加企业级应用集成的难度。
如果没有合适的设计和指导思想,处理不好前台、中台和后台的关系,将会进一步加剧前台流程和数据的孤岛化、碎片化。
**数据中台的主要目标是打通数据孤岛,实现业务融合和创新,包括三大主要职能:**
- 一是完成企业全域数据的采集与存储,实现各不同业务类别中台数据的汇总和集中管理。
- 二是按照标准的数据规范或数据模型,将数据按照不同主题域或场景进行加工和处理,形成面向不同主题和场景的数据应用,比如客户视图、代理人视图、渠道视图、机构视图等不同数据体系。
- 三是建立业务需求驱动的数据体系,基于各个维度的数据,深度萃取数据价值,支持业务和商业模式的创新。
**相应的,数据中台的建设就可分为三步走:**
- 第一步实现各中台业务数据的汇集,解决数据孤岛和初级数据共享问题。
- 第二步实现企业级实时或非实时全维度数据的深度融合、加工和共享。
- 第三步萃取数据价值,支持业务创新,加速从数据转换为业务价值的过程。
数据中台不仅限于分析型场景,也适用于交易型场景。它可以建立在数据仓库或数据平台之上,将数据服务化之后提供给业务系统。基于数据库日志捕获的技术,使数据的时效性大大提升,这样就可以为交易型场景提供很好的支撑。
综上,数据中台主要完成数据的融合和加工,萃取数据业务价值,支持业务创新,对外提供数据共享服务。
### 3. 后台
很多人提到中台时自然会问:“既然有前台和中台,那是否有后台,后台的职责又是什么?”
我们来看一下阿里对前台、中台和后台的定位。
前台主要面向客户以及终端销售者实现营销推广以及交易转化中台主要面向运营人员完成运营支撑后台主要面向后台管理人员实现流程审核、内部管理以及后勤支撑比如采购、人力、财务和OA等系统。
那对于后台,为了实现内部的管理要求,很多人习惯性将这些管理要求嵌入到核心业务流程中。而一般来说这类内控管理需求对权限、管控规则和流程等要求都比较高,但是大部分管理人员只是参与了某个局部业务环节的审核。这类复杂的管理需求,会凭空增加不同渠道应用前台界面和核心流程的融合难度以及软件开发的复杂度。
在设计流程审核和管理类功能的时候我们可以考虑按角色或岗位进行功能聚合将复杂的管理需求从通用的核心业务链路中剥离参考小程序的建设模式通过特定程序入口嵌入前台APP或应用中。
管理需求从前台核心业务链路剥离后前台应用将具有更好的通用性它可以更加容易地实现各渠道前台界面和流程的融合。一个前台应用或APP可以无差别地同时面向外部互联网用户和内部业务人员从而促进传统渠道与互联网渠道应用前台的融合。
## 总结
今天我们主要讨论了中台建设的一些思路。企业的中台转型不只是中台的工作,我们需要整体考虑前台、中台和后台的协同、共享、联通和融合。
前台通过页面和流程共享实现不同渠道应用之间的前台融合中台通过API实现服务共享。而前台、业务中台和数据中台的融合可以实现传统应用与互联网应用的融合从而解决“后端双核心、前端两张皮”的问题。能力复用了前台流程和数据融合了才能更好地支持业务的融合和商业模式的创新。
## 思考题
你的公司是如何进行前后端设计和融合的呢?
欢迎留言分享,你也可以把今天所学分享给身边的朋友,邀请他一同交流、打卡。

View File

@@ -0,0 +1,103 @@
<audio id="audio" title="10 | DDD、中台和微服务它们是如何协作的" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/2b/34/2b42aa1876fd04527f1ed99addd31834.mp3"></audio>
你好我是欧创新。今天我一起来聊聊DDD、中台和微服务的关系。
DDD和微服务来源于西方而中台诞生于中国的阿里巴巴。DDD在二十多年前提出后一直默默前行中台和微服务的理念近几年才出现提出后就非常火爆。这三者看似风马牛不相及实则缘分匪浅。中台是抽象出来的业务模型微服务是业务模型的系统实现DDD作为方法论可以同时指导中台业务建模和微服务建设三者相辅相成完美结合。
你可能会问凭什么DDD可以指导中台和微服务建设究竟起到了什么作用呢
DDD有两把利器那就是它的战略设计和战术设计方法。
中台在企业架构上更多偏向业务模型形成中台的过程实际上也是业务领域不断细分的过程。在这个过程中我们会将同类通用的业务能力进行聚合和业务重构再根据限界上下文和业务内聚的原则建立领域模型。而DDD的战略设计最擅长的就是领域建模。
那在中台完成领域建模后我们就需要通过微服务来完成系统建设。此时DDD的战术设计又恰好可以与微服务的设计完美结合。可以说中台和微服务正是DDD实战的最佳场景。
## DDD的本质
我们先简单回顾一下DDD领域、子域、核心域、通用域和支撑域等概念后面会用到。
在研究和解决业务问题时DDD会按照一定的规则将业务领域进行细分领域细分到一定的程度后DDD会将问题范围限定在特定的边界内并在这个边界内建立领域模型进而用代码实现该领域模型解决相应的业务问题。领域可分解为子域子域可继续分为子子域一直到你认为适合建立领域模型为止。
子域还会根据自身重要性和功能属性划分为三类子域,它们分别是核心域、支撑域和通用域。关于这三类子域更为详细的讲解,你可以回看[[第02讲]](https://time.geekbang.org/column/article/149945)。
<img src="https://static001.geekbang.org/resource/image/99/29/991b8a5b685d8b0b3e172f38c0460a29.png" alt="">
接下来我们一起看下上面这张图我选择了保险的几个重要领域进行了高阶的领域划分。当然每个企业的领域定位和职责会有些不一样那在核心域的划分上肯定会有一定差异。因此当你去做领域划分的时候请务必结合企业战略这恰恰也体现了DDD领域建模的重要性。
通过领域划分和进一步的子域划分我们就可以区分不同子域在企业内的功能属性和重要性进而采取不同的资源投入和建设策略这在企业IT系统的建设过程中十分重要并且这样的划分还可以帮助企业进行中台设计。
## 中台的本质
中台来源于阿里的中台战略详见《企业IT架构转型之道阿里巴巴中台战略思想与架构实战》钟华编著。2015年年底阿里巴巴集团对外宣布全面启动中台战略构建符合数字时代的更具创新性、灵活性的“大中台、小前台”组织机制和业务机制即作为前台的一线业务会更敏捷、更快速地适应瞬息万变的市场而中台将集合整个集团的运营数据能力、产品技术能力对各前台业务形成强力支撑。
中台的本质其实就是提炼各个业务板块的共同需求,进行业务和系统抽象,形成通用的可复用的业务模型,打造成组件化产品,供前台部门使用。前台要做什么业务,需要什么资源,可以直接找中台,不需要每次都去改动自己的底层。
## DDD、中台和微服务的协作模式
我们在 [[第09讲]](https://time.geekbang.org/column/article/159580) 已经说过了传统企业和阿里中台战略的差异,那实际上更多的企业还是会聚焦在传统企业中台建设的模式,也就是将通用能力与核心能力全部中台化,以满足不同渠道核心业务能力的复用,那么接下来我们就还是把重点放在传统企业上。
传统企业可以将需要共享的公共能力进行领域建模,建设可共享的**通用中台**。除此之外,传统企业还会将核心能力进行领域建模,建设面向不同渠道的可复用的**核心中台**。
而这里的通用中台和核心中台都属于我们上一讲讲到的业务中台的范畴。
DDD的子域分为核心域、通用域和支撑域。划分这几个子域的主要目的是为了确定战略资源的投入一般来说战略投入的重点是核心域因此后面我们就可以暂时不严格区分支撑域和通用域了。
领域、中台以及微服务虽然属于不同层面的东西但我们还是可以将他们分解对照整理出来它们之间的关系。你看下面这张图我是从DDD领域建模和中台建设这两个不同的视角对同一个企业的业务架构进行分析。
<img src="https://static001.geekbang.org/resource/image/c6/df/c647561ff910f97b8500b75de70281df.png" alt="">
如果将企业内整个业务域作为一个问题域的话企业内的所有业务就是一个领域。在进行领域细分时从DDD视角来看子域可分为核心域、通用域和支撑域。从中台建设的视角来看业务域细分后的业务中台可分为核心中台和通用中台。
从领域功能属性和重要性对照来看通用中台对应DDD的通用域和支撑域核心中台对应DDD的核心域。从领域的功能范围来看子域与中台是一致的。领域模型所在的限界上下文对应微服务。建立了这个映射关系我们就可以用DDD来进行中台业务建模了。
**我们这里还是以保险领域为例。**保险域的业务中台分为两类:第一类是提供保险核心业务能力的核心中台(比如营销、承保和理赔等业务);第二类是支撑核心业务流程完成保险全流程的通用中台(比如订单、支付、客户和用户等)。
这里我要提醒你一下根据DDD首先要建立通用语言的原则在将DDD的方法引入中台设计时我们要先建立中台和DDD的通用语言。这里的子域与中台是一致的那我们就可以将子域统一为中台。
中台通过事件风暴可以进一步细分,最终完成业务领域建模。中台业务领域的功能不同,限界上下文的数量和大小就会不一样,领域模型也会不一样。
当完成业务建模后我们就可以采用DDD战术设计设计出聚合、实体、领域事件、领域服务以及应用服务等领域对象再利用分层架构模型完成微服务的设计。
以上就是DDD、中台和微服务在应用过程中的协作模式。
## 中台如何建模?
看完了三者的协作模式,我们就顺着上面的话题,接着来聊聊中台如何建模。
中台业务抽象的过程就是业务建模的过程对应DDD的战略设计。系统抽象的过程就是微服务的建设过程对应DDD的战术设计。下面我们就结合DDD领域建模的方法讲一下中台业务建模的过程。
**第一步:**按照业务流程(通常适用于核心域)或者功能属性、集合(通常适用于通用域或支撑域),将业务域细分为多个中台,再根据功能属性或重要性归类到核心中台或通用中台。核心中台设计时要考虑核心竞争力,通用中台要站在企业高度考虑共享和复用能力。
**第二步:**选取中台,根据用例、业务场景或用户旅程完成事件风暴,找出实体、聚合和限界上下文。依次进行领域分解,建立领域模型。
由于不同中台独立建模,某些领域对象或功能可能会重复出现在其它领域模型中,也有可能本该是同一个聚合的领域对象或功能,却分散在其它的中台里,这样会导致领域模型不完整或者业务不内聚。这里先不要着急,这一步我们只需要初步确定主领域模型就可以了,在第三步中我们还会提炼并重组这些领域对象。
**第三步:**以主领域模型为基础,扫描其它中台领域模型,检查并确定是否存在重复或者需要重组的领域对象、功能,提炼并重构主领域模型,完成最终的领域模型设计。
**第四步:**选择其它主领域模型重复第三步,直到所有主领域模型完成比对和重构。
**第五步:**基于领域模型完成微服务设计,完成系统落地。
<img src="https://static001.geekbang.org/resource/image/3c/47/3caae85ef680eb7cbc2ffb5c6a603f47.png" alt="">
结合上面这张图你可以大致了解到DDD中台设计的过程。DDD战略设计包括上述的第一步到第四步主要为业务域分解为中台对中台归类完成领域建模建立中台业务模型。DDD战术设计是第五步领域模型映射为微服务完成中台建设。
<img src="https://static001.geekbang.org/resource/image/45/71/45de1af6a4b5dd6cf54921ff9f422571.png" alt="">
那么如果还是以保险领域为例的话,完成领域建模后,里面的数据我们就可以填上了。这里我选取了通用中台的用户、客户和订单三个中台来做示例。客户中台提炼出了两个领域模型:客户信息和客户视图模型。用户中台提炼出了三个领域模型:用户管理、登录认证和权限模型。订单中台提炼出了订单模型。
这就是中台建模的全流程,当然看似简单的背后,若是遇上复杂的业务总会出现各种各样的问题,不然应用起来也不会有那么多的困难。如果你在按照以上流程实施的过程中遇到什么问题,欢迎在留言区和我讨论。
## 总结
今天我们主要讨论了传统企业中台建设的一些思路梳理了DDD、中台和微服务的关系。DDD的战略设计可用于中台业务建模战术设计可指导中台微服务设计。相信DDD与中台的完美结合可以让你的中台建设如虎添翼
另外,这一讲只是开一个头,在下一讲中我还会以一个传统核心业务的中台建设案例,详细讲解中台的设计过程。
## 思考题
你的企业是否在做中台现在是用什么方法做中台业务建模呢和DDD的设计方法相比你觉得孰优孰劣
欢迎留言分享,你也可以把今天所学分享给身边的朋友,邀请他一同交流、打卡。

View File

@@ -0,0 +1,59 @@
<audio id="audio" title="答疑有关3个典型问题的讲解" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/fc/4b/fcdf97141fa0ce1200643c3ae2e6fb4b.mp3"></audio>
你好,我是欧创新。
截至今天这一讲我们的基础篇和进阶篇的内容就结束了。在这个过程中我一直有关注大家提的问题。那在实战篇正式开始之前啊我想针对3个比较典型的问题做一个讲解希望你也能同步思考调动自己已学过的内容这对我们后面实战篇的学习也是有一定帮助的。
**问题1有关于领域可以划分为核心域、通用域和支撑域以及子域和限界上下文关系的话题还有是否有边界划分的量化标准**
我在 [[第 02 讲]](https://time.geekbang.org/column/article/149945) 中讲到了,在领域不断划分的过程中,领域会被细分为不同的子域,这个过程实际上是将问题范围不断缩小的过程。
借用读者“密码123456”的总结他认为“对于领域问题来说可以理解为对一个问题不断地划分直到划分为我们熟悉的、能够快速处理的小问题。然后再对小问题的处理排列一个优先级。”
这个理解是很到位的。在领域细分到一定的范围后,我们就可以对这个子域进行事件风暴,为这个子域划分限界上下文,建立领域模型,然后就可以基于领域模型进行微服务设计了。
虽然DDD没有明确说明子域和限界上下文的关系。我个人认为子域的划分是一种比较粗的领域边界的划分它不考虑子域内的领域对象、对象之间的关系和结构。子域的划分往往按照业务阶段或者功能模块边界进行粗分其目的就是为了让你能够在一个相对较小的问题空间内比较方便地用事件风暴来梳理业务场景。
而限界上下文本质上也是子域,限界上下文是在明确的子域内,用事件风暴划分出来的。它体现的是一种详细的设计过程。这个过程设计出了领域模型,明确了领域对象以及领域对象的依赖等关系,有了领域模型,你就可以直接进行微服务设计了。
关于核心域、通用域和支撑域划分这三个不同类型子域的主要目的是为了区分业务域的优先级确定IT战略投入。我们会将重要的资源投入在核心域上确保好钢用在刀刃上。每个企业由于商业模式或者战略方向不一样核心域会有一些差异不要用固定的眼光看待不同企业的核心域。
核心域、通用域和支撑域都是业务领域只不过重要性和功能属性不一样。采用的DDD设计方法和过程是没有差异的。
从目前来看还没有可以量化的领域以及限界上下文的划分标准。它主要依赖领域专家经验以及和项目团队在事件风暴过程中不断地权衡和分析。不要奢望一次迭代就能够给复杂的业务建立一个完美的领域模型。领域模型很多时候也需要多次迭代才能成型它也需要不断地演进。但如果是用DDD设计出来的领域模型的边界和微服务内聚合的边界非常清晰的话这个演进过程相对来说会简单很多所需的时间成本也会很低。
**问题2关于聚合设计的问题领域层与基础层为什么要依赖倒置DIP**
聚合主要实现核心业务逻辑,里面有很多的领域对象,这些领域对象之间需要通过聚合根进行统一的管理,以确保数据的一致性。
在聚合设计时我们会用到两个重要的设计模式工厂Factory模式和仓储Repository模式。如果你有兴趣详细了解的话推荐你阅读《实现领域驱动设计》一书的第11章和第12章。
那为什么要引入工厂模式呢?
这是因为有些聚合内可能含有非常多的实体和值对象,我们需要确保聚合根以及所有被依赖的对象实例同时被创建。如果都通过聚合根来构造,将会非常复杂。因此我们可以通过工厂模式来封装复杂对象的创建过程,但并不是所有对象的构造都需要用到工厂,如果构造过程不复杂,只是单一对象的构造,你用简单的构造方法就足够了。
又为什么要引入仓储模式?解答这个问题的同时,我也一起将依赖倒置的问题解答一下。
在传统的DDD四层架构中所有层都是依赖基础层的。这样做有什么不好的地方呢如果应用逻辑对基础层依赖太大的话基础层中与资源有关的代码可能会渗透到应用逻辑中。而现在技术组件的更新频率是很快的一旦出现基础组件的变更且基础组件的代码被带入到了应用逻辑中这样会对上层的应用逻辑产生致命的影响。
为了解耦应用逻辑和基础资源,在基础层和上层应用逻辑之间会增加一层,这一层就是仓储层。一个聚合对应一个仓储,仓储实现聚合内数据的持久化。聚合内的应用逻辑通过接口来访问基础资源,仓储实现在基础层实现。这样应用逻辑和基础资源的实现逻辑是分离的。如果变更基础资源组件,只需要替换仓储实现就可以了,不会对应用逻辑产生太大的影响,这样就实现了应用逻辑与基础资源的解耦,也就实现了依赖倒置。
关于聚合设计过程中的一些原则问题。大部分的业务场景我们都可以通过事件风暴找到聚合根建立聚合划分限界上下文建立领域模型。但也有部分场景比如数据计算、统计以及批处理业务场景所有的实体都是独立无关联的找不到聚合根也无法建立领域模型。但是它们之间的业务关系是非常紧密的在业务上是高内聚的。我们也可以将这类场景作为一个聚合处理除了不考虑聚合根的设计方法外其它诸如DDD分层架构相关的设计方法都是可以采用的。
一些业务场景如果复杂度并不高而用DDD设计会带来不必要的麻烦的话比如增加复杂度有些原则也是可以突破的不要为做DDD而做DDD。即使采用传统的方式也是没有关系的最终以解决实际问题为最佳。但必须记住一点如果采用传统的设计方式一定要保证领域模型的边界以及微服务内聚合的逻辑边界清晰这样的话以后微服务的演进就不会太复杂。
**问题3领域事件采用消息异步机制发布方和订阅方数据如何保证一致性微服务内聚合之间领域事件是否一定要用事件总线**
在领域事件设计中,为了解耦微服务,微服务之间数据采用最终一致性原则。由于发布方是在消息总线发布消息以后,并不关心数据是否送达,或者送达后订阅方是否正常处理,因此有些技术人会担心发布方和订阅方数据一致性的问题。
那在对数据一致性要求比较高的业务场景,我们是有相关的设计考虑的。也就是发送方和订阅方的事件数据都必须落库,发送方除了保存业务数据以外,在往消息中间件发布消息之前,会先将要发布的消息写入本地库。而接收方在处理消息之前,需要先将收到的消息写入本地库。然后可以采用定期对发布方和订阅方的事件数据对账的操作,识别出不一致的数据。如果数据出现异常或不一致的情况,可以启动定时程序再次发送,必要时可以转人工操作处理。
关于事件总线的问题。由于微服务内的逻辑都在一个进程内,后端数据库也是一个,微服务内的事务相比微服务之间会好控制一些。在处理微服务内的领域事件时,如果引入事件总线,会增加开发的复杂度,那是否引入事件总线,就需要你来权衡。
个人感觉如果你的场景中,不会出现导致聚合之间数据不一致的情况,就可以不使用事件总线。另外,通过应用服务也可以实现聚合之间的服务和数据协调。
以上就是3个典型问题的答案了不知你先前是否有同样的疑惑这些答案又是否与你不谋而合呢如果你还有其它问题欢迎在留言区提出我会一一解答。
今天的内容就到这了,如果有所收获,也可以分享给你的朋友,我们实战篇见!