中台与DDD

中台与DDD

概念

什么是中台

  • 按照可复用原则,将通用的、可复用的能力沉淀到中台,完成企业级业务模型重构
  • 中台落地的技术实现有很多种,当前微服务架构是公认的最佳实践。
  • 中台本质是业务领域的子域

微服务与DDD是共生关系

  • 微服务提倡将应用进行服务化拆分,通过业务领域边界实现服务边界的划分。
  • 而微服务的拆分困境在于不知道业务或者应用的边界在什么地方
  • DDD恰好提供一种基于业务界限上下文边界来划分业务的方法
  • DDD是一种设计方法,微服务是一种架构风格,两者都是为了追求软件的高响应力,从业务视角去分离应用系统复杂性的手段
  • DDD关注点在于业务抽象、领域建模,维持业务和代码逻辑的一致性。微服务的关注点在于实现去中心化,架构演进。
  • 当然,微服务还可以考虑性能、伸缩等技术要求,单独将一块业务领域剥离到一个服务,也是可以的,这块最小可以做到把DDD中的一个聚合单独剥离成一个微服务
  • 中台和微服务设计的关键,在于领域模型设计(横向解耦),以及微服务的合理分层设计(纵向解耦)

DDD

战略设计

  • 概念

    • 子域

      • 子域是可以不断递归划分的,关键还是要看你的业务理解,以及团队的大小
      • 在很多场景中,很多流程节点框定的边界天然就是子域
      • 子域是从问题的视角出发,将大问题分解成小问题,所以可以直接从感觉上划分
    • 界限上下文

      • 界线上下文是从解决方案的视角触发。所以一般是子域划分好了,然后在里面罗列领域对象,如果这些领域对象还可以再分块内聚,则在子域内通过界限上下文将它们隔开
      • 界限上下文本质上就是子域,只是它会更加考虑技术实现和领域对象边界这些细节,不像划分子域时只需要明确问题就行。
      • 子域和界限上下文的关系是一对一或者一对多的关系
      • 界限上下文内的部分叫做领域模型
      • 界限上下文就是业务的实际边界,通常可以作为微服务的边界。当然,考虑团队和架构等非业务因素,也可以把更低级别的聚合或者更高级别的子域作为微服务边界
    • 实体

      • 有唯一标识符

      • 重要的不是其属性,而是其标识符和延续性

      • 可以修改部分值

        • 需要通过聚合修改,而不是直接在数据库获取数据记录然后直接修改
      • 一般是实实在在看的着的业务对象,有业务属性、业务行为、业务逻辑

    • 值对象

      • 没有唯一标识符
      • 通过属性来标识,本质就是一个属性的集合
      • 不能修改内部值,只能整体替换
      • 只是作为一个修饰的属性集合,初始化完了就再也不变,不包含业务逻辑
      • 还可以将实体是数据作为值对象存储,起到快照的作用
    • 聚合

      • 聚合之间也是有上下文边界的,只是这个边界比界限上下文的边界小

      • 聚合之间是松耦合的,需要避免互相调用,可以通过在应用服务层实现互相调用。

      • 如何判断是否是聚合根

        • 是否有独立的生命周期
        • 是否有全局唯一ID
        • 是否可以修改其他对象
      • 我们一般在一个聚合之内使用事务保证强一致性,在聚合之间只需要保证最终一致性,用以达成松耦合

    • 仓储模式

      • 值对象在序列化时,可能为了简化,存在实体表里,有两种存储形式

        • 直接序列化成json存一个字段
        • 没个字段也作为单独的字段存储在实体表里
      • 仓储模式主要完成领域对象的持久化,用来隔离数据库实现,类似DbService,其中DbService接口属于领域层,DbServiceImpl属于基础层

      • 仓储服务使用的是PO数据,而由DO转PO是由工厂模式实现。

    • 工厂模式

      • 工厂模式主要完成领域对象的创建和初始化,如果领域对象的初始化简单的话,也可以放在聚合根里完成
      • DO和PO互转的工作,也是由工厂完成,因为这也属于创建对象的一部分。
      • 引入工厂的核心原因就是,让聚合能够聚焦业务逻辑,将创建对象这种通用能力单独剥离
    • 领域事件

      • 如果某个事件的发生,会进一步触发业务动作,那这个事件就很可能是领域事件
      • 如果事件不允许丢失,则事件在发送之前,也需要持久化到数据库中。这也就是我们常用的本地事件表模式。
  • 流程

    • 明确主题、 产品愿景

    • 领域建模(横向)

      • 方法

        • 事件风暴

          • 步骤

            • 根据所有角色的使用场景,确定所有的流程

            • 罗列出领域中的所有事件,标注出导致该事件的命令

            • 对事件进行分类,整理出实体、聚合、聚合根以及界限上下文

              • 需要考虑依赖关系,截断循环依赖
          • 关键点

            • 业务的通用语言中,一般名词就是领域对象,动词就是命令或者领域事件

            • 事件风暴的本质是由底向上归纳,既先摊开所有细节,再一层一层归纳总结,是一个从发散到收敛的过程

            • 有时在迭代过程中新增的领域逻辑,可以单独作为一个副领域单独拆出来,而不一定要将原先的领域模型改的更通用来进行适配,可以等副领域的逻辑稳定后,再进行重构

              • 这就相当于利用动静分离的原则,而不是单独的DDD
      • 交付件

        • 完成后,所有横向的子域、聚合都得到了划分,甚至还有实体的关键参数等等

战术设计

  • 服务识别和设计

    • 方法

      • 将命令作为服务设计的起点,然后按分层架构进行每层的内容设计,既在横向划分好的结构中补充纵向内容

        • 横向的代码耦合,不用开方法实现,直接看方法定义以及类的字段就能看到,因为代码实现里的调用,肯定是靠注入的服务或者入参来获取引用,这些地方不能发生耦合。

        • 纵向的分层不清,需要根据具体实现来判断,因为像实体会在所有层次作为参数传递,但是在应用层最好不要调用多个实体的方法,这个只能通过查看方法实现,光看定义看不出来

        • 实际代码设计时,有的时候很难做到分层那么清晰,而且会引入过多的封装,此时要注意权衡,核心的原则还是在保证数据一致性等功能特性的情况下,做到高内聚低耦合

          • 一个简单的判断依据,就是这个代码是不是在任何地方看起来都很好演进,比如流程的逻辑不会出现在领域层。
    • 交付件

      • 在按命令进行服务设计时,会得到各层服务,以及完善聚合内的方法。
  • 分层架构(纵向)

    • 结构

      • 用户接口层

        • 主要完成前后端分离,进行前段数据和接口的适配

        • 主要模块

          • facade
          • assembler
          • dto
      • 应用层

        • 主要职责是协调多个聚合间的编排和组合

        • 微服务间的调用只能在应用层

        • 易变的如流程、业务组合、编排的业务需求放在应用层,但是不要将领域逻辑放在应用层,会导致应用层失焦

        • 主要模块

          • 应用服务

            • 服务、聚合的组合编排
            • 权限、事务、安全等非业务逻辑
            • 结果拼装
            • 应用层因为跨微服务调用,也有可能会与dto和assembler模块
          • 事件发布和订阅

      • 领域层

        • 主要实现领域模型的核心业务逻辑

          • 此处的业务逻辑主要是指聚合自身的原子业务逻辑,不是用户操作或者流程等方面的业务逻辑
        • 一般是不变的核心逻辑,才下沉到领域层,要区分好易变的业务逻辑,和不变的核心逻辑。

        • 一般涉及一个实体的业务逻辑,在实体内部实现,涉及多个实体的,在聚合根或者领域服务中实现

        • 主要模块

          • 工厂
          • 聚合根以及其他实体
          • 领域服务
      • 基础层

        • 主要提供通用技术和基础服务

        • 基础层在传统4层架构里是被所有层依赖,在新4层架构里,是依赖所有层,本质就是多加了一层接口做依赖倒置而已,没有逻辑上的改变

        • 主要模块

          • 仓储服务
          • 缓存、网关等
    • 关系

      • 严格分层和松散分层的区别在于,严格分层中,任何层只能与直接依赖层发生依赖

        • 遵循严格分层,既是清晰层间的职责,更是方便以后一个微服务拆分成多个微服务时,聚合可以方便的拆分成微服务
        • 在查询类的接口中,允许应用层直接调用基础层,通过sql实现高性能,因为此时也没有太多业务逻辑需要下沉。
      • 当任何层次出现重发代码时,就要考虑重组并下沉能力

      • 有时候两层的功能一定要放在一层处理时,关键是要考虑其主要能力是否是需要下层。比如装配数据时还校验数据,此时放在应用层会比放在用户接口层好一点,因为需要把校验能力沉淀下来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值