在代码界, 有一个令程序员闻之心惊, 谈之色变的存在 -- 祖传代码(legacy code).
相信很多接触编程的人都对祖传代码有着难以言表的恐怖体验. 如果不改, 就难以实现新的需求, 支撑新的业务. 但一旦改了, 新出现的 bug 绝对能让人失去理智.
刚改完一行祖传代码
也正是出于以上的原因, 祖传代码才会经由一个个程序员之手, 代代相传, 生生不息.
那么问题就来了: 祖传代码为什么动不得?
回答这个问题之前需要弄清楚一个点, 那就是并不是所有的祖传代码在修改后都会出现 bug. 很多代码之所以能被 "祖传" 下来都是因为其严谨而实用.
但是, 更多的代码之所以会成为祖传代码, 都是因为其逻辑混乱, 再加上缺乏注释, 导致后来接手的人不敢轻易动手重构, 于是相关人员彼此之间心照不宣, 只管用不管改, 促使代码被祖传了下来.
于是, 第二个问题就来了: 既然祖传代码出现了问题, 为什么还能被运行和使用?
出现这种情况的原因一般有两种:
一, 外包不靠谱
系统的运行不是只写代码实现功能就完事了, 还要考虑到后期的可维护性. 而系统架构是极其复杂的, 并非一个外包就能完美解决的.
对产品需求的了解是一个长期的过程, 需要长时间与产品打交道. 而大部分外包都遵循着成本最小的原则, 缺乏对产品充分的了解, 导致最后的成品只是样子货, 禁不起再利用.
二, 缺乏可用文档
小七之前提到过, 养成写文档和为代码添加注释的习惯, 可以提高代码的可阅读性. 但很多人对自己的记忆力和理解能力有着迷之自信, 常常抱着 "功能都实现了, 为啥还要花时间写代码" 的心态, 能不写注释就不写. 以至于后面的人接手项目的时候完全不明白某部分代码的意义, 从而出现理解偏差, 导致逻辑混乱, 影响新功能的顺利实现.
一般情况下, 如果代码构成比较简单, 或许还能推导出其中的逻辑, 但如果写这串代码的是个 "天书派" 程序员, 那就只能自求多福了. 因为他可能自己都不知道为啥当初要写这行代码.
除了上面这两点, 还有很多因素会导致祖传代码被延续下来, 比如代码作者离职, 比如程序员为了保住饭碗 (国内还真有这种现象) 通过公共函数使逻辑复杂化, 再比如逻辑出错但不影响运行所以被保留了下来等等.
出于种种原因, 稍有历史的互联网公司业务都离不开祖传代码. 也因此, 很多历史遗留问题也被传承了下来.
亚马逊的工程师将他们公司的代码形容为 "一座很大的屎山, 你见过的最大的山, 每次你想修正一个 bug, 你的工作就是爬到屎山的正中心去."
亚马逊的平台架构是用 C++ 写的, C++ 的一大缺点就是缺乏自省. 而亚马逊有超过五千万行 C++ 代码, 所以一旦出现 bug, 解决方法就不是找到问题代码然后删除重写那么简单. 更别说, 有人可能好不容易爬到了屎山的正中心, 然后拉了一坨新的屎.
在互联网圈子里, 最常见到祖传代码的还是游戏行业. 即使是暴雪这样的游戏大厂也逃不开被祖传代码支配的命运.
暴雪的魔兽世界 (简称 WOW) 在 12 年前就进入国内了, 从最早的版本开始就支持默认 16 格背包.
但是, 随着游戏的不断更新, 16 格初始背包显然不能满足玩家的需求, 于是大家纷纷发邮件建议暴雪增加初始背包格数.
然而, WOW 在当时已经是一款很老的游戏了, 以至于暴雪自己都不记得是哪个挨千刀的程序员写的背包代码. 所以背包扩容的事就不了了之了.
直到今年 1 月份, 暴雪终于找到了那行代码, 增加了 4 个背包初始格. 而代价就是数不清的全新的游戏 bug.
除了亚马逊和暴雪以外, 很多人估计也都知道: 微软的 Windows 其实也是用的祖传问题代码. 因为要考虑到平台之间互相的可操作性, 所以 Windows 操作系统是建立在年复一年持续的代码维护基础上. 说白了就是只添砖加瓦, 不修复地基.
可能是意识到历史问题实在太多, 直到 2014 年 6 月, 微软才专门招人对遗留代码进行修复.
历史遗留问题是最难解决的问题, 而偏偏祖传代码就是这样的问题. 你永远不知道你接手的代码有着怎样奇异的身世.
你以为祖传代码很悲催, 但更悲催的是它已经八代单传; 你以为八代单传很悲催, 但更悲催的是它已经断了香火; 你以为断了香火很悲催, 但更悲催的是它可能根本就是无字天书.
所以, 如果遇到很恶心人的祖传代码, 不要想着推倒重写, 先找到写代码的人, 狠狠地揍一顿再说.
反正重写又不加工资.
文章来自公众号: 哈啰我的程序员 东半球最有趣的程序员聚集地
来源: http://www.jianshu.com/p/a35f717a11d1