Hefery 的个人网站

Hefery's Personal Website

Contact:hefery@126.com
  menu
73 文章
0 浏览
2 当前访客
ღゝ◡╹)ノ❤️

DDD与分层领域模型

DDD

DDD发展情况

  1. 2003年《领域驱动设计》Eric Evans正式提出 DDD 《领域驱动设计精简版》
  2. 2013年《实现领域驱动设计》Vaughn Vernon 发展领域事件、六边形架构战略设计
  3. 2013年 Alberto Brandolini 事件风暴建模法

DDD相关概念

模型:对领域的抽象和模拟
建模:针对特定问题(超市、电商)建立领域的合理模型

软件系统复杂来源:领域 -(建模)-> 模型 -(设计+技术)-> 代码

  • 业务本身的复杂性:
    钱:币种 + 数量
    人民币:编号 + 面额 + 版本
    钞票:编号 + 面额 + 版本 + 形状 + 颜色 + 图案 + 重量 + 防伪标签
  • 设计实现引入额外复杂性:

DDD核心思想

  • 模型分解
    • 领域划分 Subdomain
    • 限界上下文 Bounded Context
  • 模型驱动设计(Model Driven Design)
    通过分层架构隔离领域层、仔细选择模型和设计方案等措施保持实现与模型的一致

DDD易混淆点

DDD与面向对象

面向对象:

  • OOAD:object oriented analysis and design,面向对象分析与设计(与DDD同一层)
  • OOP:object oriented programing,面向对象编程(为DDD所依赖)

DDD与OOAD联系和区别:

  • 联系:
    • 都是建模和设计的思想
    • 部分建模方法和工具可复用
  • 区别:
    • OOAD 没有战略设计;DDD 通过战略设计划分领域和模型
    • OOAD 仅用对象描述世界;DDD 的描述更细致

DDD与敏捷开发

  • 联系:
    • 都是软件工程领域的思想,解决软件工程中的不同问题,一般可结合应用
  • 区别:
    • 敏捷:关注流程和文化;DDD:关注建模设计方法
    • 敏捷:重人员轻文档;DDD:重视统一语言的建立

DDD战略设计

用户故事

描述模型

  • 问题空间的描绘:who + what + why,As a role, I want to action (so thst benefit)
  • 文字表述
  • 讨论+图形表达

通用语言

  • 在讨论模型和定义模型时,团队使用的同一种语言(商品-sku 订单-order 支付-payment)
  • 领域知识需要在团队内部高效流转,模型需要描述
  • 通用语言要体现在代码里

战略设计

DDD中对问题空间和解决方案空间进行分解的过程,目的是分解模型以控制复杂性

领域划分

进行分工协作而非基于需求,以分离关注点为原则对问题空间的划分

  • 子域:领域中某个方面的问题和解决它所涉及的一切
    • 核心域:交易域 + 运营域
    • 通用子域:商品域 + 支付域
    • 支持子域:用户域
  • 精炼:将子域再细化为核心域、通用子域、支持子域
限界上下文(BC)

划分限界上下文

  • Domain Storytelling 领域故事陈述法

    • 边界特征
      • 单向联系
      • 语义区别
      • 活动触发方式不一样
  • Event Storming 时间风暴法

  • 基于子域概念提取

确定上下文映射

上下文映射:指限界上下文之间的模型映射关系。即上下文间的协作。描述团队之间的协作关系以及上下文之间的集成关系。如:交易上下文=商品+订单+支付+物流

上下文映射模式

  • 开放主机服务:服务提供方为所有消费方提供一套公共的API,针对通用的功能和模型
    • 微信支付上下文(UpStream) --> 商城支付上下文(DownStream)
  • 顺从者:没有模型到模型的转换,一个上下文沿用另一个上下文的部分模型
  • 大泥球:由混杂的模型构成的糟糕系统,模型不稳定且难于维护
    • 微信支付上下文(UpStream) --> 商城支付(DownStream)<-- 支付宝支付上下文(UpStream)
    • 与大泥球合作的上下文要确保自身不被污染,设置防腐层
  • 防腐层:
    • 把上游上下文的模型转换成自己上下文的模型
    • 是下游上下文中访问外部模型的一个代理层
  • 共享内核
    • 两个上下文共享部分模型
    • 包括但不限于代码、jar包、.so、数据库表等
    • 慎用,仅当团队紧密合作且共享部分稳定
  • 合伙人
    • 技术无关,是一种团队协作关系
    • 两个团队之间可以随时互通有无,协同变更
  • 客户/供应商
    • 下游上下文可以向上游上下文提需求
    • 一般用于核心域与非核心域之间的协作
  • 分道扬镳
    • 两个上下文无协作,各自独立
    • 当两个上下文之间的集成成本过高
  • 公开语言
    • 标准化与协议化的模型
    • 所有上下文都可以与公开语言中的模型进行转换
    • 对接了公开语言的上下文之间可以实现组件化对接

战术设计

  • 对各个BC的细节设计过程
  • BC内部的模型结构与完整技术方案
领域分层

传统DDD分层模型

  • 接口层 Interface
  • 应用层 Application
  • 基础设施层 Infrastructure
  • 领域层 Domain

洋葱分层模型:

  • 适配层 Adapter
  • 应用层 Application
  • 基础设施层 Infrastructure
  • 领域层 Domain
领域事件

领域事件:领域中发生的任何领域专家(运营人员、管理员、用户)感兴趣的事情,领域事件一般由聚合产生

领域事件基本属性

  • 事件命名:OrderCancelEvent
  • 事件ID
  • 产生时间

发布和订阅方式

  • 外部系统:API定向通知、API定时拉取、消息队列
  • 内部系统:观察者模式、数据库流水、消息队列

领域事件的存储

  • 直接使用消息中间件的存储:冗余机制 + 做好备份
  • 基于数据库:分布式 + 按时间分区

事件处理的要求

  • 顺序性:聚合ID + 存储分片 + 消费分组
  • 幂等性:用幂等性代替分布式事务,状态判断或去重

建模方法

  • Domain Storytelling(领域故事陈述法)
  • Event Storming(事件风暴法)
  • 4C(四色建模法)

分层领域模型

分层领域模型简介

开发中,我们习惯项目或系统横切为表现层-业务逻辑层-数据访问层

优点:

  • 解耦:系统越大、需求变化快,就越需要保证程序间的依赖关系越少,分层使我们更容易应对
  • 降低维护成本和升级成本
  • 代码或逻辑复用

阿里开发手册中,建议使用的应用分层

  • 终端显示:各个端的模板渲染并执行显示,如前端 JS 渲染,移动端展示
  • 开放接口:
    • 可直接封装 Service 方法暴露成 RPC 接口
    • 通过 Web 封装成 HTTP 接口
    • 进行网关安全控制/流量控制等
  • Web:主要对访问控制进行转发,各类基本参数校验,或不复用的业务简单处理
  • Service:相对具体的业务逻辑处理
  • Manager:通用业务处理层
    • 对第三方平台封装的层,预处理返回结果及转化异常信息
    • 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理
    • 与 DAO 层交互,对多个 DAO 的组合复用
  • DAO:数据访问层,与 MySQL、Oracle、Hbase 等进行数据交互
  • 外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口

细分层级仅是为了满足业务需要。千万不要为了分层而分层。过多的层会增加系统的复杂度和开发难度

经典分层领域模型

  • DO:Data Object,与数据库表结构对应,通过 DAO 层想上传输数据源对象
  • DTO:Data Transfer Object,数据传输对象,Service 或 Manager 向外传输的对象
  • BO:Business Object,业务对象,由 Service 层输出的封装业务逻辑的对象
  • AO:Application Object,应用对象,在 Web 层与 Service 层之间抽象复用对象模型
  • VO:View Object,视图层对象,通常是 Web 向模版渲染引擎层传输的对象
  • Query:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数查询封装,禁止使用 Map 类传输

BO、AO、DTO的界限不是非常明确。这也是因为系统处理的业务不同、复杂度不同导致的。所以在设计系统分层和建模的时候,需要综合考虑实际应用场景

根据业务和习惯使用不同的 Bean:

  • POJO:Plain Ordinary Java Object,简单 Java 对象,提供对应的 getter/setter
  • JavaBean,可序列化(持久化)的 POJO
    具有空构造函数
    所有属性为私有属性,,不应该有公共属性,提供 getter/setter 向外提供访问和操作私有属性的方法
    实现序列化接口:java.io.Serializable
  • PO:Persistent Object,持久化对象,主要用于持久化层,与数据库对应,通常也是 ORM 中的实体,如,使用 JPA 时的 Entity 与数据库表做映射,通常是一个 JavaBean,和阿里规定的 DO 相同作用
  • DAO:Data Access Object,数据访问对象,与数据库交互的对象,提供不同的接口访问数据库来实现对数据库的操作,而接口使用的数据交互通常是 PO 或 DO,通过它可使用面向对象的方式来与数据库交互
对象含义层级业内命名阿里规约个人习惯
视图层对象视图层AdapterVOVOVO
数据传输对象应用层ApplicationDTODTODTO
数据存储对象基础设施层InfrastructurePO(Persistent Object)DO(Data Object)DO
领域对象领域层DomainDO(Domain Object)BO(Business Object)领域通用名

分层领域模型转换

考虑点:

  • 原对象和目标对象相同属性类型或名称不一样
  • 集合类属性中的泛型不一样
  • 能不能只复制部分属性
  • 能不能自定义转换逻辑
  • 嵌套对象是深拷贝还是浅拷贝

标题:DDD与分层领域模型
作者:Hefery
地址:http://hefery.icu/articles/2022/04/05/1649088010763.html