查看原文
其他

2020 年的 BUG

liuyubobobo 是不是很酷 2021-06-01

2020 年到来以后,全世界不同地方的软件系统,出现了一些 bug。


纽约街边的停车收款机,突然从 2020 年的第一天开始,不能正常接收信用卡支付了。


这使得人们只能使用硬币或者纽约市的专属停车收费 app:ParkNYC 进行付款。但是,都 2020 年了,很少有人会随身携带一堆硬币。至于这个停车收费 app,因为必须要预先存进去 25 美元才可以使用,引来了很多人,尤其是游客的不满。


一时间,纽约市怨声载道。现在,纽约的交通部正在抓紧处理这个问题,然而,他们需要为整个城市的近 14000 个停车收款机升级软件程序。



波兰的一家公司 Novitus,在 2020 年来临的第一天,所有的收银机,都不能正常地打印票据了。如今,公司也正在紧急地修复这个问题。



一款著名的拳击类游戏:WWE 2k20,在 2020 年的第一天,突然无法正常运行了。然而,如果用户把系统时间修改为 2020 年以前的任何一天,游戏都能正常运行。




德国汉堡市的地铁,在新年来临的第一天,延误了一段时间。据报道是因为一次软件升级失败导致的。大概率的,这次升级失败,也是因为时间走到了 2020 年。



splunk 是一家硅谷的创业公司,专门分析服务器产生的数据,从而快速完成业务分析、安全事件审计、DDoS 攻击监控等等服务。2019 年 11 月,splunk 发现自己的软件系统在 2020 年到来的时候,将无法正常运作。所以,splunk 强制他的所有客户——包括美国前 100 强企业的 92 家,来升级系统,以避免这一“灾难”。





为什么有那么多软件系统在 2020 年到来的时候,会产生 bug?这个问题,和本世纪初的千年虫 bug 的原理,是一模一样的。


所谓的千年虫 bug,是指当时间走到 2000 年的时候,很多软件系统会崩溃。


为什么时间走到 2000 年的时候,软件系统会崩溃?因为在很多软件系统中,年份是使用两位数字来存储的。


如果是 98,或者 99,我们可以很安全地认为,时间是 1998 年或者 1999 年,规则就是在这两位数字前面加上 19。但是,对于 00,加上 19,就是 1900 年,而不是 2000 年。于是,时间发生了错误,整个软件系统将不能正常运转。


工程师们很早就意识到了千年虫 bug 的存在,于是,在新世纪来临之前,各个软件公司都在全力解决这一问题。甚至,在那个年代,有一个专门的职位,叫“千年虫工程师”,顾名思义,就是专门解决千年虫问题的。


在当年,千年虫工程师是平均薪资最高的工程师。据报道,和千年虫相关的“修补”工作,大约造成了全世界 3000 亿到 5000 亿美元的损失。


讽刺的是,在 2000 年以后,千年虫工程师这个职位都不复存在了。





时间来到今天,2020 年之所以会发生这一系列的 bug,和千年虫的原理一样:系统使用两位数字存储年份。


但这一回,对于这些软件系统,18 或者 19 可以被系统正确地认为是 2018 年或者 2019 年。不过,当时间走到了 20,系统懵逼了,会误以为是 1920 年。


为什么?因为 1920 年,是很多系统的“标定年”,英文叫做 pivot year。也就是系统会自动在 00 到 19 这些年分之前加上 20,表示 21 世纪的年份;而会给 20 到 99 这些年份之前加上 19,表示 20 世纪的年份。


为什么会将 1920 年作为“标定年”?这又牵扯到一段计算机科学的历史。


熟悉“时间戳”的同学都知道,UNIX 系统定义起始时间为 1970 年 1 月 1 日 0 时 0 分 0 秒。所以,这个时间是 UNIX 世界的起始时间。


随着 UNIX 在服务端的普及和流行,这个起始时间甚至超越了 UNIX 系统,成为了整个计算机世界的起始时间。就算没有接触过 UNIX 的同学,无论是在数据库中,还是在各个语言的时间戳转换的函数中,都应该接触过这个“知识点”:0 这个时间戳,表示 1970 年 1 月 1 日 0 时 0 分 0 秒。


这也解释了为什么大家在处理和时间相关的程序的时候,有的时候,一不小心,显示的时间是 1970 年 1 月 1 日 0 时 0 分 0 秒。如果在国内的同学,可能会经常看到 1970 年 1 月 1 日 08:00。这是因为,UNIX 定义的起点时间,是以格林威治时间为准的。而由于中国时间以北京时间为准,而北京在东八区,所以,对应 UNIX 起点时间,就是 1970 年 1 月 1 日 08:00。


这和 1920 年有什么关系?答案是,1970 年前后各取 50 年,就是 1920 和 2020 年。所以,很多计算机系统都以 1920 年作为“标定年”,来转化两位数字表示的年份。而这种转换,到了 2020 年,就失败了。





2020 年 bug 的一个简单解决方案,就是使用四位数字,而非两位数字来表示年份。这么简单的一个方案,为什么当时不采用?


答案是,如果回头看 20 年前,甚至 30 年前的计算机系统,存储空间还是极度紧张的。100 以内的两位数字,只需要一个字节就可以表示;而 4 位数字,则需要两个字节,整整多了一倍。


这个存储空间的差距,现在看起来简直不值一提。但是,在二三十年前,事情可完全不一样。


我是 1998 年拥有的第一台个人电脑的,那个时候的硬盘容量,我印象很清楚,只有 512 MB,还算高配了。而那时的主要移动存储介质,是一种叫做软盘的介质。每片软盘,只能存储 1.44 MB 的内容。


1998 年尚且如此,更不用提 1990 年了。而个人电脑处理的数据和资料毕竟有限。如果是服务器,每天处理成千上万的数据,在时间存储上,使用两位数而非四位数,绝对是一个重要的优化。如果大家能找到那个年代的服务器开发教程,甚至会特意强调这个优化。


然而,这个曾经的优化,如今成为了 bug 的源泉。



另一个重要原因,在于很多人并不认为某个程序或者某段代码能运行 20 年,30 年之久。甚至,多数人不认为自己写的程序能运行 5 年时间。


虽然,在大多数情况下,这个结论是正确的。软件发展的速度出奇的快,大多数代码很快就会淘汰掉。但是,仍然有少部分代码,坚强地一直运行着。


而且,每一个软件工程的开发,并非都是从 0 开始的。以 MacOS 系统为例,我们看其中的 API 命名,包括部分框架的设计模式,就能明白这其中包含着多少遗留的历史代码了。


所以,即使某一个软件产品退出了历史舞台,但是其中的代码片段,很有可能继续以一种不为大众所知的方式,存在于现代世界中。这些代码片段中的 bug,好像从“远古时期”乘坐时间机器来到今天,成为当下的安全隐患。



有意思的是:这种事情能完全避免吗?答案是不能的。


因为,这样的 bug,本质不是逻辑错误,而是假设错误。然而,这样的假设错误,站在当年的视角看,不仅不是错误,甚至可以叫做是“优化”。


可是,短短 20 年,这就变成了一个错误。


这就好比,如今,我们不可能选择使用五位数去存储年份一样。然而,到了 9999 年,这将成为一个大问题。


这件事非常好地向我们阐述了软件工程的复杂性。软件工程本身不是绝对的数学公式推导。在软件工程的很多实现方案中,是没有绝对的“对”和“错”的,而是具有相应的时代特点的。


然而,在一个时代中,绝对正确的事情,到了另一个时代,很有可能是存疑,甚至是绝对错误的。


这样的事情,在人类的文明历史中,时常发生。比如封建君主制,比如希特勒,比如冷战思维。如今,这样的事情,也发生在了软件的世界中。


这说明了什么?


软件本身,已经毫无疑问地,成为了人类文明的一种体现形式。和书籍,音乐,电影,雕塑,等等等等,是一样。


而软件工程师,则是这种人类文明体现的书写者。


嗯,反正我就是这么“骗”自己的:



大家加油!





本文相关阅读推荐:


bug 变 feature


如果程序语言是音乐


王垠的面试 和 P 与 NP


软件工程师,工作效率,以及网易




《是不是很酷》虽然只是一个个人公众号,但在用心做技术原创。每周至少两次更新。希望一起陪你,用技术人的眼光,观察这个世界,探索这个世界。


如果喜欢我的文章,点个”在看“吧 

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存