Day959.架构现代化模式 -遗留系统现代化实战

news2024/12/25 16:53:52

架构现代化的新城区模式

Hi,我是阿昌,今天学习记录的是关于架构现代化的新城区模式的内容。

前面的四个现代化并不是层层递进的关系,而是既可以同时进行,也可以颠倒顺序。

比如,既可以先重构代码,再拆分架构,也可以先拆分架构,再重构代码。

同时,也可以重组团队结构,专门拉出一个平台团队去搭建 DevOps 平台。


一、绞杀植物模式

选择把绞杀植物模式作为架构现代化的第一个模式,因为它的思想影响了很多其他模式,包括气泡上下文、扩张 - 收缩、修缮者等等。

绞杀植物模式(Strangler Fig),这是 Martin Fowler 在 2004 年左右提出的,它是一种用新系统替换旧系统的模式。遗留系统现代化的五种策略,其中就有 Rebuild/Replace 策略,绞杀植物模式就是针对这种策略的。

很多团队在选择了 Rebuild/Replace 策略后,往往希望一股脑地构建出新的系统或服务,然后直接替换,而忽略了增量演进这个原则。这样做的后果就是,新构建的系统或服务,与原系统有很大差异,甚至根本不可用。

绞杀植物模式描述了绞杀植物是如何工作的。像榕树、无花果树这类绞杀植物,会从宿主植物的头部播种,慢慢向下生长,直到插入土中,长出自己的根。几年甚至几十年过后,这些绞杀植物最终会杀死自己的宿主,占据宿主原来的位置,完成“谋权篡位”。

在这里插入图片描述

在替换一个软件系统时也是一样,应该在旧系统旁边搭建一个新系统,让它缓慢增长,与旧系统同时存在,逐步地“绞杀”旧系统。这个“逐步”的意思,其实就是增量演进。“同时存在”指的是并行运行。

在以增量演进为手段讲过一个例子,演示如何用绞杀植物模式来增量演进和并行运行。

绞杀植物模式不但可以用来替换旧系统,也可以替换一个服务或模块,或者像例子中介绍的那样,用独立的服务来替换单体中的模块。

乔梁的著作《持续交付 2.0》里总结了这种模式的利弊。它有三个优势:

  • 第一,不会遗漏原有需求;
  • 第二,可以稳定地提供价值,频繁地交付版本,更好地监控其改造进展。
  • 第三,避免“闭门造车”

劣势主要来自迭代的风险和成本,绞杀的时间跨度会很大,存在一定风险,而且还会产生一定的迭代成本。

总之,绞杀植物模式的这种新旧共存、并行运行、小步快跑、逐步替换的思想,你在之后的很多模式里还会找到相似的影子。

如果拿城市建设来打比方的话,绞杀植物模式就类似于城市迁址。

在搭建好新址的基础设施(代码库、运行环境、脚手架、配置等)后,就可以把居民(代码)迁移到新址中。但这个过程也应该是逐步进行的,如果一股脑全部搬迁过去,可能就会造成混乱。就像明成祖迁都北平,建紫禁城建了三年,迁都仅用了几个月,结果诸事不利,差点被儿子迁回南京。

倘若一部分一部分地迁移居民,让先去的那些人逐渐处理掉那些混乱,等全部搬过去之后,就会好很多吧。


二、气泡上下文模式

下一招是气泡上下文,它从何而来。领域驱动设计的创造者 Eric Evans 在 2013 年发表了一篇文章,介绍了如何在遗留系统中应用 DDD

多年来,在落地 DDD 战术设计的时候,人们往往倾向于选择一个“干净”的限界上下文(Bounded Context)。然而在遗留系统中,这种“干净”的上下文可遇不可求,这就导致在遗留系统中应用 DDD 十分困难。

人们只能在 Rebuild/Replace 的时候,在新的系统中应用 DDD 战术设计。为了能够在遗留系统中使用 DDD,Eric 在文章中提出了四种模式,其中第一种就是气泡上下文(Bubble Context)模式。

这里的气泡,指的是用防腐层(Anticorruption Layer)隔离开的一个小的限界上下文,这个上下文用于特殊的开发目的,并且不打算长期使用。它就像是一个悬浮在遗留系统之上的气泡一样,十分“干净”,却一捅就破。

什么是防腐层呢?它是 Eric 在《领域驱动设计》一书中提出的模式,顾名思义是为了隔离不同上下文之间模型不匹配的问题,避免一个上下文中的模型渗透到另一个上下文中。

当你遇到一个新的需求时,可以评估这个需求,如果它适合的话,可以不在遗留系统中开发这个需求,而是将它放到气泡上下文中,在一个全新的环境内开发这个需求。

由于防腐层隔离了遗留系统,因此可以在气泡中相对自由地进行领域建模,而不必受到遗留系统的限制。

在这里插入图片描述

然而,Eric 的气泡上下文是没有自己的数据库的,只能访问遗留系统中的数据库。


为此,它提出了基于防腐层的仓库(ACL-backed Repository)模式,即在仓库中调用防腐层,由防腐层去直接访问遗留系统数据库。

仓库模式用起来就像是内存中的集合,所以会让人觉得,气泡上下文中真的有自己的数据一样。这样一来,气泡上下文中的开发者就可以专注于业务逻辑开发,而不必关心数据从哪儿来,大大降低了认知负载。

当然,如果不想让领域层中的仓库依赖防腐层,就可以将仓库的接口定义在领域层,将仓库的实现类定义在防腐层,以实现依赖倒置。

就像一些新企业建厂办公(DDD 落地),老城区的空间不够或者条件不适合。那么就会建立一个新城区(气泡上下文),按照更适合这些企业需求的方式规划和布局(应用 DDD 的各种战术模式)。当新城区需要供电供水供暖(数据)时,就拉一条新的管线(基于防腐层的仓库)从老城区来获取这些资源。


三、自治气泡

显然,这样的方式是不可能长久的。新需求中必然有需要建新表的时候,如果仍然建立在遗留系统中,就会让遗留系统更加混乱。就像新城区的人多了,却还要跑到老城区的医院和学校去,这就太麻烦了。

因此,Eric 提出了第二种模式:自治气泡(Autonomous Bubble)。顾名思义,自治气泡就是能够自治的气泡,它有自己的数据库,与遗留系统是弱耦合的。

它不再直接访问遗留系统的数据和服务,而是通过同步防腐层(Synchronizing ACL),将遗留系统中的数据同步到自治气泡中。

同步的方式可以是轻量级的每日同步脚本,也可以是消息或领域事件

在这里插入图片描述
这就像是新城区中建好了水电气厂,也建好了医院、学校等其他基础设施(数据库),但是工厂的员工、医院的医生、学校的老师(数据)仍然住在老城区,他们需要每天辛苦地通勤到新城区工作(同步数据)。

这种自治气泡非常接近于微服务架构中的一个服务,都有独立的数据库,能够独立演进,与其他服务通过事件等机制进行弱耦合地通信。

只不过在微服务架构中,还可以通过 API 来访问其他服务。而在原始的自治气泡模式中,是彻底隔断了 API 调用这种方式的。


四、变动数据捕获

要想在自治气泡中同步数据,Eric 给出的原始方案是用定期脚本或领域事件。其实还有一种方式是变动数据捕获(Change Data Capture)模式,简称 CDC。

它能识别和跟踪数据库中的数据变动,并捕获这种变动,完成一系列后续处理,比如:

将变动内容发布到一个事件总线中,再由气泡上下文去消费这个事件,从而同步数据;

或者干脆直接连接其他数据库进行同步。

一般来说,有两种捕获变动数据的方法。一种是使用数据库触发器。

大多数关系型数据库都支持触发器,尤其是 Oracle 这类数据库,还能在触发器中调用外部服务,做起同步来尤其简单。

使用触发器一定要慎重,如果一个系统有一两个触发器还不算大问题,但有些系统(尤其是遗留系统)就是构建在大量的触发器之上的。

这简直就是灾难,因为它们很难管理,根本不知道一个数据变化会触发哪些行为,以至于无法搞清楚系统是如何工作的。

基于大量数据库触发器的系统,认知负载太高了。

另一种捕获数据的方式是使用一个单独的工具,来轮询数据库的事务日志。由于日志本身包含了数据的变动。

工具本身也运行在单独的进程中,也不用担心和数据库产生耦合和竞争。轮询事务日志的做法,可以称得上是最整洁的 CDC 方案。在将单体应用拆分为微服务的时候,CDC 是一个经常会使用到的模式。但在微服务架构下,它就有点不合时宜了。

因为它把服务内部的数据泄露到了事件总线中,破坏了封装。

更好的方式还是应该让服务来发布领域事件(Domain Event)到事件总线中,其他服务来消费领域事件,而不是变动的数据。

比如一个订单开始配送了,应该由物流服务发布一个“订单已配送”事件,而不是由 CDC 来发布一个订单表中,一行数据的变化情况。


五、事件拦截

如果遗留系统是事件驱动的架构(Event-Driven Architecture),自治气泡上下文甚至整个架构现代化的工作都轻松了不少。

可以使用事件拦截(Event Interception)模式来取代 CDC,实现气泡中的数据同步。Martin Fowler 早在 2004 年就提出了这种模式,作为构建绞杀植物应用的一种落地方案。

可以拦截一些系统中已有的事件,为它们编写新的监听程序,来进行数据的同步或开始连带的业务处理。

必要的时候也可以在遗留系统中补充一些缺失的事件。


六、遗留系统封装 API

无论是在气泡上下文中使用基于防腐层的仓库,还是在自治气泡中使用同步防腐层,其实都很别扭。

如果遗留系统是一个 Web 系统,可以方便地添加 API,最简洁的方式是将遗留系统封装为若干个 API,对外提供业务能力,供各个气泡上下文访问。但仍然需要在气泡上下文中提供一个防腐层,只不过这个防腐层不再直连遗留系统的数据库,而是去访问遗留系统封装的 API。

在这里插入图片描述

在封装 API 时,强烈建议新写 API,不要复用那些老的 API。

一方面老 API 是为特定的页面而编写的,很难被其他气泡复用。

另一方面,即使能复用,老页面与气泡的需求变化方向和速率也是不同的,很可能出现为了满足老页面的需求变化而改了 API,结果气泡上下文中的功能被破坏了。

如果你的遗留系统不是基于 Web 的,就会稍微麻烦一些了。

如果还想应用这种模式,可以新建立一个服务,直连遗留系统数据库,对外提供各种 API。但这会造成大量的代码和业务的重复。

在应用了遗留系统封装 API 模式后,自治气泡就更像是一个微服务了。它有自己的数据库,对于依赖的数据通过 API 来访问。

当然如果遗留系统本身是基于事件的,还可以充分利用事件机制,来实现服务之间的松耦合。

这就像是新城区建设得差不多了,有了自己的水电气厂和医院学校,甚至连工人医生和老师(数据)都住在新城区了(独立的数据库),但对于某些特殊场景,如高端的商场、电影院等,你仍然需要时不时去一趟老城区(调用 API)。


七、总结

从 Martin Fowler“灵光一现”发明的绞杀植物模式出发,接着学习了 Eric Evans 发明的气泡上下文和自治气泡模式,以及在气泡中可以使用的数据同步和访问方式,包括变动数据捕获、事件拦截和遗留系统封装 API。

在这里插入图片描述

从气泡上下文,到自治气泡,再到微服务,这其实描述了一个新需求落地成微服务的演进路线。

一步到位地去开发一个微服务,认知负载偏高,而且你可能也并不需要。

按需演进地去开发,认知负载就会低得多,也更容易得到一个刚刚好的架构。有很多新需求都可以通过气泡上下文来构建,比如报表、问卷、评分等。

在着手开发类似这样的需求前,作为架构师,应该思考一下:是否仍然在遗留系统中进行开发,是否可以新建一个服务来开发。这样可以和遗留系统划清界限、保持隔离。新的服务可以更好地规划和设计,遗留系统也没有变得更糟。这有点类似我们在代码现代化中介绍的新生和外覆方法,它们自己是可测的,同时也没有影响到旧方法。

气泡上下文一开始可能不需要自己的数据库,只需要从遗留系统中获取数据即可。慢慢地随着需求的迭代,开始有了自己的数据,就可以用自治气泡的方式让它拥有自己的数据库,并通过变动数据捕获或事件拦截的方式来同步遗留系统中的数据,或通过 API 来访问遗留系统的功能。

曾经在项目中使用过很多次气泡上下文模式,当时并不知道这是一种模式,只是想把这种看似与遗留系统不太相干的需求放在外面,不要再和遗留系统纠缠在一起了。

没想到用起来效果还真的挺不错。无论是绞杀植物还是气泡,以及之前课程里提到的接缝、工厂、仓库,包括新老城区建设等等,其实都是一种隐喻。隐喻不但有助于理解概念,还能激发我们在看似不相关的场景中,发现相似点的这种概念性思维(Conceptual Thinking)。

像 Martin Fowler 这种看到绞杀植物绞杀了宿主的现象,从而联想到遗留系统也应该以这样的方式进行替换,真的是把概念性思维发挥到了极致啊。


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

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

相关文章

在外远程NAS群晖Drive - 群晖Drive挂载电脑磁盘同步备份【无需公网IP】

文章目录 前言1.群晖Synology Drive套件的安装1.1 安装Synology Drive套件1.2 设置Synology Drive套件1.3 局域网内电脑测试和使用 2.使用cpolar远程访问内网Synology Drive2.1 Cpolar云端设置2.2 Cpolar本地设置2.3 测试和使用 3. 结语 转发自CSDN远程穿透的文章:【…

DAY07_常用API下

1:String 1.1 String(构造方法) String类,它涉及到两个案例:用户登录和聊天室。 先来看用户登录案例:需要输入用户名和密码,和已知的用户名和密码进行比较,涉及到比较的方法, 一般来说&…

【Springboot+Vue+MP+ElementUI+axios项目实战记录】

写在最前:仅用于记录项目中遇到的问题,并不一定解决 1、 想要实现,点击配置自动跳转页面 2、 虽然使用了push追加了url,但是在跳转下一个,比如 配置跳转到用户会因为之前的url是http://localhost:8080/admin/pagetw…

【SpringBoot】MyBatisPlus代码生成器

项目准备 数据库 MySql 5.7 新建数据库votedb,新建两个测试表user、vote_theme user表 vote_theme表 建表代码如下 -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS user; CREATE TABLE…

muduo 网络库数据流分析

最近自己实现了一个 Tiny_WebServer 服务器,是一个半同步半反应堆的模式,具体可以看我 github 上面的描述。但是春招实习二面被面试官表示项目太简单了,疯狂被怼分布式、集群等知识,故想进一步重构项目,无奈我实现的 T…

Anaconda Prompt安装pytorch

详解Anaconda安装pytorch的全过程 1.首先切换Anaconda的镜像地址,切换的原因我想大家应该明白😊 在anaconda prompt中输入以下四行命令 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --add ch…

医学图像分割之Attention U-Net

目录 一、背景 二、问题 三、解决问题 四、Attention U-Net网络结构 简单总结Attention U-Net的操作:增强目标区域的特征值,抑制背景区域的目标值。抑制也就是设为了0。 一、背景 为了捕获到足够大的、可接受的范围和语义上下文信息,在标…

Anaconda安装教程

最新Anaconda3安装教程 1.Anaconda3下载 官网下载地址 缺点: 下载速度比较慢,对速度有要求的小伙伴往下看 通过清华镜像加速的方式下载比较快 清华镜像加速地址 2.Anaconda3安装 双击安装包,点击next 点击 I agree 选择使用的用户&am…

攻防世界-Crypto-不仅仅是Morse

题目描述:题目太长就不拷贝了,总之,就是对以下字符进行解密 --/.-/-.--/..--.-/-..././..--.-/..../.-/...-/./..--.-/.-/-./---/-/...././.-./..--.-/-.././-.-./---/-.././..../..../..../..../.-/.-/.-/.-/.-/-.../.-/.-/-.../-.../-.../…

QML应用动画(Applying Animations)

目录 一 扩展可点击图像元素版本2(ClickableImage Version2) 1 第一个火箭 2 第二个火箭 3 第三个火箭 动画可以通过以下几种方式来应用: 属性动画 - 在元素完整加载后自动运行; 属性动作 - 当属性值改变时自动运行&#xf…

通讯录的实现(静态入手版)

🍉博客主页:阿博历练记 📖文章专栏:c语言(初阶与进阶) 🎁代码仓库:阿博编程日记 🌹欢迎关注:欢迎友友们点赞收藏关注哦 文章目录 🍭前言&#x1f…

python学习之【类和对象】

前言 五一快乐! 上一篇文章python学习——【第八弹】中,给大家介绍了python中的函数,这篇文章接着学习python中的类和对象。 我们知道,python中一切皆对象。在这篇文章开始之前,我们先了解一下编程界的两大阵营——面…

[渗透教程]-004-长城防火墙GFW的原理

文章目录 1. baidu.com 请求过程2. GFW原理2.1 GFW拦截方法1:DNS渲染2.2 通过IP黑名单2.3 VPN阻断1. baidu.com 请求过程 家庭的路由器具备了交换机的功能.域名–>ip,优先检测本地的缓存,没有的话就查找DNS服务器,传输层对应该层的数据进行封装增加了端口的信息,网络层对传输…

[230502]英语阅读长难句分析|共6个

🍣五月份第二篇笔记🍣 40:0/3 41: 3/3 目录 题目 40-1 (1)句子结构分析 (2)生词 (3)原题 40-2 (1)句子结构分析 (2&#…

2022年度项目管理软件排名揭晓:哪些软件在市场中脱颖而出?

在项目管理软件的选择过程中,用户会倾向于参考一些软件排名来辅助自己进行选择。软件排名方面推荐参考G2,一个国外的靠谱软件评测网站,类似于软件版的“大众点评”,软件评价来自于真实用户,网站通过多维度的算法&#…

springboot3+react18+ts实现一个点赞功能

前端&#xff1a;vitereact18tsantd 后端&#xff1a;springboot3.0.6mybatisplus 最终效果大致如下&#xff1a; 后端&#xff1a; 引入pom依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring…

PMP/高项 03-项目进度管理

项目进度管理 概念 项目进度管理&#xff08;Schedule Management) 项目进度管理又叫项目工期管理&#xff08;Duration Management)或项目的时间管理(Time Management) 是一种为管理项目按时完成项目所需的各个过程 进度管理过程 规划进度管理 定义活动 排列活动顺序 估算活…

jQuery -- 常用API(上)

1. jQuery选择器 1.1 jQuery基础选择器 原生 JS 获取元素方式很多&#xff0c;很杂&#xff0c;而且兼容性情况不一致&#xff0c;因此 jQuery 给我们做了封装&#xff0c;使获取元素统一标准。 语法&#xff1a;$(“选择器”) // 里面选择器直接写 CSS 选择器即可&#xff…

【毕业设计】基于springboot + vue微信小程序商城

目录 前言一、视频展示二、系统介绍三、项目地址四、运行环境五、创新点/亮点六、设计模块①前台②后台 七、系统功能模块结构图八、 准备阶段①使用真实支付②使用模拟支付九、使用说明十、登录后台十一、后台页面展示十二、微信小程序页面展示关于我 前言 【毕业设计】基于s…

IPsec中IKE与ISAKMP过程分析(快速模式-消息2)

IPsec中IKE与ISAKMP过程分析&#xff08;主模式-消息1&#xff09;_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析&#xff08;主模式-消息2&#xff09;_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析&#xff08;主模式-消息3&#xff09;_搞搞搞高傲的博客…