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

Day949.遗留系统之殇:为什么要对遗留系统进行现代化? -遗留系统现代化实战

遗留系统之殇:为什么要对遗留系统进行现代化?

Hi,我是阿昌,今天学习记录是关于遗留系统之殇:为什么要对遗留系统进行现代化?的内容。

不知道你是否跟曾经一样,身处一个遗留系统的漩涡之中,每天为毫无头绪的代码和混乱不堪的架构发愁。

一个新的需求来了,都不知道从哪儿开始改起,即便看似简单的需求都要很久才能上线。

到底什么样的系统才能称之为遗留系统呢?它存在哪些问题,复杂在哪里?


一、关于遗留系统的误区

一个问题:假如一个系统七八年了,它是不是个遗留系统?系统的时间长等同于就是遗留系统,这是很多人的一个误区。

虽然大多数遗留系统确实是存在的时间很长,但并不等于时间长的都是遗留系统。一个项目上工作 6 年多,这是一个有着 12 年历史的老项目。

  • 它的技术栈最初是.NET Framework,现在已经有部分迁移到了.NET Core;
  • 它最初是单体架构,现在是一个小单体加多个微服务;
  • 它从第一行代码开始就使用 TDD 的方式开发,至今已经有 30000 多个不同类型的测试;
  • 它一开始使用 SVN 来管理源代码,不过早在十年前就被迁移到了 Git
  • 它从第一天就有 CI/CD 相伴,并且一直坚持基于主干开发的分支策略,每个月都有稳定的版本发布;
  • 它没有一行注释,但是任何开发人员都能通过阅读源代码快速了解系统的实现,也就是说代码质量相当高……这个系统历时 12 年之久,比很多公司活的时间都长。

那它是遗留系统吗?答案是否定的

因为它的代码质量高、架构合理、自动化测试丰富、DevOps 成熟度也高,各种技术、工具都是相对先进的,怎么能说是遗留系统呢?


思考一下:存在时间短的系统就不是遗留系统吗?

一个项目,它仍旧是基于 JDK 1.4 的(那个时候 Java 6 已经发布 4 年了),很多 Java 的新特性都无法使用。它是一个 C/S 结构的软件,前端基于 Java 富客户端,后端是一个大单体向前端提供 RPC 服务;

它没有一行测试,每改一行代码都提心吊胆,有时为了不影响别的功能,只好把代码复制一份,加入自己的逻辑,这就导致了大量的重复代码;每次发布日期都是一拖再拖,而部署到生产环境上的 war 包,甚至在是开发机器上打包的……别看这个系统只开发完 3 年,但毫不客气地说,它从刚开发完毕的那一刻起,恐怕就是个遗留系统。

它的代码质量差、架构不可演进、没有自动化测试、缺乏 DevOps,各种技术、工具也十分落后、老旧,这样的系统,即使刚开发完,也是遗留系统。

那么从上面的描述看,已经发现了我判断遗留系统的几个维度:代码、架构、测试、DevOps 以及技术和工具。

所以说啊,时间长短并不是衡量遗留系统的标准。代码质量差、架构混乱、没有测试、纯手工的 DevOps(或运维)、老旧的技术和工具,才是遗留系统的真正特点。


二、遗留系统的特点和问题

  • 首先就是代码质量差。说优秀的代码都是相似的,而糟糕的代码则各有各的糟糕之处。一个有着 6000 行代码的单个方法,至今印象深刻。其中包含 6 个大的 if/else 块,每个块中大概有 1000 行左右的代码,这 6 个 1000 行的代码只有十分细小的差别。显然是开发人员为了偷懒,不敢在原代码上改动,于是复制出来加入自己的逻辑。他倒是图省事儿了,但是对于维护人员来说简直是噩梦。正所谓编码一时爽,维护火葬场。

  • 其次是架构,这也是遗留系统的重灾区。一个软件架构的作用,是要解决多个业务模块之间的协作问题。但如果架构混乱,多个模块之间往复调用,数据也是随意访问,模块之间的边界就会变得模糊,数据所有权也会变得含糊。试想一下,如果一张表被 10 个模块访问,谁能说得清这张表到底属于哪个模块呢?

下图是一家银行的核心应用系统模块之间的交互图,想没有一个人愿意工作在这样的系统上吧?
在这里插入图片描述
综合来看,代码和架构的质量差会导致遗留系统的维护成本相当高昂。这里的维护就包括:新需求的添加、线上 Bug 的修改,以及为了维护系统运行所需投入的软硬件和人力等。

IEEE 就曾报道过,2010 年以来,全世界在 IT 产品和服务上的支出达到了 35 万亿美元。其中四分之三用于运营和维护现有的 IT 系统,至少有 2.5 万亿用于尝试替换旧系统,其中差不多三分之一的资金都打了水漂(感兴趣的话,可以看这里)。

企业在遗留系统上的投入巨大,却没能得到相称的回报。很多资金只是用来维持系统的现状,却不能让它们变得更好。
更严重的是,代码和架构的落后还会导致系统在合规和安全方面的问题。随着我国法律法规的健全,软件系统的合规性越来越重要,而一个面对任何需求都难以实现的遗留系统,要想进行修改以符合新的法律法规,是难上加难的事情。

去年我国正式施行了《中华人民共和国数据安全法》(即中国的 GDPR),明确规定了软件系统的数据安全规范。如果不能依法进行系统的整改,将面临法律的制裁。而在遗留系统开始构建的时候,可能就没有考虑太多的安全性。随着新的攻击手段越来越丰富,遗留系统的安全性越来越脆弱,企业也很难对此投资去专门改善安全性。

然后接着看缺乏甚至没有测试所造成的问题。在一个遗留系统上添加新需求简直如履薄冰,当好不容易找到要修改的位置,敲了几行代码感觉可以了的时候,系统的另一个功能可能会因为你的这几行代码而崩溃。而一个线上 Bug 想要找到元凶,可能会难如登天,一方面缺乏有效的日志难以定位(很多遗留系统的日志是打在命令行里的),

另一方面修复了一个 Bug 也可能会导致更多的 Bug。这时就体现出自动化测试的重要性了。

不知道系统里有没有或者有多少测试,总之我在那个有着 30000 多个自动化测试的项目上修复一个 Bug 的过程是这样的:

  1. 先在本地复现 Bug,找到产生这个 Bug 的业务场景;
  2. 为这个业务场景添加一个自动化测试并运行,发现这个测试是失败的;
  3. 修改代码,让这个新增的测试通过;
  4. 运行所有的测试,确保所有的测试通过。

经过这一系列操作,我就可以有十分有信心地宣布,这个 Bug 被修复了,而且在目前测试覆盖的场景下没有引入新的 Bug。但对于没有测试的遗留系统,在测试人员告知测试通过之前,我简直是胆战心惊。那遗留系统落后的 DevOps 手段会造成哪些问题呢?这会造成重大的安全隐患。

那个例子,部署到生产环境的安装包是本地打出来的,就是非常严重的安全问题。不知你是否记得几年前著名的 XCodeGhost 事件,开发人员使用非官方渠道下载的注入了恶意代码的 XCode,并用这样的 XCode 打包 App,上传到了 App Store 上。结果下载了这种 App 的手机信息就被窃取了。

这里多说两句,这次事件延伸到我们的日常工作中也是有值得深思之处的。

  • 一是不要从非官方渠道下载开发工具,但这个教训直到现在仍然没有引起足够的重视,仍然有很多团队使用的付费开发工具不是从官方渠道下载的。

  • 二是不要在开发机器上打包部署到非开发环境(特别是生产环境)上,要通过 CI/CD 来编译、打包和部署(当然 CI/CD 上的工具也必须是从官方渠道下载)。这就是 DevOps 的作用之一。最后,技术和工具也可能存在很大的安全漏洞(比如前段时间爆雷的 log4j)。新的系统虽然也存在这样的风险,但是非常容易补救。反观遗留系统的工具升级,那就举步维艰了,原因也很简单,投入产出比合不来。

另外,落后的技术和工具也使得遗留系统难以与新系统集成。基于 Delphi、PowerBuilder、VB 或 Lotus Notes 那一代的桌面应用,就是很好的例子。新的开发团队在面临遗留系统集成的时候,往往都是唯恐避之不及。

这样的系统也使得自己所拥有的企业核心数据成为孤岛,难以与其他系统互联。


三、什么是遗留系统?

说了这么多,我们似乎已经有了一个很具体的关于遗留系统的画像了,参考如下:

在这里插入图片描述
那是不是可以进一步抽象一下概念了呢?很简单,不妨直接看看维基百科是如何定义的吧:

在计算机领域,遗留系统是一种使用旧的方法和技术的、过时的,却仍旧在使用的计算机系统。

而 Gartner 给出的定义是:

基于过时技术但对日常运营至关重要的信息系统。

嗯,有信息重合,找找关键字:旧的、过时的、重要的、仍在使用的……这里找找对应的例子,辅助下理解。

不知道是否看过一些医疗类型的美剧,还记得发生危急情况时,医院是如何通知医生们的吗?是使用寻呼机——一个在现实生活中已经寿终正寝了快 20 年的古老的通信设备。

难道美国的通信设施如此落后吗?当然不是,诞生了 iPhone 和 Android 的美国怎么可能通信落后呢?真正落后的是医院的急救寻呼系统。

这些系统往往有着六七十年的历史,很难被替换。它就完美符合上面的所有关键字:旧、过时、重要、仍在使用。还有 Windows XP 系统,尽管它很经典,但微软在 2014 年就已宣布不再维护了。

不过直到现在,仍然能在很多 ATM 机上看到它的踪影。到这,已经完全明确了遗留系统的定义以及它所带来的问题,所以觉得一个遗留系统还有保留的价值吗?为什么没有替换甚至丢弃,还要继续维护,并为其打上重要的标签呢?


四、遗留系统的现代化价值

原因有很多。首先,可能是成本太高了,企业不愿意投入资源去改进;也可能是因为积重难返,根本改不动。而遗留系统往往都是企业的核心业务系统,支撑着整个企业的业务运营,这样的系统就算问题再多,也是不可替代的。

其次,遗留系统蕴含了大量的数据资产。遗留系统中的数据虽然很难与其他系统进行集成,但这部分数据的价值又是巨大的。企业的新系统常常不得不在这些数据的基础之上去构建,其他系统要想获得遗留系统中的数据,就必须对遗留系统进行修改,所以很多团队为了避免修改代码就会去寻求数据库层面的复制和同步,这也是一个选择。

另外,遗留系统中还藏匿着丰富的业务知识。由于业务人员长期使用并且养成了习惯,很多软件系统已经与业务融为一体,很难区分哪些是真正的业务,哪些是系统的设计。而由于系统历时太久,已经失去了能够正确描述系统现状的文档,所以到最后只有遗留系统的代码才能够准确表达系统的行为,以及与之对应的业务知识。

系统改造,有可为有可不为,而对于遗留系统来说,结合其现代化价值,看上去更像是一种不得不为。所谓现代化,其实就是从代码、架构、DevOps 和团队结构这四个方面来对遗留系统进行治理。既然不能对遗留系统听之任之,就要下决心迎难而上,掌握主动权,否则当问题真正出现时就为时已晚了。

举个例子,疫情期间,美国大量人口失业,但上世纪 80 年代建造的失业系统无法及时发放失业福利,他们的国税局系统则更加老旧,是 60 年代建造的,总共需要 20 个星期的时间才能为符合条件的纳税人发放疫情补贴。

看到的是,在全球疫情这种黑天鹅事件发生时,一方面,高响应力的公司能够快速推出像疫情地图、行程码这种全新的服务,以造福社会服务大众;而一方面,陈旧的遗留系统却在拖着整个时代的后腿。

用巴菲特的话说就是,当潮水退去之后,你才知道谁在裸泳。如果说不得不为,那怎么为之更好呢?

在数字化时代,每家企业都应该意识到科技是核心竞争力,要依赖科技去重塑业务、创造新的商业模式,创造数字化收益。也就是我们常说的 Tech@Core。

很多互联网公司的数字化基因是与生俱来的,它们能够根据当前的形式和热点迅速地开启一个全新的商业模式并站稳脚跟。比如在疫情下买菜难的问题,很多公司就迅速推出了买菜 App。

然而与此同时,对于传统企业来说,与上下游客户和供应商合作的数字化需求其实也是在不断增多的。

以汽车保险这个行业为例,与车主、4S 店、汽车制造商、交管系统等等合作方之间,存在着大量的互联需求,这里面有很多商机。

一个有雄心的企业是不可能用一个落后的遗留系统去应对这些挑战的。

在这里插入图片描述

所以,迎难而上是必须的,让老旧、过时的遗留系统变得现代化也是必须的,这样才能更好地为企业的战略和运营服务。


五、总结

从业界对遗留系统的定义中总结出了 4 个关键字:

  • 旧、
  • 过时、
  • 重要、
  • 仍在使用。

然而人们对于遗留系统的认识存在一个普遍的误区,即时间长的系统就是遗留系统。事实并非如此。有些系统时间虽长,但如果一直坚持现代化的开发方式,在代码质量、架构合理性、测试策略、DevOps 等方面都保持先进性,这样的系统就像陈年的老酒一样,历久弥香。而有些系统虽然刚刚开发完成,但如果在上述几个方面都做得不好,也可以把它叫做遗留系统。遗留系统在维护成本、合规性、安全性、集成性等方面都会给企业造成巨大的负担,但同时也蕴含着丰富的数据和业务资产。应该对遗留系统进行现代化,让它重新焕发青春。


相关文章:

Day949.遗留系统之殇:为什么要对遗留系统进行现代化? -遗留系统现代化实战

遗留系统之殇:为什么要对遗留系统进行现代化? Hi,我是阿昌,今天学习记录是关于遗留系统之殇:为什么要对遗留系统进行现代化?的内容。 不知道你是否跟曾经一样,身处一个遗留系统的漩涡之中&…...

DAY 45 Nginx服务配置

Nginx概述 Nginx: Nginx 是开源、高性能、高可靠的 Web 和反向代理服务器,而且支持热部署,几乎可以做到 7 * 24 小时不间断运行,即使运行几个月也不需要重新启动,还能在不间断服务的情况下对软件版本进行热更新。 对…...

如何收集K8S容器化部署的服务的日志?

做开发的同学都知道日志的重要性,日志的种类一般有接口日志、错误日志、关键步骤日志、用户操作日志等。本文主要详细讲解使用kubernetes容器化部署的服务该如何记录和收集日志。 一、使用标准输出方式 将想要记录的日志内容输出到stdout或stderr即可(…...

python删除csv文件中的某几列或行

1. 读取数据 用pandas中的read_csv()函数读取出csv文件中的数据: import pandas as pddf pd.read_csv("comments.csv") df.head(2)用drop函数进行文件中数据的删除行或者删除列操作。 2. 删除列操作 方法一:假设我们要删除的列的名称为 ‘观众ID’,‘…...

Redis持久化机制导致服务自启动后恢复数据过长无法使用以及如何关闭

场景 若依前后端分离版手把手教你本地搭建环境并运行项目: 若依前后端分离版手把手教你本地搭建环境并运行项目_霸道流氓气质的博客-CSDN博客 在上面搭建前后端分离的项目后,如果需要在windows服务上进行部署。 若依前后端分离版本,Windo…...

DAY 37 shell免交互

Here Document 概述 常用的交互程序:read,ftp,passwd,su,sudo cat也可配合免交互的方式重定向输出到文件 Here Document 的作用 使用I/O重定向的方式将命令列表提供给交互式程序标准输入的一种替代品 格式 命令 …...

用python脚本从Cadence导出xdc约束文件

用python脚本从Cadence导出xdc约束文件 概述转换方法先导出csv文件修改CSV文件 CSV转XDC检查输出XDC文件csv2xdc源代码下载 概述 在Cadence设计完成带有FPGA芯片的原理图的时候,往往需要将FPGA管脚和网络对应关系导入vivado设计软件中,对于大规模FPGA管…...

【C++ 六】内存分区、引用

内存分区、引用 文章目录 内存分区、引用前言1 内存分区模型1.1 程序运行前1.2 程序运行后1.3 new 操作符 2 引用2.1 引用基本使用2.2 引用注意事项2.3 引用做函数参数2.4 引用做函数返回值2.5 引用本质2.6 常量引用 总结 前言 本文包含内存分区、引用基本使用、引用注意事项、…...

markdown基本语法

来自神秘人儿的投稿! markdown的使用,可以参考https://markdown.com.cn/basic-syntax/ 标题:用 # 表示 段落:enter即可,两端之间有一个空行 换行:一行的末尾加两个或者多个空格,两端之间没有…...

第十篇 Spring 集成Redis

《Spring》篇章整体栏目 ————————————————————————————— 【第一章】spring 概念与体系结构 【第二章】spring IoC 的工作原理 【第三章】spring IOC与Bean环境搭建与应用 【第四章】spring bean定义 【第五章】Spring 集合注入、作用域 【第六章】…...

PADS-LOGIC项目原理图设计

最小板原理图设计 目录 1 菜单与工具使用 2 常用设置 2.1选项卡 2.2 图纸设置 2.3 颜色设置 3 设计技巧 3.1 模块化设计思路 3.2 元件放置 3.3 走线及连接符 4 原理图绘制 4.1 POWER原理图设计 4.2 MCU原理图设计 4.2.1晶振电路 4.2.2复位电路 4.2.3 BOOT电路 …...

36岁大龄程序员被裁,找了2个月工作,年包从100万降到50万,要不要接?

为了找到工作,你愿意接受降薪多少? 一位36岁的杭州程序员问: 36岁被裁,找了2个月工作,年包从100万降到50万,真心纠结,要不要接? 网友们分成了旗帜鲜明的两派,一派人认为不…...

Android Retrofit 源码分析

1、简介 Retrofit 是一种基于 Java 的 RESTful Web Service 客户端库,它可以将网络请求抽象出来并支持多种转换器,可以将 JSON、XML 和其他格式的响应数据自动转换为 Java 对象。Retrofit 通过注解的方式来描述 REST API 调用,使开发人员能够…...

CDN如何阻止网络攻击

随着网络技术的发展,网络攻击事件也越来越多,对企业和个人的安全和稳定造成严重威胁。为此,高防CDN应运而生,成为广大用户保障网络安全的重要工具。什么是高防CDN?高防CDN的特点有哪些?高防CDN如何阻止网络攻击?接下来让我们一…...

Mybatis-Plus -04 条件构造器与代码生成器

Mybatis-Plus--条件构造器与代码生成器 1 条件构造器1.1 > < 1.2 in notin1.3 between...1.4 orderBy...1.5 like... 2 代码生成器2.1 引入依赖2.2 生成器代码 1 条件构造器 通过条件构造器可以更加轻松的完成条件查询与更新(底层就是动态SQL) 1.1 > < ge 小于 &l…...

MapReduce高级篇——全局计数器

MapReduce Counter 计数器 概念 在执行MapReduce程序的时候&#xff0c;控制台输出日志中通常下面片段&#xff0c;可以发现输出信息中的核心词是counter,中文叫做计数器 在执行MapReduce城西过程中&#xff0c;许多时候&#xff0c;用户希望了解程序的运行情况&#xff0c;H…...

轻松掌握K8S目录持久卷PV/PVC的kubectl操作知识点04

1、介绍 在docker中可以将容器中的目录挂载出来&#xff0c;在k8s中pod可以部署在不同节点&#xff0c;假如该节点的机器宕机了&#xff0c;k8s可能就会将此Pod转移到其他机器&#xff0c;就不是原先的机器了。k8s有自己的一套挂载方案&#xff0c;如下图所示&#xff0c; 原…...

Appuploader证书申请教程

转载&#xff1a;IOS证书制作教程 点击苹果证书 按钮 点击新增 输入证书密码&#xff0c;名称 这个密码不是账号密码&#xff0c;而是一个保护证书的密码&#xff0c;是p12文件的密码&#xff0c;此密码设置后没有其他地方可以找到&#xff0c;忘记了只能删除证书重新制作&…...

acwing17给了一个头节点,从尾到头输出链表的元素,顺便练练容器

方法一 建立一个数组&#xff0c;从头到尾遍历一遍链表&#xff0c;然后将链表的每个元素的值赋给数组 犯了一个错误 新建的vector容器是一个可变长的数组&#xff0c;要想像数组下标那样访问前提是这个下标所指向的元素得存在&#xff0c;这也就跟那个声明一维数组得写出长度来…...

Linux 性能优化大全!

性能指标 高并发和响应快对应着性能优化的两个核心指标&#xff1a;吞吐和延时 应用负载角度&#xff1a;直接影响了产品终端的用户体验 系统资源角度&#xff1a;资源使用率、饱和度等 性能问题的本质就是系统资源已经到达瓶颈&#xff0c;但请求的处理还不够快&#xff0…...

精通 TensorFlow 2.x 计算机视觉:第一部分

原文&#xff1a;Mastering Computer Vision with TensorFlow 2.x 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;…...

mulesoft MCIA 常用词汇、知识点汇总

mandate 授权 carry out 执行 subscriptions 订阅 stakeholders 利益相关者 periodically 定期地 Idempotent 幂等的 on-premises 本地 mutual 相互 two-way 双向的 arbitrary 任意的 mandatory 强制性的 round-robin 循环 replicate 复制 compensating actions 补…...

Python 单样本学习实用指南:1~6 全

原文&#xff1a;Hands-On One-shot Learning with Python 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;只关心如…...

心血管疾病数据探索分析

心血管疾病数据探索分析 初步数据分析 首先,导入挑战所需模块: import pandas as pd import numpy as np import seaborn as sns import matplotlib import matplotlib.pyplot as plt import matplotlib.ticker from matplotlib import rcParams import warnings warnings…...

Pandas的应用-1

Pandas是一个开源的数据分析工具&#xff0c;它提供了高性能、易于使用的数据结构和数据分析工具。其中&#xff0c;Series是Pandas中最基本的数据结构之一&#xff0c;它是一种类似于一维数组的对象&#xff0c;可以储存任何数据类型。在本文中&#xff0c;我们将介绍Series的…...

【状态估计】电力系统状态估计的虚假数据注入攻击建模与对策(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

【Spring】Spring @Import注解的使用和源码分析

文章目录 介绍Import导入bean的三种方式普通类ImportSelector接口ImportBeanDefinitionRegistrar接口 源码解析总结 介绍 今天主要介绍Spring Import注解&#xff0c;在Spring中Import使用得比较频繁&#xff0c;它得作用是导入bean&#xff0c;具体的导入方式有多种&#xff…...

C++中的类与对象

类与对象 我们在C语言中自定义的struct 叫做结构体&#xff0c;而在C中我们把struct升级为了类&#xff0c;并且还加入了一个class&#xff0c;也称为类&#xff0c;那么我们今天就来看一下结构体和类的不同和相同 1.结构体与类 我们在C语言中的结构体是struct&#xff0c;而…...

探索Qt图像处理的奥秘:从入门到精通

探索Qt图像处理的奥秘&#xff1a;从入门到精通&#xff08;Exploring the Secrets of Qt Image Processing: From Beginner to Expert&#xff09; 引言&#xff1a;Qt图像处理的概述和应用&#xff08;Introduction: Overview and Applications of Qt Image Processing&#…...

springboot+vue企业人事人力资源管理系统java公司员工出差考勤办公OA系统

“简易云”是这个系统的名字 &#xff08;6&#xff09;系统管理&#xff1a;主要下拉分为角色管理、菜单管理&#xff1b; 角色管理&#xff1a;此页面可对角色进行增删改查操作&#xff0c;可修改不同角色的权限&#xff1b; 菜单管理&#xff1a;此页面可配置系统可展示的菜…...