跳转至

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

你好,我是姚琪琳。

不知道你是否跟曾经的我一样,身处一个遗留系统的漩涡之中,每天为毫无头绪的代码和混乱不堪的架构发愁。一个新的需求来了,都不知道从哪儿开始改起,即便看似简单的需求都要很久才能上线。

假如你也如此,请不要悲伤,也不要心急,其中有很多妥善的应对之法,我会在这个专栏中一一交付给你。

但在此之前啊,我想我们是不是得先明确一下,到底什么样的系统才能称之为遗留系统呢?它存在哪些问题,复杂在哪里?

这节课我们就来一探究竟,好为我们后面深入学习遗留系统奠定一个良好的基础。同时,我们也可以看看在高成本的现代化改造之下,为什么遗留系统还要迎难而上?

关于遗留系统的误区

请你先思考这样一个问题:假如一个系统七八年了,它是不是个遗留系统?

系统的时间长等同于就是遗留系统,这是很多人的一个误区。虽然大多数遗留系统确实是存在的时间很长,但并不等于时间长的都是遗留系统。

这里分享一个我的项目经历。我之前曾在一个项目上工作6年多,这是一个有着12年历史的老项目。

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

这个系统历时12年之久,比很多公司活的时间都长。那它是遗留系统吗?答案是否定的。因为它的代码质量高、架构合理、自动化测试丰富、DevOps成熟度也高,各种技术、工具都是相对先进的,怎么能说是遗留系统呢?

这里我还想请你进一步思考一下:存在时间短的系统就不是遗留系统吗?

仍然拿我个人经历过的一个项目来举例。它是07年左右开发完成的,当我10年加入项目组的时候发现,它仍旧是基于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等方面都保持先进性,这样的系统就像陈年的老酒一样,历久弥香。而有些系统虽然刚刚开发完成,但如果在上述几个方面都做得不好,我们也可以把它叫做遗留系统。

遗留系统在维护成本、合规性、安全性、集成性等方面都会给企业造成巨大的负担,但同时也蕴含着丰富的数据和业务资产。我们应该对遗留系统进行现代化,让它重新焕发青春。

那么遗留系统的现代化都包含哪些方面呢,下节课我们就揭晓谜题。

思考题

如果你现在正工作在遗留系统上,你或你的团队最大的痛点是什么?你们又是如何解决这些痛点的?

期待你的分享,我们可以在留言区进行互动交流!如果今天的学习让你有所收获,也欢迎把课程分享给有需要的朋友,我们下节课再见!

精选留言(15)
  • 子夜枯灯 👍(3) 💬(1)

    目前工作的遗留系统是单体应用,架构混乱并且没有任何测试。每次开发时都需要大量的人工测试。方案文档不连续,参加价值很低。

    2022-04-12

  • aoe 👍(2) 💬(6)

    在遗留系统中上班写bug加班改bug 目前应对策略; 1、新功能使用TDD开发 2、修改原有功能时尽量加一些测试 3、修改特别复杂的原有功能,基本靠运气

    2022-04-12

  • 刘大明 👍(6) 💬(3)

    老师您好,感谢抽空回答。接上次提问。 我先介绍下项目背景,和自身定位. 自己属于客户二开工程师,也就是针对现有的代码进行二次开发。 开发ide:eclipse 开发数据库:oracle11g 开发代码:本地home文件库 痛点如下: 1.全国各地是部署在各个项目本地机器上面,开发的代码包括源文件全部集中在本地环境,导致代码没有版本管理,会导致开发的文件冲突。 2.项目属于老旧巨石项目,本地home文件库一般都是10几G以上,数据库都是几百G,而且很多都是内网环境,可能需要挂VPN才能访问。 3.平时的开发模式,就是先操作页面,然后录入操作日志,定位具体的代码文件,然后本地起开发环境去debug该文件,根据现象去定位具体的代码可能出现的问题(可能需要重复debug的次数),找到问题之后,修改相应代码,一般不敢新建文件,只能在旧文件里面去新增方法,导致代码坏味道很重,但是不敢重构。 4.测试,修改代码完成之后,重启服务(可能需要10来分钟),之后在页面看效果,成功就给实施出相应文件的补丁包,实施经理将补丁放到线上环境验证改动是否成功。 说明:因为自己还是老测试方式,起服务,页面手动看效果,然后debug跟踪代码,debug效率有时候会很慢,不然定位不到具体的问题。 想请教下老师,基于这样一个背景下,以及自己的身份,怎么最大化提高工作内容呢,或者说针对这种遗留项目需要怎么做,才能变的更好呢?现在有点迷茫。。。。

    2022-04-12

  • 刘大明 👍(5) 💬(1)

    现在在维护老项目,基于本地的工作库开发,工作库很大有10几个G,而且源码都是根据class反编译出来的才能二次开发,有些页面是基于swing开发的,但是客户已经习惯了这种操作模式,想请教老师,这种开发模式属于遗留系统,应该怎么改造呢?

    2022-04-11

  • lipop 👍(2) 💬(1)

    自动化测试需要做到分支覆盖吗,分支覆盖的话感觉光是写测试用例就超过了开发的时间

    2022-04-18

  • 2022 👍(1) 💬(1)

    痛点: 1. 项目周期安排紧凑,总有各种各样的原因导致项目延期 2. 设计之初写的设计文档,大致方向没问题,细节上会出现多处变动,但项目开发完后,没人去更新设计文档了。人员流动后,对于修复该模块的bug,可能存在改一发而动全身 3. 开发的代码,没有进行自动测试,全依赖人工测试 4. 开发人员水平高低,导致即使有设计文档,但写出来的代码架构完全没法看(只保存了最终需求是按照设计文档上做的)。

    2022-04-24

  • 术子米德 👍(1) 💬(1)

    🤔☕️🤔☕️🤔 * 📖:遗留系统 :!=长时间存在的系统,!=短时间存在的系统。判断维度:代码<cha>、架构<luan>、测试<wu>、DevOps<shou>、技术<jiu>、工具<lao>等方面。 * 🤔:代码差,可以重写;测试无,可以补上;DevOps手动,可以改造;技术旧,可以学习;工具老,可以更新;可是,架构乱,难道要重来嘛,那所有的可以都变得可以,还是都变得不可以。这是架构带来的最大困惑,它不是问题的时候,就当它不存在,它称为问题的时候,就像空气里放进点硫磺,怎么也弄不干净的味道。不过,如果核心问题真的是架构乱,重写、补上、改造、学习、更新估计都不顶用。架构的问题,要么是基因病,要么是血液病,发作起来,所有的组织和结构,都无法幸免。 * 📖:遗留系统蕴含数据资产,隐藏业务知识,它很重要,它还能用。 * 🤔:遗留系统有点像泥石流后形成的冰川,又乱又脏的感觉,搬不动挪不走的样子。但是它蕴含着大量的淡水,它携带着气候变化的信息。

    2022-04-22

  • _MISSYOURLOVE 👍(1) 💬(1)

    如此看来,我们维护的也是一个遗留系统了;据说系统最初的版本是由外包团队开发,后面由公司自己的技术团队接手开始维护,代码质量一言难尽,基本就没有什么文档可言,都已经2022年了,某些项目还一直是使用前后端耦合的方式在进行维护着,由于年代久远,某些业务功能连产品都不知道具体逻辑,需要进行改造的时候,还需要我们去看代码然后给产品梳理相关的业务逻辑

    2022-04-17

  • 公号-技术夜未眠 👍(1) 💬(1)

    老师好,遗留系统和现代化系统进行集成的策略和步骤有哪些?谢谢

    2022-04-11

  • 西米 👍(0) 💬(1)

    我们现在的系统就是一套大的单体系统,虽然它才上线5年,目前是基于 .net core 3.1 。部署在Azure web app上,看了老师您这篇文章,我可以很快的定义它为:遗留系统,因为没有 devops、测试全靠人工黑盒测试。目前公司也下定决心开始 大力全新打造一套系统。

    2022-04-18

  • escray 👍(0) 💬(1)

    按照代码质量差、架构混乱、没有测试、纯手工 DevOps、陈旧的技术和工具……这样的标准来说,我们现在正在开发的,就是遗留系统。 如果以后还有机会写代码,至少要找一个有单元测试的地方。 为什么要对遗留系统进行现代化,在文中已经说的很明白了,主要是因为维护成本高以及安全隐患,而遗留系统的价值在于不可替代、数据资产、业务知识。 记得之前有专门招聘 COBOL 程序员的,似乎维护遗留系统也还是挺有“钱途”的。 给一个不进行现代化的理由,因为体制内的单位大多是项目制的,一个项目做完了之后,维护是没有多少经费支持的,只能再从头来二期。而且,不懂技术的业务领导,往往追求“新潮流技术”,云计算、大数据、人工智能……,但是他们却不会注意到单元测试、CI/CD、DevOps 之类的。 对于寻呼机的例子,我觉得不是很合适,不知道现在是否还在用,但是寻呼机似乎是比较适合医院场景的。在 2019 年之前,还是有大量的医院使用寻呼机的,主要原因是信号、电池和便携,后来也看到在 2021 年前后会逐步被升级或替代。 https://www.thehealthy.com/healthcare/doctors/hospital-pagers/ https://www.medicaldevice-network.com/analysis/how-will-uk-hospitals-let-go-of-the-pager/

    2022-04-13

  • Bradly 👍(0) 💬(2)

    目前系统最大的痛点是基础表设计不合理导致系统性能很差。而这些数据又是最重要的数据,改起来难度很大。

    2022-04-12

  • Jaising 👍(1) 💬(0)

    经过一段时间观察积累,我发现遗留系统重构更多体现了一名开发人员的软件设计能力,是否具备面向未来变化的预估与抽象能力,真正让软件“软”起来快速响应变化,而不仅仅是当下一亩三分地的产出。 从开发者视角看,一方面大量涌入行业的新人没有意识遗留系统的危害,另一方面不具备重构能力想改又改不动,见树木不见森林,最后只能对自己熟悉的领域修修补补。 以前我也会认为系统重构纯粹是个技术债务,后来发现这是一个工程问题,到现在意识到它也关乎商业价值。从哪里动手、改造哪些、带来的收益是什么,本身也是一个反复迭代纠正的事情。现在践行最好的方式就是将系统重构纳入日常,没有测试保障的就先面向可测试性设计,具备测试能力再补全测试用例,并不断打磨业务模型,将重构的成本降低、重构速度提升,保证每次修改比上一次有一点进步。因为系统功能不变化,安全性、合规性这样的外部环境变化一样会将系统推上重构之路。

    2024-09-13

  • 苜蓿° 👍(0) 💬(0)

    上面全中; 1、代码很差,因为太过久远,类似的功能只敢复制简单修改来用;而且全部都是if,一个if几千行的都有; 2、架构,因为是外采系统,基本上没有什么架构,到处都可以开发,到处都可以连接数据库 3、测试、DevOps 以及技术和工具这些基本上都是全靠人工,关键测试都是依靠核心开发才行 针对以上有两个阶段 第一阶段 1、研发梳理现在系统逻辑,并做分享和每周过会; 2、拆分系统,先从大的方面分为几个小服务,代码基本是完全复制,新功能新服务开发;数据库也按照职责拆分 3、埋点数据源,统一抽取隔离分离源 第二阶段 搭建新项目,初步替代和替换就系统

    2024-12-23

  • 伊诺 👍(0) 💬(0)

    一个长生命周期项目,交叉开发。总想动手改造前人代码👁

    2023-11-27