zoukankan      html  css  js  c++  java
  • 【系统架构理论】一篇文章搞掂:领域驱动设计

    一、什么是领域驱动设计

    1.1、面向业务的设计

    当我们需要构建一个业务复杂的系统,我们不仅要从技术角度去构建一个稳健的系统,还要从业务角度出发,保证系统能满足业务需求。

    架构设计的考虑点:不仅面向技术,更应该面向业务;面对不同的业务复杂度,选择的架构可能不同。

    架构师的工作:面对复杂的业务逻辑,需要整合业务和技术才能很好地解决。业务架构驱动技术架构。

    一个典型开发团队:新手、中级开发者、高级开发者/架构师(技术架构)、领域专家/产品经理(业务架构)、项目经理

    要解决的问题:将复杂的业务架构梳理好,并能为技术架构的设计提供要求或指导。

    总结:要进行一个业务复杂系统的架构设计,我们要将技术架构和业务架构整合起来。

    1.2、使用领域驱动设计,让业务架构和技术架构能整合起来

    既然业务对系统架构有影响,那么如何能将业务语言转化为对技术架构设计有指导意义的信息?

    其中一种方法就是领域驱动设计。

    领域驱动设计:Domain Driven Design(DDD),一种软件开发的方法学

    • 强调开发人员与领域转件协作,交付业务价值
    • 强调业务高层次方向
    • 强调系统建模工具和方法,以满足技术需求

    领域:一个组织的业务开展方式,体现业务价值。

    例如:电商网站中的产品、订单、发票、库存、物流;保险公司的保险单、理赔、再保险等。

    业务价值:有用的领域模型、抽象的业务定义、更好的用户体验、清晰的模型边界;目的是指导开发出优秀的技术架构。

    如何使用DDD:

    1、业务专家以通用语言准确传达业务规则给开发人员

    2、开发人员根据业务规则进行设计模型的设计

    3、再设计代码模型以满足设计模型的需求

    最终目标:能体现系统业务,又能指导代码开发的一个模型;将设计模型和代码模型很好地结合起来。

    通用语言(Ubiquitous Language):

    • 团队成员的行话
    • 面向业务
    • 表现形式:术语表、文档和图、模型语言。。。
    • 面临的挑战:领域专家持续不断介入、开发者对领域的思考方法

    综上,我们可以考虑领域驱动设计的设计纬度,从2个方面来看领域驱动设计

    设计的策略:

      关注如何设计领域模型以及对领域模型的划分

    • 领域/子域
    • 通用语言
    • 界限上下文
    • 架构风格

      用于清楚界分不同的系统和业务关注点

    设计的技术:

      关注技术实现的层面教会我们如何具体地实施DDD

    • 实体/值对象
    • 领域服务
    • 领域事件
    • 资源库

      基于技术设计工具按照领域模型开发软件

    总结:我们为使业务能指导架构开发,将业务架构与技术架构整合起来,提供的一种解决办法是领域驱动设计,并提出了领域驱动设计的实现策略和实现技术。

    1.3、实现领域驱动设计的思路

    • 提供一套通用的建模语言和术语
    • 展示基于领域趋同的架构设计方法
    • 展示实现领域驱动设计的各项关键技术
    • 基于具体案例展示设计的策略和技术

    二、领域与上下文

    2.1、架构的轮回

    领域(Domain):

    • 一个组织所做的事情以及其中所包含的一切内容
    • 业务范围及所进行的活动
    • 开发某个软件时,面对的就是组织的领域

    领域模型(Domain Model):

    针对整个业务系统创建的模型

    有2种建模方式:

    单一、内聚、全功能式:现在的系统越来越复杂,这种形式容易进入难以维护的境地。

    功能拆分、服务化、子域:架构更简单更容易维护;适合分布式计算;现在越来越流行,如微服务

    架构的迭代与轮回:

     

    我们希望在第4步之前就要将架构简单化,避免到了不可维护的程度

    复杂系统的简单化:功能拆分

    拆分关注点:核心功能、辅助功能、第三方功能

    拆分后的功能组装:系统集成

    功能拆分在领域驱动设计的表现:

    拆分关注点:子域

    功能组装:界限上下文

    2.2、领域/子域/界限上下文

    子域分类(一个常见分类):

    • 核心域:核心业务
    • 支撑子域:专注于业务的某一方面
    • 通用子域:用于整个业务系统

    界限上下文:

    • 领域存在于界限上下文中
    • 每个模型概念、属性和操作,在边界之内有特殊含义
    • 同一个名称的模型,如User,在不同接线上下文中,是不同的

    拆分上下文的策略:几个可以考虑的角度

    • 根据业务/通用语言(合适)
    • 根据技术架构(不建议)
    • 根据开发任务分配(不建议)
    • 一个团队一个上下文(合适)

    2.3、子域划分案例

    以一个项目计划系统作为例子,阐明如何进行子域的划分

    项目计划系统的需求:

    • 系统完成对某个项目任务的分解
    • 系统的目的是项目计划的制定
    • 计划的制定通过召开项目会议的方法进行
    • 项目会议的与会人员需要确保身份的有效性

    讲解思路:

    • 假想业务流程
    • 围绕领域驱动设计的理念和实践
    • 从策略的设计到技术的设计
    • 层层剖析和演进

    初步上下文拆分:

    2.4、组织和集成模式

    大泥球风格(Big ball of mud):

    实践中比较常见,把所有代码都混合在一起,随着业务复杂,逻辑堆积,导致结构不清晰,边界模糊

    改进:拆分后集成

    高层次的架构分析:上游(Upstream)下游(Downstream):

    集成的关注点:

    • 上下文之间的关系如何(谁是上游谁是下游)
    • 不同开发团队之间的关系如何

    团队之间的关系:组织和集成模式

    • 合作关系:共同成败
    • 共享内核:共享内核显式边界和小型化
    • 客户方/供应方:上游/下游,下游受上游影响巨大;主流模式但不是最好模式
    • 遵奉者:上游无推动力,下游只能妥协或另谋他路
    • 上面几种不属于较好的方法,以下是比较好的方法
    • 防腐层(Anticorruption Layer):下游客户根据领域模型创建单独一层(可以理解为门面?或适配模式?)
    • 开放主机(Open Host):定义协议,让别人通过协议访问(如RESTful风格)
    • 发布语言(Published Language):共享语言完成集成交流(如发布对应API文档)

    2.5、领域模型的上下文集成技术

    一般领域模型中较常用的集成技术是以下几种

    开放主机服务:

    • 上游上下文提供
    • REST

    发布语言:

    • 上游上下文提供
    • XML/JSON/...
    • 消息事件

    防腐层:

    • 下游上下文提供

    2.6、案例中的上下文

    集成的关注点:

    • 上下文之间的关系如何(谁是上游谁是下游)
    • 不同开发团队之间的关系如何

    集成分析:

     

    使用到的组织和集成模式:

    • OHS:开放主机
    • PL:发布语言
    • ACL:防腐层

    三个子域的集成关系:

     

    • 【用户权限上下文】是【项目核心上下文】【计划讨论上下文】的上游;
    • 【计划讨论上下文】是【项目核心上下文】的上游;
    • 上游使用【开放主机】和【发布语言的】组织和集成模式
    • 下游使用【防腐层】的组织和集成模式

    三、领域驱动架构

    3.1、传统分层架构

    一般领域层只包含接口,由其他层去实现。

    问题:

    • 领域层如何和其它层进行耦合

    解决思路:依赖倒置

    依赖倒置: 

      • 高层不应该依赖于低层,2者都应该依赖于抽象
      • 抽象不应该依赖于细节,细节应该依赖于抽象
      • 编程应该面对抽象,低层实现和高层实现互相独立,改变不会对系统做成影响,而且由于低层独立,可以进行更好的复用。
    • 领域层的服务接口谁去实现

    应用层和基础设施层进行实现

    当我们使用领域驱动架构时,使用了依赖倒置原则,希望面向领域面向抽象编程,使原来的分层架构变得模糊,不在存在严格的分层概念。

    这个时候,有一种更加适合领域驱动架构的编程架构模式:平面型架构

    3.2、平面型架构(重要的架构)

    领域驱动架构推崇编程架构风格

    原因:

    • 系统依赖复杂的领域模型,领域模型应该放中间被其它模块依赖
    • 有界限上下文,需要和其它服务交互
    • 分层架构不太容易实现

    平面型架构:

     

    基础架构:

    • 由内而外围绕领域模型展开
    • 应用程序包含业务逻辑

    适配器:

    • 多种适配器
      • 数据持久化
      • 数据集成
    • 面向结构和Mock机制

    3.3、SOA架构

    根据适配器的不同形成不同的架构风格

     

    3.4、RESTful风格架构

     

    4、命令查询职责分离模式CQRS

    Command Query Responsibility Segregation

    传统数据操作:

    CQRS:

    解决领域数据和界面显示的匹配:

    5、事件驱动架构EDA

    Event-Driven Architecture

    6、领域驱动设计的策略设计

    这里讲解实现领域驱动设计的策略,并通过一个案例作为展示

    策略设计的内容包括:

    • 通用语言:使用通用语言描述出业务需求
    • 领域/子域:对系统进行领域划分
    • 界限上下文:对领域的边界进行划分,并确认界限上下文之间如何交互
    • 架构风格:使用平面型架构,是否使用CQRS/EDA

    案例策略设计的思路:

    • 领域/子域:
      • 核心域的名字和目标是什么?
      • 核心域包含哪些概念?
      • 核心域的支撑子域和通用子域是什么?
      • 核心如何与其他子域进行写作和集成?
      • 如何针对各子域安排人员?

    策略设计的一个参考:

    Core核心域

    7、领域驱动设计的技术设计

    当我们的策略设计完成后,需要关注技术层面,思考如何使用技术来实现这些策略。

    7.1、实体与值对象

    关于对象:

    • 数据对象:面向数据库
      • 数据驱动(Data-Driven)设计
      • 开发者关注数据的属性和关联关系
    • 实体对象:面向领域
      • 领域驱动(Domain-Driven)设计
      • 很多对象不是通过他们的数据属性定义
      • 实体具有一系列标识和行为定义
    • 普通的开发者趋向关注数据而不是领域

    实体:

    • 有唯一标识
    • 具有可变性

    唯一标识策略:

    • 用户提供初始唯一致
      • 用户通过界面输入,系统判断是否重复,重复则不允许创建实体
    • 系统内部自动生成唯一标识
      • UUID
      • 根据时间/IP/对象标识/随机数/加密
      • 第三方框架,如Apache Commons Id
    • 系统依赖持久化存储生成唯一标识
      • Oracle的Sequence
      • Mysql的自增列
      • 尽早标识/延迟标识
    • 来自另一个上下文(不推荐使用)
      • 从外部系统查找、匹配和赋值唯一标识
      • 需要考虑对象同步
      • 可以通过时间驱动架构和领域事件解决同步问题

    推荐通过内部系统提早生成

    贫血模型和充血模型:

     

    贫血模型:

    • 优点:
      • 系统层次结构清楚,各层之间单相依赖,领域对象几乎只用作传输介质用,不会影响到各层次划分。
    • 缺点:
      • 不够面向对象,领域对象只是作为保存状态或者传递状态用,只有数据没有行为的对象不是真正的对象,在Business Logic里面处理所有业务逻辑,对于细粒度的逻辑处理,通过一层Facade达到门面包装的效果。
      • Business Login层比较庞大,边界不易控制,内部的各个模块之间的依赖关系不易管理。

    充血模型:

    • 优点:
      • 面向对象,Business Logic符合单一职责,不像贫血模型里面那样包含所有的业务逻辑太过沉重。
      • 每一个领域模型对象都可以具备自己的基础业务方法,通常满足充血模型的特征。
      • 充血模型更加适合较复杂业务逻辑的设计开发。
    • 缺点:
      • 如何划分业务逻辑,逻辑应该正确放到Domain Object和Business Logic比较困难

    值对象Value Object:

    • 当只关心对象的属性时,该对象应归为值对象
    • 值对象是不变对象
    • 值对象没有唯一标识
    • 值对象具有较低的复杂性

    cusetomer为实体,address为值对象

    值对象的特征:如何分离值对象

    • 度量或描述领域中的一个部分
    • 可以作为不变量
    • 将不同的相关属性组合成一个概念整体
    • 当度量或描述改变时,可以以另一个值对象予以替换
    • 可以和其他值对象进行相等性比较
    • 不会对协作对象造成副作用

    值对象的应用:

    • 上下文集成
    • 表示标准类型

    值对象的实现:

    • 只用构造函数
    • 不用setter方法

    建模:使用通用语言

    • 识别实体
    • 挖掘实体关键行为
    • 识别值对象
    • 构建概念整体

    建模例子:

    实体与值对象的区别:

    • 从标识的角度
      • 实体有唯一标识,值对象没有唯一标识,不存在这个值对象或那个值对象的说法
    • 从是否只读的角度
      • 实体可变;值对象只读
    • 从生命周期的角度
      • 实体具有生命周期,而值对象无生命周期可言,因为只是一个值,依附于某个具体实体

    7.2、领域服务

    背景:

    • 现实中的事物:
      • 有些操作是一系列活动或动作,不是单个事物,概念上并不属于任何对象
      • 建模的基本表现范式是对象,单一些领域概念不适合建模成实体或值对象
    • 我们的思路:
      • 当领域中某个重要的过程或转换操作不属于实体或值对象的职责时,应该在模型中添加一个作为独立接口的操作,既领域服务(Comain Service)

    领域服务区别于其它服务:

    • 应用层:资金转账应用服务
      • 获取输入
      • 发送消息给领域层服务并监听确认消息
      • 决定使用基础领域层服务发送通知
    • 领域层:资金转账领域服务
      • 与Account和Money等对象进行交互,执行相应的借入和贷出操作,提供结果的确认
    • 基础设施层:发送通知服务
      • 按照应用程序的指示发送电子邮件等信息

    领域服务区别于实体和值对象:

    • 执行一个显著的业务操作过程
    • 以多个领域对象作为输入进行计算,结果产生一个值对象
    • 对领域对象进行转换

    2、领域服务建模

     

    3、依赖注入模式

     

    领域事件

    以前这个东西没有或不常用,系统复杂度上升后出现

    同等地位 实体、值对象、领域服务、领域事件

    1、领域事件

    2、领域事件建模

     

     

    3、领域事件实现

    代码演示事件订阅者

    代码演示事件存储

    4、事件转发

     聚合

    用于理清边界

    1、聚合

    简化对象


    2、聚合建模

    3个都是聚合

     

    资源库

    1、资源库


    2、资源库实现

     

     

    代码演示

    集成界限上下文

    1、系统集成基础

    2种策略

     

     

     消息中间件

    应用程序

     

     

    这里比较重要,领域模型只定义接口,基础设置实现,然后由应用程序通过依赖注入来组装?

    上面讲解了策略设计,技术设计

    下面讲解实例

     1、案例分析
    2、技术设计

    领取驱动架构项目实例

    1、代码系统结构

    使用自动化构建工具:Maven

    Common是通用组件,和业务无关。

    其它几个领域依赖Common组件,但是领域之间在Maven层面没有依赖关系。

    代码结构:

    通过一个父pom管理4个模块,其中3个领域模块依赖Common模块。

    2、Common组件

    封装一些通用的工具,或基类等,可以自行积累

    通用工具类组件:

    • DomainModelBase:领域对象基类
    • Assertion:判断工具,用于进行判断操作,如果判断为假,则抛出IllegalArgumentException或IllegalStateException异常
    • Event/EventStore:事件以及事件存储方案
    • CommonUtil:通用工具
    • PersistenceUtil:持久化工具,抽象持久化
    • RestUtil:封装一些第三方工具
    • SerializationUtil:序列化工具
    • SpringUtil:Spring框架工具类

    Event

    • DomainEvent
    • DomainEventPublisher
    • DomainEventSubcriber

    Serialization

    Json

    Gson

    FastJSON

     

    EventStore

    StoredEvent

    EventStore

    EventSerializer

    MySQLJDBCEventStore

    3、Core上下文

     

  • 相关阅读:
    团队冲刺--第二阶段(五)
    团队冲刺--第二阶段(四)
    团队冲刺--第二阶段(三)
    团队冲刺--第二阶段(二)
    团队冲刺--第二阶段(一)
    第一阶段意见评论
    人月神话阅读笔记02
    基础-定位
    基础-颜色
    标准文档流
  • 原文地址:https://www.cnblogs.com/LiveYourLife/p/9342566.html
Copyright © 2011-2022 走看看