当前位置: 首页 > news >正文

DDD架构实践

ddd架构浅析

背景介绍

什么是ddd架构,是以ddd思想为参考,做出一份符合ddd思想的框架。

随着技术的迭代升级,越来越多的瓶颈暴露出来,性能瓶颈,系统复杂度瓶颈,这些都逐一被迭代出的技术产物解决。最终的一个产物微服务,几乎完美解决了性能和系统复杂度的问题,保证服务性能的前提下,还简化了系统的复杂度,降低开发难度,让系统更加容易维护。

但是对于B端企业来说,单单解决性能和系统复杂度问题还远远不够,极度复杂的业务,让系统难以维护,动辄几百上千行的方法,让开发人员头疼。每一个简单逻辑的背后,都会存在多个业务方,多个业务方的兼容使得逻辑变得复杂,加上业务的变化频繁这一特点,让系统的复杂度极速提高。

ddd很早就出现了,由于过于复杂难以理解,一直没有很好地最佳实践。ddd的核心思想,就是为了解决B端企业的业务复杂度而生,近些年ddd的突然爆火,是因为有了最佳实践的落地,比较出名的比如cola的应用分层框架。

ddd核心分模块思想

ddd的思想核心是通过领域建模、分层分包的模式来进行降低业务复杂度,简化开发逻辑,清晰业务流向。

通过cola的最佳实践,可以把ddd进行落地,并且由核心和拓展几个点来进行分析。

核心模块

核心分包为 适配器、领域、基建包,

三个包都不相互依赖,形成相互隔离的几个单独模块,让每一个模块都只有很单一的能力,这样就可以很好的把业务限制在领域中,极好的来沉淀建立自己的核心业务能力。

适配器层:

由于B端业务多样性且复杂,所以需要单独的适配器来做,将不同的业务来进行适配,进入自己的核心且单一的能力中。

通过将单一能力,增加多个适配器,提高业务的适配能力。b端业务的多样性,往往体现在数据及命名的多样性,但核心的业务大体相同,所以通过适配器,可以极大降低因多样性带来的复杂度。

领域层:

领域层的单独存在,一方面是为了限制核心业务不会散落的到处都是,另一方面是让开发更加聚焦在核心业务的开发上。通过一些策略及拓展模式,就可以实现核心业务及其不同的特性。

B端企业级对外提供的能力一定是单一的,只有这样才能逐渐沉淀自己在行业内的影响力,如果什么都能支持,反而会觉得什么都不强,都不稳定。而且随着差异太大的业务,会导致成本剧增。

单一的能力,会逐渐去完善产品能力,最终沉淀产出一个标准的行业产品。

在大能力不变的情况下,不同的特性处理,通过一些拓展点,就可以快速实现接手。

基建层:

在B端业务中,三方依赖的侵入性变动也是对业务稳定性的一个侵蚀,比如业务前期,使用某种组件可以满足业务需求,随着发展需要更换另一种组件,这种组件变更给系统带来的稳定性影响是非常重要的,因为组件的变更导致业务宕机是非常不合理的,为了避免这种情况,将三方组件完全隔离是非常必要的。

三方组件包括但不限于:数据库、缓存、mq、三方接口、三方sdk、三方rpc等。

可以认为所有和外部交互的都应该限制在基建层,以此来进行隔离,保证系统的稳定性。

domain模块

domain是三个模块的轴承,通过依赖倒置,让三个模块相互隔离,全都由domain拉着,通过domain进行交互。

domain的必要性:

从物理层面进行隔离,让其他人不能使用其他模块的东西。

pom的变更应该提起cr人员的注意,切实做好每一个pom变更,避免在代码中引入坏味道。

引入之后通过规约来限制是很不合理的,根据墨菲定律,只要存在,就一定会被人使用到。

非核心模块

client模块:

如果系统有对外提供的能力,比如rpc接口,mq实体定义等。

这些内容是切面与系统存在的,需要提供给外部引用,应该单独出来,避免把自己的核心内容给外部使用。

优势:

  1. 避免由于外部使用不当,导致自己内部的实体变更,让交互不稳定。
  2. 避免由于提供依赖太大,导致对方系统的负担
  3. 避免核心能力让对方引用,增加安全风险

遵守规则:

  1. client包中,不应有任何三方依赖,只是一个简单接口及实体的定义
  2. 不应有内部使用的包,只需要提供外部所需的即可,遵守最小可用原则
  3. 统一出参封装,所有对外提供的接口应统一封装,方便框架层面做统一处理。

common模块

对应本应用而言,在不同模块中都有使用到的工具,分别定义是不合适的,通过common包来抽象出共有能力,来降低代码重复率。

ext模块

如果业务的多样性非常复杂,对每一个特性的处理都需要大量的业务逻辑,那么ext模块单独抽出就很有必要。多样性处理的太多,和核心业务掺杂在一块,随着业务的发展,就会产生特性分支和主分支分不清的情况,混用,职责不清晰,能力不单一。即使规约的再好,根据墨菲定律,这种问题一定会发生。

另外一些高阶的玩法,ext模块外置,核心能力很稳定,拓展能力变动较大时,ext模块会成为热插拔组件,通过快速迭代更新来满足业务,做到完全的系统热插拔,不影响当前业务,新的业务快速上线。

也为了避免不同特性分支相互影响,通过这种做到完全隔离。

sop模块

核心业务稳定,且领域模型较为完善,业务进入后期阶段,新的业务接入就不再依托于编码,而且通过流程引擎来做编排,让新的业务进入。

同一个业务能力,有多种处理,且都为核心能力,此时就应该把这个作为一个sop,把这些提出来一个sop模块单独处理,原本核心的领域层,做流程编排及其他前置业务处理。拓展点再次升级为某个sop的拓展能力。

一般情况下,sop是ext的发展产物,某个ext的特性分支业务发展很好,逐渐成长为核心业务,趋于稳定,此时该特性分支就会成为核心能力分支。

最佳实践讲解

本节主要来解析每一个模块中,应该放些什么,每一层的依赖如何处理等。

分层模块

适配器模块

本层定位是系统入口,所有的业务起点,都应该在这里。

比如:controller接口、rpc接口实现、mq消费者实现等。

本层依赖:

内部依赖:核心领域模块,client模快、common模块。

三方依赖:核心框架、rpc和mq等必要框架、基础组件。

禁止依赖:业务模块、基建模块

特殊说明

本层的模型定义在本层内、或者取自client。

本层调用领域层之前,需要做好模型转换,将模型转换为领域层里面定义的模型,然后再定义,这层的转换器应该写在这层。

业务模块

本层定位为核心业务逻辑处理,所有的业务处理都应在这里。

比如:业务流程判断走向、业务逻辑判断、根据不同的数据做不同的处理、调用数据库接口、调用mq接口、和外部交互的逻辑等。

本层依赖:核心领域模块、common模块。

三方依赖:核心框架

禁止依赖:适配器模块、基建模块、client模块、任何非必要三方依赖

特殊说明

本层不需要做任何类型转换,进来就是自己所需要的模型。

本层不允许引入其他模块的模型,这层的模型都应该非常稳定,不能有三方注解(比如rpc注解、fastjson注解、mybatis注解、mq注解等)

基建模块

本层定位为防腐基础设施,所有和外部的交互都应该在这里,这里应该为单条线的末端。

比如:从数据库中获取数据的最终实现,从缓存中获取数据的最终实现,发送mq的实际实现,调用rpc接口的最终实现等。

本层依赖:核心领域模块、common模块。

三方依赖:核心框架、外部sdk、外部client模块、任何三方所需要的依赖。

禁止依赖:适配器模块、client模块、业务模块

特殊说明

本层的模型可以用到领域模型或者三方交互模型。进来都是领域模型,根据需求转换为对应的三方接口模型。

处理完如果有数据透出,必须要使用类型转换器,不可把本层模型透出,也不能把三方接口模型定义到领域模块中。

领域模块

本层定位是不同模块的轴承,所有的核心交互接口定义及数据模型定义都在这里,这里联通各个模块。

比如:核心业务处理的接口(DomainService),基础建设中的能力透出接口(InnerService/Gateway)。

本层依赖:common模块

三方依赖:无

禁止依赖:几乎不允许依赖任何内容

client模块

本层定位是本系统对外提供的能力点透出。

比如:对外提供的rpc接口,对外提供的mq模型等。

本层依赖:无

三方依赖:无

禁止依赖:几乎不允许依赖任何内容

common模块

本层是不同模块之间通用的工具内容。

比如:字符串处理工具,各种util类,各种通用处理能力。

本层依赖:无

三方依赖:非常稳定的三方工具包(原则上需要自己重写一套),几乎不能引用其他三方依赖。

start模块:

应用的启动模块,定义启动器及启动所必须得一些内容。

比如:spring boot启动器,启动配置,项目中的一些配置。

本层依赖:所有的模块

三方依赖:基础框架依赖

ddd框架实践

一套最基础的增删改查实践

╔ adapter
║ ╟ java
║ ╟ ╟ RpcXXXServiceImpl.java
║ ╟ ╟ XXXController.java
║ ╟ ╟ XXXConsumer.java
║ ╟ resource
║ ╚ pom.xml
╟ biz
║ ╟ java
║ ╟ ╟ XXXDomainServiceImpl.java
║ ╚ pom.xml
╟ infra
║ ╟ java
║ ╟ ╟ XXXConverter.java
║ ╟ ╟ XXXClient.java
║ ╟ ╟ XXXInnerServiceImpl.java
║ ╟ ╟ XXXDO.java
║ ╟ resource
║ ╟ ╟ mapper
║ ╟ ╟ ╟ xxxMapper.xml
║ ╚ pom.xml
╟ domain
║ ╟ java
║ ╟ ╟ XXXDomainService.java
║ ╟ ╟ XXX.java
║ ╚ pom.xml
╟ client
║ ╟ java
║ ╟ ╟ RpcXXXService.java
║ ╟ ╟ XXXDTO.java
║ ╚ pom.xml
╟ common
║ ╟ java
║ ╟ ╟ XXXUtil.java
║ ╚ pom.xml
╟ start
║ ╟ java
║ ╟ ╟ Application.java
║ ╟ ╟ config
║ ╟ ╟ ╟ Config.java
║ ╟ resource
║ ╟ ╟ application.properties
║ ╟ ╟ META-INF
║ ╚ pom.xml
╚ pom.xml

实际demo

TODO…

相关文章:

DDD架构实践

ddd架构浅析 背景介绍 什么是ddd架构,是以ddd思想为参考,做出一份符合ddd思想的框架。 随着技术的迭代升级,越来越多的瓶颈暴露出来,性能瓶颈,系统复杂度瓶颈,这些都逐一被迭代出的技术产物解决。最终的…...

Bert-vits2-v2.2新版本本地训练推理整合包(原神八重神子英文模型miko)

近日,Bert-vits2-v2.2如约更新,该新版本v2.2主要把Emotion 模型换用CLAP多模态模型,推理支持输入text prompt提示词和audio prompt提示语音来进行引导风格化合成,让推理音色更具情感特色,并且推出了新的预处理webuI&am…...

认识缓存,一文读懂Cookie,Session缓存机制。

🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。 🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。 🎉欢迎 👍点赞✍评论…...

关于react native项目中使用react-native-wechat-lib@3.0.4

关于react native项目中使用react-native-wechat-lib3.0.4 插件官网安装依赖包(Android和iOS下载插件完成后记得更新依赖,)Android中配置1.在项目文件夹下面创建文件夹wxapi(如上图)2.在文件MainApplication.java中如下…...

【LeetCode刷题笔记(8-1)】【Python】【接雨水】【动态规划】【困难】

文章目录 引言接雨水题目描述提示 解决方案1:【动态规划】结束语 接雨水 引言 编写通过所有测试案例的代码并不简单,通常需要深思熟虑和理性分析。虽然这些代码能够通过所有的测试案例,但如果不了解代码背后的思考过程,那么这些代…...

pycharm通过ssh连接远程服务器的docker容器进行运行和调试代码

pycharm连接远程服务器的docker容器通常有两种方法: 第一种:pycharm通过ssh连接已在运行中的docker容器 第二种:pycharm连接docker镜像,pycharm运行代码再自动创建容器 第一种方法比较通用简单,作者比较推崇。 条件…...

Chrome2023新版收藏栏UI改回旧版

版本 120.0.6099.109(正式版本)Chrome浏览器菜单新版、旧版的差异 想要将书签、功能内容改回旧版的朋友可以网址栏输入:「chrome://flags」,接着搜寻「Chrome Refresh 2023」。 最后将 Chrome Refresh 2023、Chrome Refresh 2023…...

WebSocket与JavaScript:实现实时获取位置

一、WebSocket介绍 WebSocket是一种在单个TCP连接上进行全双工通信的协议。与传统的HTTP请求相比,WebSocket能够在服务器和客户端之间建立持久连接,实现实时数据传输。WebSocket提供了较低的延迟和高效的数据传输。在实时舆情监测中,它能够实…...

一种解决Qt5发布release文件引发的无法定位程序输入点错误的方法

目录 本地环境问题描述分析解决方案 本地环境 本文将不会解释如何利用Qt5编译生成release类型的可执行文件以及如何利用windeployqt生成可执行的依赖库,请自行百度。 环境值操作系统Windows 10 专业版(22H2)Qt版本Qt 5.15.2Qt Creator版本5.0…...

UE4/UE5 日志插件(基于spdlog)

1 解决问题 对于高频日志序列化到本地的需求,spdlog肯定完美满足。 源码地址:https://github.com/gabime/spdlog 博主下载的版本为 spdlog-1.12.0,各位大佬可以根绝自己爱好选择。 2 过程介绍 大概目录: SpdlogLibC目录下是对…...

微信小程序ios中非cover组件点击重复触发地图tap事件

现象&#xff1a; map中使用view组件的click事件会重复触发地图的tap组件&#xff0c;只在ios上出现 <map id"maps" style"width: 100vw;height: 100vh;" :latitude"latitude" :longitude"longitude":markers"markers"…...

7.26 SpringBoot项目实战【还书】

文章目录 前言一、编写控制器二、编写服务层三、Git提交前言 本文是项目实战 业务接口 的最后一篇,上文 曾说过【还书】的 入口是【我的借阅记录】,因为【还书】是基于一次借阅记录而言,另外在4.2 数据库设计 曾分析过【还书】的业务场景,需要执行两步操作: 更新【借阅记…...

Golang中使用errors返回调用堆栈信息

Golang的errors包返回堆栈信息 标准库errors提供了处理错误的方法。比如常用的 func New(text string) error 用该方法处理错误信息&#xff0c;就只会输出自定义的 text 到控制台或者日志文件&#xff0c;没有其它辅助排查的信息输出&#xff0c;所以常规我们就只能根据 te…...

Web前端-HTML(常用标签)

文章目录 1. HTML常用标签1.1 排版标签1&#xff09;标题标签h (熟记)2&#xff09;段落标签p ( 熟记)3&#xff09;水平线标签hr(认识)4&#xff09;换行标签br (熟记)5&#xff09;div 和 span标签(重点)6&#xff09;排版标签总结 1.2 标签属性1.3 图像标签img (重点)1.4 链…...

一 OpenCV中的数据类型

1. cv::Mat 2. cv::Point 主要用来表示二维点&#xff0c;也有表示三维点的模板类型&#xff1b; cv::Point p(int, int) 最常用 ① cv::Point_<T> ② cv::Point2i cv::Point_<int> ③ cv::Point2f cv::Point_<float> ④ cv::Point2d …...

59. 螺旋矩阵 II(java实现,史上最详细教程,想学会的进!!!)

今天来分享一下螺旋矩阵的解题思路及代码的实现。 题目描述如下&#xff1a; 首先拿到这道题&#xff0c;首先不要慌张&#xff0c;我们来仔细分析一下会发现并没有那么难。 首先看下边界的元素是1、2、3递增的&#xff0c;那么我们也许可以根据这一点先把边界的元素一个一个给…...

vue 将后端返回的二进制流进行处理并实现下载

什么是二进制流文件&#xff1f; 二进制文件是一种计算机文件格式&#xff0c;它的数据以二进制形式存储&#xff0c;与文本文件不同。二进制文件可以包含任意类型的数据&#xff0c;例如图像、音频、视频、可执行文件、压缩文件等&#xff0c;而文本文件则仅仅包含 ASCII 码或…...

PyCharm连接远程服务器

要求&#xff1a;PyCharm专业版才支持远程服务 一、创建远程连接 先建立本地与远程服务器之间的SSH连接 1、配置连接 2、建立SSH连接&#xff0c;选择文件传输协议 SFTP 3、设置服务器名&#xff08;可以随意命名&#xff09; 4、配置 SSH连接 点击 172.18.1.202 配置…...

使用Qt制作网易云播放器的歌曲排行界面

&#xff01;&#xff01;&#xff01;直接上图&#xff01;&#xff01;&#xff01; &#xff01;&#xff01;&#xff01;直接上图&#xff01;&#xff01;&#xff01; &#xff01;&#xff01;&#xff01;直接上图&#xff01;&#xff01;&#xff01; 网易云排行榜…...

【.NET Core】特性(Attribute)详解

【.NET Core】特性&#xff08;Attribute&#xff09;详解 文章目录 【.NET Core】特性&#xff08;Attribute&#xff09;详解一、概述二、编写自定义属性2.1 自定义特性的主要步骤2.2 应用AttributeUsageAttributeAttributeTargets 成员Inherited属性AllowMultiple属性 三、声…...

【C++】POCO学习总结(十九):哈希、URL、UUID、配置文件、日志配置、动态库加载

【C】郭老二博文之&#xff1a;C目录 1、哈希 1.1 说明 std::map和std::set 的性能是&#xff1a;O(log n) POCO哈希的性能比STL容器更好&#xff0c;大约快两&#xff1b; POCO中对应std::map的是&#xff1a;Poco::HashMap&#xff1b; POCO中对应std::set的是 Poco::Hash…...

1846_安全SPI

Grey 全部学习内容汇总&#xff1a;GitHub - GreyZhang/g_embedded: some embedded basic knowledge. 1846_安全SPI SPI是一种常见的通信方式&#xff0c;在汽车电子中比较常用。但是如果涉及到安全相关的设计&#xff0c;可能得考虑更多。而SPI协议本身没有很好的标准化&am…...

SQL Server ,使用递归查询具有层级关系的数据。

假设我们有一个表格 Employees&#xff0c;其中包含员工的层级关系信息&#xff0c;每一行包括员工的ID、姓名以及上级员工的ID。 下面是一个示例表格及其数据&#xff1a; Employees ---------------------- EmployeeID | Name | ManagerID ---------------------- 1 …...

【参数汇总】mysql服务端/客户端常见优化参数

mysql服务端参数 1、innodb_buffer_pool_size &#xff08;innodb索引buffer pool缓冲区大小&#xff09; 默认大小为128M&#xff0c; 官方推荐其配置为系统内存的 50% 到 75% 。 一般innodb_buffer_pool_size要结合以下两个参数来设置&#xff1a; innodb_buffer_pool_ch…...

LeetCode 142. 环形链表 II

给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整…...

Leetcode刷题笔记题解(C++):224. 基本计算器

思路&#xff1a; step 1&#xff1a;使用栈辅助处理优先级&#xff0c;默认符号为加号。 step 2&#xff1a;遍历字符串&#xff0c;遇到数字&#xff0c;则将连续的数字字符部分转化为int型数字。 step 3&#xff1a;遇到左括号&#xff0c;则将括号后的部分送入递归&#x…...

还在为学MyBatis发愁?史上最全,一篇文章带你学习MyBatis

文章目录 前言一、&#x1f4d6;MyBatis简介1.Mybatis历史2.MyBatis特性3.对比&#xff08;其他持久化层技术&#xff09; 二、&#x1f4e3;搭建MyBatis1.开发环境2.创建maven工程3.创建MyBatis核心配置文件4.创建mapper接口5.创建MyBatis的映射文件6.通过junit测试功能7.加入…...

C# WPF上位机开发(树形控件在地图软件中的应用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们聊过图形软件的开发方法。实际上&#xff0c;对于绘制的图形&#xff0c;我们一般还会用树形控件管理一下。举个例子&#xff0c;一个地图…...

【华为】文档中命令行约定格式规范(命令行格式规范、命令行行为规范、命令行参数格式、命令行规范)

文章目录 命令行约定格式**粗体&#xff1a;命令行关键字***斜体&#xff1a;命令行参数*[ ]&#xff1a;可选配置{ x | y | ... } 和 [ x | y | ... ]&#xff1a;选项{ x | y | ... }* 和 [ x | y | ... ]*&#xff1a;多选项&<1-n>&#xff1a;重复参数#&#xff…...

Trie 字典树(c++)(前缀)

题目链接&#xff1a;用户登录 题目&#xff1a; 样例&#xff1a; 输入 5 3 aaa aba aabbaa abbbbb cdd aabba abc abab 输出 Y N N 思路&#xff1a; 根据题目意思&#xff0c;要用到 Trie 字典树算法。 Trie 字典树&#xff0c;顾名思义&#xff0c;“字典”&#xff0…...