【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

程序开发者去世,代码没人懂,一个 bug 导致千万损失

  • 2020-05-09
  • 本文字数:3321 字

    阅读完需:约 11 分钟

程序开发者去世,代码没人懂,一个bug导致千万损失

系统出故障了。当年负责写这个程序的开发者早在十五年前就去世了,现在已经没有人能读得懂他的代码了…


现在一些关键系统的运行仍依赖于过时的软件,但编写他们的人要么离职要么已经去世。中间也缺少维护或更新,导致现在几乎没人能理解它们,而且一旦出现 Bug 就会给企业造成不可挽回的损失。


而现实中的这种例子,远比你想象中的要多。

一个令人深思的故事

我的一位客户负责数项世界排名前一百的养老基金,该公司在前几个月成功的将程序搬到了云端。作为项目的主任架构师,前两天我很意外地直接收到了 CIO 的短信:“抱歉打扰,我们出 S1X 级的大问题了。你能下午飞过来吗?”



“S1X”是他们对“比最严重级别还要糟,级联影响到业务其它非直接相关部分”问题的定义。


事情看起来十万火急,当天晚上我就飞到现场进行了诊断,发现是该客户的系统中一个批处理任务发生了崩溃。


该任务每天晚上执行一次,通过写一个 CSV 文件为某些养老金计算缴费率,再将计算的结果输出到另一个收益(benefit)分配程序。原先收益分配程序设定为在缴费(contribution)低于预测(projection)时会向客户发出报警。由于上一个处理任务已发生崩溃,不再产生输出,因此程序认为“所有缴费为零”。


所以系统立即向该养老基金的经理们发出大量警报邮件,基金经理们被吓得赶紧从该项目里撤离了。


起初没有人找得出问题发生在哪里,在大家的记忆和工作记录中,这个批处理任务也从未崩溃过。编写该批处理程序的人已经在 15 年前离世了,并且数十年前就不再是该企业的员工了。尽管该批处理的程序代码规模不大,但非常难读。因为在编程时主要考虑的是提高计算效率,并未考虑如何适合他人阅读。当然,程序也没有留下任何测试。


事故发生的前一天,脚本在运行环境中的编排发生了一次更改。这被认为是导致事故的罪魁祸首。幸运的是,这个更改做了版本 push,工程部门据此回溯到先前的版本。但不幸的是,这只使事情变得更糟。


最后我们通过提供热修补脚本的方式解决了这个问题。但实质上这次崩溃已经给该基金造成了 170 万美元(约 1203 万人民币)的直接损失。

“数据溃烂”(Bit Rot)问题

事实上类似的故事并非孤例。我在 2012 年离开英特尔加入 Sun 公司,切身体会到他们的 SPARC 产品线做得是多么的糟糕。Sun 在互联网泡沫时代的杀鸡取卵行为,导致此后 SPARC 远远落后于英特尔的至强产品线。


我的经理都和我说,要在英特尔至强服务器上运行模拟程序,因为 SPARC 服务器“非常慢”。更严重的问题在于,英特尔不仅 CPU 性能更好,而且具有制造优势,这意味着 CPU 的制造成本也大大降低。


随之而来的问题很明显:既然远远落后于竞争对手,那么为什么客户还是会购买我们的 SPARC 芯片?一位高级架构师向我给出了令人震惊的答案。那是因为我们的客户的软件系统过于僵化,只能在 SPARC/Solaris 系统上运行。而迁移到 x86/Linux 对客户而言是一项艰巨的任务。许多客户甚至丢失了源代码,无法重新编译应用。


他们能做的最好选择,就是升级到最新一代的 SPARC 处理器,无论这样的处理器性能多慢,价格多么昂贵。


这就是问题所在。我们整个部门的业务模式,完全围绕着这个国家中那些溃烂的软件系统。

维持运转的代价

我加入 Amazon 后,发现自己面对正是这样一个为遗留系统而构建适用的原型。该系统是另一个团队基于大量技术债务开发的,并且团队早已解散。之后该项目的所有权就移交给我们的团队……事实操明,这并非揽下一件好事。所以开发人员陆陆续续跳槽到其他的团队。我加入时的十多名团队成员中,一年后一位都没有留下。


该系统从表面上看并非一无是处。它使用了现代编程语言和技术栈(Java 8)编写,由拿着六位数收入的开发人员所组成的团队进行着日常维护,并不断更新以修复错误和添加新功能。尽管如此,测试修改(turnover)依然是拖累整个系统的显著负担。所有权变更和团队更替导致整体代码设计、端到端功能、最佳实践和调试技术等大量实操知识的丢失。尽管我们一直努力保持项目的推进,但感觉就像进入了一片沼泽地,四处亡羊补牢,深陷战争迷雾(Fog of War)中。


设想一下,一个运行在第一版 Java 上的项目,开发活动几乎为零,没有开发人员负责。还有比这更糟的项目吗?

如何预防发生灾难性故障

软件开发人员致力于构建健壮、无错误的系统,无需过多人工维护就能正常运行多年。据此标准,上面所说的养老金脚本无疑是非常成功的项目。


然而现实很严峻,再好的项目有发生崩溃的一天。最终,所有内容都需要做更新。导致原因可能是:


  • 系统运行所基于的硬件系统停产了。

  • 系统的依赖关系不再可用。

  • 依赖关系中出现了严重安全漏洞,而唯一可用的安全补丁仅适用于并不后向兼容的版本。

  • 应用开发基于一些已不再成立的假设。

  • 甚至是整个世界发生了改变,软件必需因势而变。


无论出于何种原因,变更都是不可避免的。唯一的问题是,当最终需要变更时,它的代价有多大。


对于一个活跃维护的系统,变更就不会那么痛苦。但是,对于一个已有几年甚至数十年没有维护的系统,那么很多因素都可能会导致灾难性的错误。例如:


  • 构建系统的开发人员已经离职。

  • 源码丢失。

  • 开发人员不了解如何正确地编译源码,并构建可执行文件。

  • 开发人员不了解如何部署系统。

  • 开发人员不了解如何正确地配置运行可执行文件。

  • 开发人员对代码的架构和实现一头雾水。

  • 开发人员不了解使代码功能正常运作所依赖的常量和隐含假设。

  • 开发人员不了解如何运行自动化测试。

  • 开发人员不了解如何调试测试问题。

  • 开发人员不了解如何调试生产故障。

  • 开发人员不了解如何获取生产日志和指标度量。


一种解决方案是对上述问题做尽量详细的记录。但文档并非最优的解决方案,因为其中难免会有遗漏。再全面的文档,也比不上自己亲自动手操作。

理想的做法

一个好的开端,就是企业指定专门的开发人员全面负责上述所有问题。但这还不够。


如果仅仅反复“阅读文档”,那么就会产生厌倦。人们并不能从中获得实践经验,进而解决实际问题。


如果加上“绩效审核”,那么人们更倾向于新的出彩项目,很有可能会简单地抹去并掩盖旧的问题,甚至直接从中剔除问题。如果没有真正面对的可交付成果或挑战,许多人自然会选择一条最轻松的道路。


真正要想避免软件发生溃烂,唯一的方法是确保项目的持续推进,即使看起来毫无必要,或是存在风险。建立、维护和验证实操知识和能力的最佳方法,就是不断做出变更,并测试这些变更是否能成功地执行。一旦项目停止推进,那么相关实操知识就会过时和消解。


即使原地打转听上去很可笑,但这对疏于维护而言仍是一种进步。事实上,维护人员总是可以做一些事情实现向前推进,虽然步伐可能很小。


一种做法是使用所有依赖关系的最新版本去更新开发环境,例如:


  • 从 JDK 8 迁移到 11。

  • 更新 JVM,使用 G1 垃圾回收机制替代原先的 CMS。

  • 将 GCC 编译器从版本 5 更新到 7。

  • 将数据库从 Postgres 9.5 更新到 Postgres 11。

  • 将 AWS SDK 从版本 1.10 更新到 1.11。

  • 在生产环境中安装最新的 Linux 发行版。


在一些情况下,依赖关系会过时。这时就需要考虑整体迁移到新的架构。例如:


  • 从 SPARC 迁移到 x86;

  • 从 Solaris 迁移到 Linux。


同样,保持开发人员的战斗力,可对应用做如下更新:


  • 修复顽疾和一些边缘用例。

  • 加固自动测试套件。

  • 清理技术债务。

  • 做性能优化。

  • 实现新特性。

  • 增量重构代码库,改进可读性。


上述变化势必会带来暂时性风险,并产生看似“不必要的”支出。开发人员难免会犯一些错误,甚至引入新的错误。面对这些代价时,人们很容易退而求其次,认为“如果还没有破裂,就不要修复。”


对于一个业务价值不大的系统,这可能是合理的做法。但对于任何关键任务系统而言,忽略问题将仅会掩盖较小的瞬态风险,而没有解决永久的灾难性风险。一旦有一天需要紧急调试或更新系统,那么企业将无所适从。


对于任何关键任务系统,至关重要的就是维持实操知识和能力。做到这一点的唯一方法,就是不断地开展实操。企业的大脑和肌肉一样,不使用,就会失效。


作者介绍:


Rajiv Prabhakar,毕业于密歇根大学和斯坦福大学,之后曾在 Intel 和 Sun Microsystem 公司工作五年,参与了 Jaketown、Skylake 和 SPARC 设计团队。之后转向软件相关工作,先后任职于 Amazon、Google、Engineers Gate,并数次自己组建创业公司。


原文链接:


https://software.rajivprab.com/2020/04/25/preventing-software-rot/


公众号推荐:

2024 年 1 月,InfoQ 研究中心重磅发布《大语言模型综合能力测评报告 2024》,揭示了 10 个大模型在语义理解、文学创作、知识问答等领域的卓越表现。ChatGPT-4、文心一言等领先模型在编程、逻辑推理等方面展现出惊人的进步,预示着大模型将在 2024 年迎来更广泛的应用和创新。关注公众号「AI 前线」,回复「大模型报告」免费获取电子版研究报告。

AI 前线公众号
2020-05-09 09:0210774

评论

发布
暂无评论
发现更多内容

从源码全面解析Java 线程池的来龙去脉

做梦都在改BUG

Java 源码 线程池

全网更简单的方法,教你一键接入微信公众号,包教包会。包你成功。三包

派大星

ChatGPT

华为云大数据治理轻量级解决方案为中长尾企业赋能

轶天下事

selenium源码通读·13 |webdriver/support分析

Python 源码 测试 自动化测试 selenium

去哪儿网异常统计分析实践——Heimdall

Qunar技术沙龙

去哪儿网 Heimdall

开启数字化,传统工厂该如何布局?

优秀

数字化 数字工厂

Hive SQL on Flink 构建流批一体引擎

Apache Flink

大数据 flink 实时计算

企业办公转型的出路在哪里?华为云桌面开创办公新形式

轶天下事

神奇,声网Web SDK还能这么实现直播中美颜功能

声网

前端 Web RTC 美颜

案例实践|云智慧ITSM产品在利星行汽车的运维实践

云智慧AIOps社区

运维 ITSM ITSM软件 ITSM解决方案 IT 运维

横空出世!复盘B站面试坑我最深的Java并发:JDK源码剖析

做梦都在改BUG

Java 源码 jdk 高并发

太强了!京东首席架构师深邃洞察:服务化+云原生+微服务

做梦都在改BUG

Java 架构 微服务 云原生

Wallys AP controllers devices/IPQ4019 and IPQ4029 chipsets provide centralized management.

Cindy-wallys

IPQ4019 ipq4029

业务出海,华为云全球加速服务GA助一臂之力

轶天下事

selenium源码通读·12 |webdriver/remote分析

Python 源码 测试 自动化测试 selenium

AI与全民开发:挑战和机会并存

草料二维码

AI 无代码 全民开发

一文带你直观感受,BPM管理系统如何在低代码平台实现搭建

加入高科技仿生人

低代码 数字化 系统开发 BPM

ChatGPT会如何影响我们,会让我们失业吗?兼与吴军博士商榷 | 社区征文

李韧

人工智能 ChatGPT 三周年征文

Alibaba开发十年,写出这本“MQ技术手册”,看完我愣住了

程序知音

Java RocketMQ 消息中间件 Java进阶 后端技术

kafka高性能设计之内存池

做梦都在改BUG

Java kafka 系统设计 高性能 内存池

盘“底座”,盘出新生意经

用友BIP

05.01~05.07 NFT 生态热点汇总

NFT Research

NFT NFT\ #Web3

看火山引擎DataLeap如何做好电商治理(一):挑战与痛点

字节跳动数据平台

监控 模型 电商 数据平台 DataLeap

selenium源码通读·11 |webdriver/common/touch_actions.py-TouchActions类分析

Python 源码 测试 自动化测试 selenium

流行的DJ音乐混音软件:X Djing - Music Mix Maker for Mac

真大的脸盆

Mac Mac 软件 音乐混音软件

联合索引该如何选择合适的列?

江南一点雨

MySQL

数据库运维实操优质文章分享(含Oracle、MySQL等) | 2023年4月刊

墨天轮

MySQL 数据库 oracle postgresql 国产数据库

「微服务」这10道Consul面试题值得一看

王中阳Go

golang 微服务 面试题 服务发现 服务注册

Unity 发布《金融科技类APP用户调研报告》,应用内广告和搜索广告成为获客突破口

Geek_2d6073

虚拟模块在前端开发中的应用与示例

Lee Chen

JavaScript 前端

【web 开发】生活中大家都喜欢搞模板来规范化操作,抽象类却玩不明白-PHP的抽象类(63)

迷彩

模板 抽象类 三周年连更 抽象方法

程序开发者去世,代码没人懂,一个bug导致千万损失_语言 & 开发_Rajiv Prabhakar_InfoQ精选文章