领域驱动设计-架构篇

news2025/7/27 4:00:38

目录

1、软件架构概述

1.1 软件架构概念

1.2 软件架构分类

1.3 软件架构模式

1.4 软件架构风格

2、领域驱动软件架构

2.1 架构风格

六边行架构(领域驱动设计首选)

为什么选择REST架构

松耦合

可伸缩性

易用性

约束性

2.2 架构模型

命令和查询职责分离(CQRS)


大家好,我是老王随聊。筹备了一周之久的架构篇终于出炉了……

前面我们介绍了关于领域驱动设计业务战略层面的几个概念:领域、子域、界限上下文以及界限上下文映射图。那接下来我们要知道如何基于技术战略层面进行领域驱动软件架构设计。本篇主要内容包含两部分:软件架构概述和领域驱动软件架构。

下图是从软件架构层面整理的DDD架构图(完善中)。

在开始讲领域驱动架构之前,我们需要先了解关于软件架构的一些常见架构风格和模型,因为这些内容也将会在领域驱动设计中使用到,便于我们更好的了解这些架构模型在领域驱动中应该如何发挥其价值,如何集众所长。另外,即便是领域驱动设计这种新的方法论,在技术层面也依然采用现有的一些常见设计架构思想,无非就是新瓶装旧酒,关键在于酒怎么装的问题。

1、软件架构概述

1.1 软件架构概念

在软件工程领域,“架构”主要是指软件架构,其主要目的在于指导架构师和开发人员如何进行软件设计,也就是为我们提供软件系统各个方面的设计方向。

软件架构,并不是指可编码能实际落地的文档,而是一个系统的草图​。它的主要工作是对一系列相关业务的一种抽象建模,把各种对象抽象成可直接构成系统应用的组件,并对各组件之间如何映射、如何通信进行了明确且细致的描述。最终,在实现编码阶段,这些抽象组件将被细化为具体的某个类或者对象。

那在领域驱动设计中,除了我们看到的软架构外,还隐含着另外一种架构—即业务架构。该业务架构的设计思想将伴随着整个业务系统的生命周期,关于业务架构方面的内容我在后面的文章会讲到。

1.2 软件架构分类

通常一个良好的软件架构,需要具备以下特性:可靠性、安全性、扩展性、可定制化、可伸缩、可维护、易用性和市场机制这八个特点,不同的软件架构模式侧重的特点不同。

从我们日常所关注的角度来看,大体可以分为三类:逻辑架构、物理架构和系统架构。

逻辑架构指的是软件系统中元件之间的关系。比如常用的分层架构就是一种逻辑架构,每一次包含多个逻辑元件;物理架构通常是指软件系统在硬件上的部署方式。比如微服务架构、垮机房垮区域的分布式架构等;系统架构指的是系统非功能性特征,比如云架构,考虑系统的稳定性、可扩展等。

1.3 软件架构模式

从软件架构模式角度看,大致可以划分为:分层模式(常用的标准架构)、客户端/服务模式、事件总线模式、管道和过滤器模式、微核模式、微服务模式和云模式等;

分层架构,将软件分成若干个水平层,每一层都有清晰的角色和分工,不需要知道其他层的细节,层与层之间是通过接口通信;

事件驱动架构,就是通过事件进行通信的软件架构,主要用于系统之间解耦或异步任务处理;

微核模式,也叫插件模式,指的是软件的内核相对较小,主要功能和业务逻辑都通过插件实现,主要用于提升系统组件单元的可插拔性;

云架构,主要解决系统的扩展性和并发的问题,是最容易扩展的架构;

管道和过滤器模式,是面向数据流的软件体系结构,其优点将整个系统的输入输出行为理解为单个过滤器行为的叠加与组合,目的在于将复杂问题分解,做到化繁为简的效果。

1.4 软件架构风格

从架构风格的抽象纬度划分,常见的分布式应用架构风格有以下三种:

分布式对象(简称DO),它要解决的主要问题是位于不同进程中的对象之间的调用问题,常见的架构实例有CORBA、RMI、EJB、DCOM、NET Remoting等。

远程过程调用(简称RPC),远程过程调用采用客户机/服务器(C/S)模式。请求程序就是一个客户机,而服务提供程序就是一台服务器。和常规或本地过程调用一样,远程过程调用是同步操作,在远程过程结果返回之前,需要暂时中止请求程序。使用相同地址空间的低权进程或低权线程允许同时运行多个远程过程调用。常见的架构实例有SOAP、XML-RPC、Hessian、DWR等。WEB服务提供一个分布式函数或方法接口供用户调用,这是一种比较传统的方式。通常,在WSDL中对RPC接口进行定义(类似于早期的XML-RPC)。

表述性状态转移(简称REST),WEB服务类似于HTTP或其他类似协议,它们把接口限定在一组广为人知的标准动作中(比如HTTP的GET、PUT、DELETE)以供调用。此类WEB服务关注与那些稳定的资源的互动,而不是消息或动作。此种服务可以通过WSDL来描述SOAP消息内容,通过HTTP限定动作接口;或者完全在SOAP中对动作进行抽象。架构实例有HTTP、WebDAV。

不同架构模式和风格会之间有非常大的差别。这里暂且不聊对比差异,先了解在领域驱动设计该如何使用这些架构模式和架构风格。

2、领域驱动软件架构

2.1 架构风格

六边行架构(领域驱动设计首选)

我们知道,六边形架构是一种对称性的架构风格,其原理采用了端口适配器模式。其目的在于构建一种持久生命力的架构,各端口之间是一种平等方式与系统交互,是内部和外部的关系,不存在前端和后端严格划分的概念。六边形架构如下图所示。
 

那为什么领域驱动设计会将六边形架构作为首选?

核心原因在于,领域驱动设计与传统的分层架构相比,其希望我们将重点的工作放在领域层设计上。领域层、基础设施层只依赖由领域模型所定义的抽象接口,而客户层是一种平等的方式与业务模型进行交互。因此与传统风层结构相比,其采用了依赖倒置原则。以上的交互和依赖倒置正好与六边形架构,所以这才是真正选择六边形架构的原因。

当然,如果你的项目采用了领域驱动设计的方式,不一定必须采用六边形架构,具体采用哪种风格需要我们在做架构设计前,从性价比通盘考虑后再选择。

另外需要注意的一点,即使你的系统采用了六边形架构,那同时也依然可以在六边形架构内部使用其他类型架构。比如SOA架构、REST或者事件驱动架构,也有可能采用CQRS;或者数据网织或基于网格的分布式缓存;还有可能采用Map- Reduce这种分布式并行处理方式。六边形架构可为系统其他架构提供坚实的基础支撑,这也体现了六边行架构很好的包容性。

为什么选择SOA架构

面向服务的体系结构​(SOA),是一个组件模型,它将应用程序的不同功能(即服务)通过服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种这样的系统中的服务可以以一种统一和通用的方式进行交互。

这里提到SOA架构,主要是与从六边形架构相比,它们都为领域驱动设计提供了共同的基础价值。

在SOA架构中,这8大设计原则依然适应六边形架构,而且有一部分特性对六边形架构进行了很好的补充。比如服务抽象、松耦合、服务重用性、服务组合性、服务契约、服务自治性、服务无状态性、服务可发现性,这些特性均可以与六边形架构进行很好的结合。在上图中,服务边界位于最左侧,而领域模型位于中心位置,消费方可以通过REST、SOAP和消息机制获取服务。

为什么选择REST架构

REST,表述性状态传递,属于Web架构的一种软件架构风格,REST也是web架构的理论扩展。它是一种针对网络应用​的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。

在了解领域设计驱动之前,要说明两点:

第一,REST并不是一种具体的技术,也不是一种具体的规范,而是一种内涵非常丰富的架构风格,一整套研究和评价软件架构的方法论,这套方法论的核心词在“架构风格”。

第二,架构风格是一种研究和评价软件架构设计的方法,它是比架构本身更加抽象的概念。一种架构风格是由一组相互协作的架构约束来定义的,而架构约束是对软件的运行环境施加在架构设计之上的一种约束行为,对架构进行更好的规范。

尤其是第二点,对于我们进行软件设计所起到的作用更大。

在三种主流的Web服务​实现方案中,因为REST模式的Web服务与复杂的SOAP​和XML-RPC​对比来讲明显的更加简洁,当前很多企业开发系统,越来越多的web服务开始采用REST风格设计和实现。

我们知道,在 REST 架构风格中,数据和功能被视为资源,并使用统一资源标识符 (URI) 进行访问。通过使用一组简单的、定义良好的操作来处理资源。客户端和服务器通过使用标准化的接口和协议(通常是 HTTP)来交换资源。另外,其资源是与表现形式进行分离的,以便可以以各种格式访问其内容,例如 HTML、XML、纯文本、PDF、JPEG、JSON 等。

​那REST在领域驱动设计中的作用是什么呢?依然是其与六边行架构所提供的共同价值所决定的,即松耦合、可伸缩和易用性。

松耦合

符合REST原则的系统具有更好的松耦合。通常来讲,添加新资源并在已有资源中创建到新资源的链接是非常简单的,要添加新的格式同样如此。REST API使用URI来进行资源的定位,所以这个URI需要直观并且容易使用。

可伸缩性

基于基于REST的系统也是非常容易理解的。因为此时系统被分为很多较小的资源模块,每一个资源块都可以独立测试和调试,并且每一个资源模块都表示了一个可重用的入口点。该架构本身具有很好的松耦合和可伸缩性。

易用性

采用REST架构风格,对于开发、测试、运维人员来说,都会更简单。可以充分利用大量HTTP服务器端和客户端开发库、Web功能测试/性能测试工具、HTTP缓存、HTTP代理服务器、防火墙。这些开发库和基础设施早已成为了日常用品,不需要什么火箭科技(例如神奇昂贵的应用服务器、中间件)就能解决大多数可伸缩性方面的问题。

约束性

另外,REST架构风格最重要的架构约束有6个:客户-服务器(Client-Server)、无状态(Stateless)、通信的会话状态(Session State)、缓存(Cache)、统一接口(Uniform Interface)、分层系统(Layered System)。这些特性对六边形架构也进行了很好的规范约束。

2.2 架构模型

我们前面提到,架构模式通常分分层模式(常用的标准架构)、客户端/服务模式、事件总线模式、命令和查询职责分离模式、管道和过滤器模式、微核模式、微服务模式和云模式等。从作者的视角,为什么要单独大篇幅去讲命令查询模式呢?这是我们需要重点关注的地方。

命令和查询职责分离(CQRS)

CQRS 是“命令和查询责任分离”的英文缩写,它是一种将数据存储的读取操作和更新操作分离的模式,类似于我们在数据库层面的读写分离。它主要解决了,在复杂系统中当多种读取形式和写入工作负载非对称,并且读写的性能要求有很大差异时,会倒置模型执行太多操作且过度复杂的问题。这样做的好处就是可以最大限度地提高系统的性能、可缩放性和安全性。

但CQRS这种模式在领域驱动设计当中是最优的吗?凡事都有两面性,固然优点需要借鉴学习,但也需要我们用批判精神来看待其不足。那CQRS在领域驱动设计中不好的一面也体现的会更明显。

第一,CQRS无法很好的解决事务性。

对于之前采用的单一数据源,我们通常依靠关系型数据库的事务特性能够很好的保证数据的完整性。但是在 CQRS 中这一切都发生了变化。因为在CQRS中一个 command 触发的事件,在 query 端可能需要更新很多个数据模型,而这是有可能失败的。一旦更新失败那么数据就会长时间的处于不一致状态,这时需要外部的介入单独处理。从事务的角度来看 CQRS,需要面对的是问题是如何解决最终一致性。

第二,数据时效性问题。

在 CQRS模式中,当command 端完成数据更新后,需要通过事件形式通知查询端系统,这也就意味着系统之间会存在一定时间差,此时如果业务对于数据的实时性要求非常高,那么可能 CQRS 的技术架构选型就不适合了,此时可能需要对实时的数据接口进行区分加以特殊处理。

第三,查询模式设计的复杂性问题。

虽然 CQRS 为我们分离了领域模型和服务于查询功能的数据模型,但这意味着我们需要单独设计另一套针对查询功能的数据模型。


这种做法带来的问题就是当查询接口越来越多时就会难以管理,仍然需要按照 DDD 中划分领域的思路将属于一个领域的查询集中管理作为整个查询系统的一个上下文,甚至需要独立出一个新的微服务,这也无形之中,CQRS 在带来架构自由与便利的同时也不可避免的引入了额外的复杂性与技能要求。

那作者为什么还要在DDD中提及CQRS架构模式呢?

我个人理解主要有以下两点:

1)选择与领域驱动契合的点—边界清晰职责明确

如果你所面对的业务系统已经非常庞大,而且业务流程庞杂逻辑繁琐,那么不妨尝试使用 CQRS 将 Command 与 Query 进行拆分,将领域模型与数据模型的边界划分的更清晰些。

2)领域驱动架构设计需要集众所长

从作者所的文章中,我们看到无论采用CQRS、消息总线模型、长时处理模型哪种单一架构模型,都不能完美解决系统中所存在的各种问题。所以需要我们使用多种架构模式来共同协作,以此完善整个系统架构。

总之,在软件架构设计中,无论是架构风格还是架构模式,都需要集众所长,避其所短,方能设计出架构良好的系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/394730.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TOUGH系列软件建模及在地下水、CO2地质封存、水文地球化学、地热等多相多组分系统多过程耦合

TOUGH2系列软件传统地下水模拟软件Feflow和Modflow不同,TOUGH2系列软件采用模块化设计和有限积分差网格剖分方法,通过配合不同EOS模块,软件可以处理各种复杂地质条件下,诸如地热能开发,非饱和带水气运移、油气运移&…

HBase---浅谈HBase原理

浅谈HBase原理 文章目录浅谈HBase原理HBase定义HBase逻辑结构HBase物理存储结构TimeStampType数据模型NaneSpaceRegionRowColumnTineStampCellHBase架构MasterMaster 架构Meta 表格介绍Region ServerRegionServer 架构MemStoreWALBlockCacheZookeeperHDFSHBase写数据流程HBase读…

设计模式中的UML类图

在线绘图工具: https://app.diagrams.net/ https://www.processon.com/ 第一个需要挂梯子,但很好用,本文用它绘制样例图 最近在看Head First一书,即使在软件工程的课程中学习过UML类图如何绘制,但显然已经忘掉很多了…

1、介绍与环境安装

文章目录前言主要特征安装安装检查查看httprunner版本创建项目创建新项目运行脚手架项目前言 HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。 …

Vue3电商项目实战-购物车模块6【16-登录后-合并购物车、17-登录后-商品列表、18-登录后-加入购物车、19-登录后-删除操作】

文章目录16-登录后-合并购物车17-登录后-商品列表18-登录后-加入购物车19-登录后-删除操作16-登录后-合并购物车 目的:登录后需要把把本地购物车合并,且清空本地购物车。 大致步骤: 编写合并购物车的API接口函数编写设置购物车数据的mutatio…

Containers--array类

Array 类 简介 Array 类是一个固定大小的数组,它的大小在编译时就已经确定了。Array 类的大小是固定的,因此它的大小不能改变。 数组是固定大小的序列容器:它们以严格的线性顺序保存特定数量的元素。 在内部,数组除了包含的元素之外不保留…

第十三届蓝桥杯省赛C++ A组 爬树的甲壳虫(简单概率DP)

题目如下: 思路 or 题解: 概率DP 状态定义: dp[i]dp[i]dp[i] 表示从树根到第 iii 层的期望 状态转移: dp[i](dp[i−1]1)∗11−pdp[i] (dp[i - 1] 1) * \frac{1}{1-p}dp[i](dp[i−1]1)∗1−p1​ 这个式子的意思是:…

Unity3D Shader系列之模板测试

一、 模板测试原理模板测试位于GPU渲染流水线的逐片元操作阶段,片元着色器完成之后就会进入模板测试,模板测试通过后再进入深度测试。我们的GPU中有一个模板缓冲区(Stencil Buffer)(Stencil即是模板的意思),其大小为整个屏幕大小*8位&#xf…

Pytorch基础语法学习2——argparse模块

一、基本介绍 argparse 模块是 Python 内置的用于命令行参数解析的模块,可以通过少数代码中变量或者参数的改变以实现对整个代码项目的操控。对于大型代码项目(如代码超过1000行),十分便捷 argparse 模块可以让人轻松编写用户友好的命令行接口&#xf…

企业级信息系统开发学习笔记1.7 基于XML配置方式使用Spring MVC

文章目录零、本节学习目标一、Spring MVC概述1、MVC架构2、Spring MVC3、使用Spring MVC的两种方式二、基于XML配置与注解的方式使用Spring MVC(一)创建Spring项目【SpringMVCDemo01】(二)在pom文件里添加相关依赖(三&…

ConvMixer:Patches Are All You Need

Patches Are All You Need 发表时间:[Submitted on 24 Jan 2022]; 发表期刊/会议:Computer Vision and Pattern Recognition; 论文地址:https://arxiv.org/abs/2201.09792; 代码地址:https:…

Python编程训练题2

1.11 有 n 盏灯&#xff0c;编号 1&#xff5e;n&#xff08;0<n<100&#xff09;。第 1 个人把所有灯打开&#xff0c;第 2 个人按下所有编号为 2 的倍数的开关&#xff08;这些灯将被关掉&#xff09;&#xff0c;第 3 个人按下所有编号为 3 的倍数的开关&#xff08;其…

【华为OD机试2023】租车骑绿岛 C++ Java Python

【华为OD机试2023】租车骑绿岛 C++ Java Python 前言 如果您在准备华为的面试,期间有想了解的可以私信我,我会尽可能帮您解答,也可以给您一些建议! 本文解法非最优解(即非性能最优),不能保证通过率。 Tips1:机试为ACM 模式 你的代码需要处理输入输出,input/cin接收输入…

如何实现在on ethernetPacket中自动回复NDP response消息

对于IPv4协议来说,如果主机想通过目标ipv4地址发送以太网数据帧给目的主机,需要在数据链路层填充目的mac地址。根据目标ipv4地址查找目标mac地址,这是ARP协议的工作原理 对于IPv6协议来说,根据目标ipv6地址查找目标mac地址,它使用的不是ARP协议,而是邻居发现NDP(Neighb…

Oracle启动数据库报ORA-01102解决办法

1.机器启动之后登录服务器使用sqlplus / as sysdba 登录数据库发现数据库并没有启动之前把数据库服务添加过开机自启动 2.使用startup命令启动数据库报错了 SYSorcl>startup; ORACLE 例程已经启动。 Total System Global Area 2471931904 bytes Fixed Size 2255752 byt…

框架——MyBatis的入门案例

框架概述1.1什么是框架框架&#xff08;Framework&#xff09;是整个或部分系统的可重用设计&#xff0c;表现为一组抽象构件及构件实例间交与的方法&#xff1b;另一种定义认为&#xff0c;框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义…

关基系统国产化全面落地,ZoomEye Pro支持信创资产识别

信创产业发展的核心动力是IT底层架构的独立自主&#xff0c;为了尽快推进关键信息基础设施系统的国产化替代&#xff0c;一方面国家不断推出相关政策&#xff0c;协调各方资源&#xff0c;提供强有力的政策支撑&#xff0c;另一方面也在各关基行业有序推进重要信息基础设施的国…

第四章:面向对象编程

第四章&#xff1a;面向对象编程 4.1&#xff1a;面向过程与面向对象 面向过程(POP)与面向对象(OOP) 二者都是一种思想&#xff0c;面向对象是相对于面向过程而言的。面向过程&#xff0c;强调的是功能行为&#xff0c;以函数为最小单位&#xff0c;考虑怎么做。面向对象&…

2024秋招BAT核心算法 | 详解图论

图论入门与最短路径算法 图的基本概念 由节点和边组成的集合 图的一些概念&#xff1a; ①有向边&#xff08;有向图&#xff09;&#xff0c;无向边&#xff08;无向图&#xff09;&#xff0c;权值 ②节点&#xff08;度&#xff09;&#xff0c;对应无向图&#xff0c;…

抓狂!谷歌账号又又登录异常?给你支招解决

最近&#xff0c;就有很多朋友向东哥反馈说&#xff0c;谷歌账号登录异常了&#xff0c;明明账号密码都是对的&#xff0c;愣是登不上去&#xff0c;严重影响工作进度&#xff0c;很是捉急。所以东哥今天就总结了一份谷歌账号登录异常的解决方案&#xff0c;希望能帮助到大家&a…