作者在本节继续讲述复杂系统中bug的问题,有些bug甚至是人们无法消除的,我们能做到的就是不断从错误中学习,不断积累经验和知识。
在开源软件开发行业,“林纳斯定律”被许多人奉为真理。这个定律是以Linux系统的创始人林纳斯·托瓦兹(Linus Torvalds)的名字命名的,意思是“只要给予足够的关注,所有的bug都不是问题”。换句话说,如果能有足够多的人去检验某种技术,那么任何故障,无论它有多么复杂,看上去有多么难以处理,都是可以修复的,因为总会有人能找到解决办法。
但是,随着系统变得越来越复杂,这个“真理”似乎不再成立了。并不是所有的bug都可以消除:当我们面对复杂的充满交互的系统时,发现并消除每一个bug的可能性微乎其微,并且每一次修复都会引发新的问题。(永远有问题就不断修复呗)这听起来非常令人沮丧,但在某种程度上来说确实是这样的。幸运的是,我们至少还有一丝摆脱部分困境的希望。
“技术狼人”不仅是人类跨入新时代的标志,同时也为人类指出了管理复杂系统的新方向。波士顿大都会区的供水危机说明了,自来水不是“自动来的”,它也有真实的源头。不断地检测bug是我们了解这个纠缠时代的性质,并保证自身在此间繁衍生息的有限选择之一。(软件的生命周期中必不可少的就是bug修复嘛,长期永续工程)
几年前,谷歌公司的电子邮件服务系统Gmail出现过一次严重的服务中断故障,导致许多用户在大约18分钟内无法登录邮件系统。调查结果表明,问题出在谷歌软件的一个小更新包上。那是一个用来平衡邮件处理流量,以保证整个系统不会有任何一部分过载的软件包。软件包中的错误导致许多运行正常的服务器被认定为不可用。虽然这个错误并没有影响到谷歌的其他服务,但是由于Gmail需要特定的数据中心信息,所以它直接崩溃了。引发这个级联式故障的是一个很小的问题。对于这种级别的小问题,很少有人会预料到它会导致如此严重的系统故障。由此可见,系统中隐藏的某些互联性只能在发生故障时才会显现。(谷歌服务宕机,对全球的影响太大了,必须马上修复呀,谁能想到是这么小的问题)
在调试一项技术,或者在试图根除某个错误时,你会发现,系统的实际运行方式与你所期望的大为不同,无论是在汽车软件、互联网安全程序,还是城市基础设施中。在某些情况下,出现的错误都很简单,很容易被理解和修复;但是在更多的情况下,错误是不易被觉察的,甚至几乎不可能被诊断和修复。重要的是,对这种错误进行分类和编目,恰是我们研究复杂系统某个部分的第一步。(错误清单至少能避免再犯同样错误)这部技术世界的“博物志”至关重要,就像博物学家走进大自然、研究大自然,将物种及其复杂性分类编录一样,我们也需要对技术采用类似的研究方法。
我们将会越来越需要“技术博物学”。在这里,不妨再来看一个有关编程的例子。假设,你心中想着某个介于1至100之间的数字,而我的任务是尽可能快速并准确地猜到它。我会先问你,这个数字是不是超过了50;如果是,那么我会接着问你,它是大于75还是小于75……以此类推,我不断地将剩余数字一分为二,直到猜出你心中所想的那个数字。这种方法被称为“二分检索法”,其核心是将待搜索的数字分为两组。众所周知,这是一种在大型的有序列表中查找所需内容的高效方法。
在整个软件世界中,二分检索法的不同实现形式随处可见。因此,我在2006年读到谷歌公司所发布的一篇博客文章时深感不安。这篇文章讨论了二分检索法的多种实现形式,并指出了它们共同的失败之处:“号外!号外!请务必认真阅读本文内容:几乎所有的二分检索法……都崩溃了!”(数据量太大了,计算机也无法负载,和个人电脑检索大量数据类似的感觉)
虽然在普通软件中执行二分检索法的代码通常都能正常运行,但是事实证明,在涉及大量数据的情况下,二分检索法的许多实现形式都有可能会失败。那篇博客文章这样写道:“当数组的长度,也就是数组元素的个数达到了230及以上时,或者说多于10亿个元素时,二分检索法就会出问题。如此海量的数据在流行《编程珠玑》的20世纪80年代,是不可思议的事。《编程珠玑》是一本介绍计算机编程方法的经典著作,它所提出的二分检索法的实现形式也包含了这个错误。但是到了今天,在谷歌公司和其他地方,海量数据都已经很常见了。”(现在有了先进的数据库技术嘛,谷歌也有自己的云计算,算力超强了)
直到今天,在庞大的数据集随处可见的世界里,我们终于有机会发现这个错误,有机会更好地了解由我们一手打造的这个特定系统。通过这个bug,我们可以进一步地了解“技术实际上是如何运行的”,而不只是停留在“我们希望技术如何运行”的层面上。
还有很多其他例子也表明了,虽然技术系统为意想不到的行为提供了便利,但同时也让我们有机会了解到技术实际上是怎样发挥作用的。例如,1982年初,温哥华证券交易所发布了自己的股票指数,其编制方法与标准普尔500指数(S & P 500),以及道琼斯工业平均指数类似。这个股票指数的初始点位定在1 000点,然而在接下来的两年内,点位却持续下跌。到了1983年底,点位已经跌至原来的一半左右。这样的下跌是完全没有道理的,因为20世纪80年代早期的股票市场是一个大牛市。那么,这个指数为什么会持续下跌呢?有关方面展开了调查,最后发现这个指数的计算方法是错误的:它会直接把小数点3位之后的数字全部舍去。例如,如果计算结果为382.452 7,那么被存储下来的数值会是382.452,而不是四舍五入后的382.453。(居然还有这样的细节错误)
这个过程每天都要上演数千次,正确的数值无处可寻,这意味着损失了很大一部分价值。(千分之一错误的累积,复利的威力可真大呀)1983年11月,这个错误终于得到了纠正:前一周周五,指数收盘于500点左右,但是到周一开盘时,指数已超过1 000点,失去的点位重新回来了。这个计算过程中的深层问题,准确地说是算法中的错误,在这样一个异常现象中被注意到。事后看来,这起事件——当股票市场向好的时候,指数却在下跌,其实并不微妙。(也能解答我们国内的一些疑惑,咱们是十几年长期不涨原地踏步,哈哈)
我们还发现,企业和政府在利用复杂的机器学习算法,对海量数据进行挖掘时,也出现了不少类似的失败案例。在大多数情况下,这些机器学习系统对于公众,甚至对于专业人员来说,都是难以理解的“黑箱”。但是有时候,这些大型系统会表现出一些奇怪的或是令人担忧的“举动”,从而无意间为我们提供了探索系统内部世界的线索。
以微软的人工智能聊天机器人Tay为例。根据设计,这个机器人以19岁女子的身份与用户进行互动。微软将“她”放上了Twitter上,然而还不到一天的时间,“她”就已经“成长”为一名种族主义者。这是因为“她”所使用的算法接受了那些来自互联网的充满暴力的反馈信息。显然,Tay的偏执倾向并不是事先设定好的。通过这次失败,微软的设计师们更清楚地看到,程序是如何与原始的、未经过滤的互联网账号进行交互并结出恶果的,而这种恶果也是他们始料未及的。(这个太恐怖了,大数据也会被引导走向错误的道路)
显然,要想发现bug,“守株待兔”是远远不够的。许多技术开发人员都会主动搜索bug,并将它们集中放入数据库中,以系统化的方式加以解决。(事前发现总比事后要好很多,损失更小)
更重要的是,在软件开发领域中,人们开始努力尝试打破这个怪圈。他们开始测试边界情况,搜集用户实际可能做出的各种怪事,而不再局限于预设固定的软件使用方式。例如,奈飞公司通过这种策略合理地开发出了“混沌猴”(Chaos Monkey)。“混沌猴”的功能非常简单:它会出人意料地使奈飞系统服务中断。这里面的基本思想是:只有在观察到了庞大的奈飞系统如何应对各种故障之后,工程师们才能想出办法来维护系统的稳定,并以此抗御突如其来的各种意外情况。奈飞公司希望,在“混沌猴”完成了其使命后,工程师们所设计的系统运行方式,与实际的系统运行方式能够完全匹配。(这一招还是蛮厉害的呀,奈飞不愧是科技公司呀)
从失败中吸取教训,是理解任何复杂系统的重要机制。回顾一下科学史便不难发现,几个世纪以来,博物学家们一直在利用这种方法研究自然界中的复杂系统。(人类科技文明的进步就是如此)