「InfoQ」代码没人懂,一个bug导致千万损失,程序开发者去世( 二 )


该系统从表面上看并非一无是处 。 它使用了现代编程语言和技术栈(Java8)编写 , 由拿着六位数收入的开发人员所组成的团队进行着日常维护 , 并不断更新以修复错误和添加新功能 。 尽管如此 , 测试修改(turnover)依然是拖累整个系统的显著负担 。 所有权变更和团队更替导致整体代码设计、端到端功能、最佳实践和调试技术等大量实操知识的丢失 。 尽管我们一直努力保持项目的推进 , 但感觉就像进入了一片沼泽地 , 四处亡羊补牢 , 深陷战争迷雾(FogofWar)中 。
设想一下 , 一个运行在第一版Java上的项目 , 开发活动几乎为零 , 没有开发人员负责 。 还有比这更糟的项目吗?
如何预防发生灾难性故障
软件开发人员致力于构建健壮、无错误的系统 , 无需过多人工维护就能正常运行多年 。 据此标准 , 上面所说的养老金脚本无疑是非常成功的项目 。
然而现实很严峻 , 再好的项目有发生崩溃的一天 。 最终 , 所有内容都需要做更新 。 导致原因可能是:
系统运行所基于的硬件系统停产了 。
系统的依赖关系不再可用 。
依赖关系中出现了严重安全漏洞 , 而唯一可用的安全补丁仅适用于并不后向兼容的版本 。
应用开发基于一些已不再成立的假设 。
甚至是整个世界发生了改变 , 软件必需因势而变 。
无论出于何种原因 , 变更都是不可避免的 。 唯一的问题是 , 当最终需要变更时 , 它的代价有多大 。
对于一个活跃维护的系统 , 变更就不会那么痛苦 。 但是 , 对于一个已有几年甚至数十年没有维护的系统 , 那么很多因素都可能会导致灾难性的错误 。 例如:
构建系统的开发人员已经离职 。
源码丢失 。
开发人员不了解如何正确地编译源码 , 并构建可执行文件 。
开发人员不了解如何部署系统 。
开发人员不了解如何正确地配置运行可执行文件 。
【「InfoQ」代码没人懂,一个bug导致千万损失,程序开发者去世】开发人员对代码的架构和实现一头雾水 。
开发人员不了解使代码功能正常运作所依赖的常量和隐含假设 。
开发人员不了解如何运行自动化测试 。
开发人员不了解如何调试测试问题 。
开发人员不了解如何调试生产故障 。
开发人员不了解如何获取生产日志和指标度量 。
一种解决方案是对上述问题做尽量详细的记录 。 但文档并非最优的解决方案 , 因为其中难免会有遗漏 。 再全面的文档 , 也比不上自己亲自动手操作 。
理想的做法
一个好的开端 , 就是企业指定专门的开发人员全面负责上述所有问题 。 但这还不够 。
如果仅仅反复“阅读文档” , 那么就会产生厌倦 。 人们并不能从中获得实践经验 , 进而解决实际问题 。
如果加上“绩效审核” , 那么人们更倾向于新的出彩项目 , 很有可能会简单地抹去并掩盖旧的问题 , 甚至直接从中剔除问题 。 如果没有真正面对的可交付成果或挑战 , 许多人自然会选择一条最轻松的道路 。
真正要想避免软件发生溃烂 , 唯一的方法是确保项目的持续推进 , 即使看起来毫无必要 , 或是存在风险 。 建立、维护和验证实操知识和能力的最佳方法 , 就是不断做出变更 , 并测试这些变更是否能成功地执行 。 一旦项目停止推进 , 那么相关实操知识就会过时和消解 。
即使原地打转听上去很可笑 , 但这对疏于维护而言仍是一种进步 。 事实上 , 维护人员总是可以做一些事情实现向前推进 , 虽然步伐可能很小 。
一种做法是使用所有依赖关系的最新版本去更新开发环境 , 例如:
从JDK8迁移到11 。
更新JVM , 使用G1垃圾回收机制替代原先的CMS 。
将GCC编译器从版本5更新到7 。
将数据库从Postgres9.5更新到Postgres11 。
将AWSSDK从版本1.10更新到1.11 。


推荐阅读