编者按:软件越来越庞大,日益蚕食世界。但是在计算硬件指数性发展了几十年的时间里,软件的开发方式却基本保持不变。随着软件变得越来越庞大,对关键系统的渗透越来越深入,软件正在积累着越来越高的风险,我们如何才能排除那些看不见的定时炸弹,避免软件给世界带来末日呢?《大西洋月刊》的一篇长文对此进行了分析。本文较长,请保持耐心。
年4月10日晚上,整个华盛顿州的服务断了6个小时。打电话求助的人听到的都是忙音。当一个陌生人试图闯入自己家时一位西雅图的女性至少拨打了37次都没打通。后来那人从窗户爬进了客厅,她拿起了一把菜刀那人才逃走了。
那次服务中断是当时有报道最大的一次,原因后来被追查到科罗拉多Englewood市一台服务器的软件上。该服务器由系统提供商Intrado运营,上面保存了一个计数器,记录的是路由给全美调度员的呼叫数。Intrado的程序员给这个计数器设置了一个阈值上限。他们选择的数字是万。
4月10日午夜过后不久,该计算器就超过了这个数字从而引发混乱。因为这个计数器是用来给每个电话生成唯一标识的,所以新的来电都被拒绝了。同时由于这些程序员并没有预计到会出现这样的问题,他们并没有设置告警来唤起注意。没人知道发生了什么事情。服务着1万的美国人的华盛顿州、加州、佛罗里达州、卡罗莱纳州以及明尼苏达州的调度中心,努力想要弄清楚呼叫者收到忙音究竟是怎么回事。结果直到早上他们才意识到罪魁祸首是Intrado的软件,而补救措施只需要改变一个数字。
不久前紧急呼叫还是在当地处理的。这样的话中断也是小规模的,而且容易诊断和修复。手机的崛起以及新能力带来的希望——比如发短信给或者发视频给调度员等——推动着依赖于互联网的更复杂系统的开发。结果就是有史以来第一次出现了全国性的中断。现在这么多年来已经出现过4次了。
有个说法是软件正在“蚕食世界”。一度由机械或者人工控制的关键系统越来越依赖于代码。也许没有比年的那个夏天更清楚表明这一点的案例了,因为离港系统出了问题,联合航空公司的飞机被迫停飞;纽约证交所在系统升级后交易被挂起;华尔街日报网站的首页崩溃;西雅图的系统再次宕机,这次是因为另一个路由器出了问题。这么多软件同时失效让人一度以为这是一次联合的网络攻击。但更令人感到害怕的是随后大家才意识到这些都是巧合。
研究软件安全达35年的MIT航空工程教授NancyLeveson说:“我们做机电系统的时候往往会想尽一切办法去进行测试。”因为软件错误导致6位病人死亡的放疗机器Therac-25的报告就是她做的。“我们往往会考虑设备能够做的所有事情,会进入的所有状态。”比方说,控制铁路平交道列车运动的几点联锁的配置就那么多,几页纸就能把整个系统描述清楚,而且你可以把每种配置都实际跑一遍来看看会发生什么。一旦做好测试好之后,你就可以清楚知道在处置的是什么。
软件就不同了。只需编辑文件里面某处的文字,同一块硅晶就可以变成自动驾驶仪或者库存管理系统。这种灵活性既是软件的奇迹,也是它的诅咒。因为可以廉价地改变,所以软件总是在变;同时因为它跟现实的一切都是脱钩的——所以占据相同空间的程序可以比另一个复杂上千遍——软件往往会不受束缚地发展下去。Leveson写道:“问题在于我们在尝试建立超过自己管理能力范畴的系统。”
软件完全按照我们的指示行事。软件失败的原因在于我们告诉它做了错误的事情。
关于工程失败我们标准的思维框架是在二战后不久形成的(在软件出现之前,针对机电系统)。其想法是通过把部件做得可靠(比如引擎可承受次起飞与降落周期)以及为那些部件故障做好预案(准备2个引擎)来把东西做得可靠。但软件不会坏掉。Intrado的错误阈值不像导致飞机失事的缺损铆钉。软件完全是按照人的吩咐行事的。实际上软件执行得非常完美。它失败的原因在于它被告诉做了错误的事。软件失败是理解的失败以及想象的失败。Intrado其实是有个备份的路由器的,如果能自动切换过去的话,几乎马上就能恢复服务。但“当时发生的情况是应用逻辑并没有要执行自动修正行动。”
这就是通过代码而不是实体做东西的麻烦。如Leveson总结那样:“复杂性是肉眼看不见的。”
现在正在进行的改变软件制作方式的尝试似乎都始于同一个前提:代码实在是太难琢磨了。那么在试图理解这些尝试之前,弄清楚为什么会这样是值得的:是什么让代码对大脑那么陌生,跟之前的东西那么不一样呢?
技术进步往往会改变世界的样子——你可以看着道路铺设下去,你可以看到天际线的崛起。但在今天你很难说出什么东西进行着了再造,因为这些东西经常是由代码重构的。比方说,当你踩了汽车油门时,你不再直接控制任何东西;脚踏板与风门之间并没有机械连接。相反,你只是给软件提交了一条命令,给引擎补充多少空气是由后者决定的。汽车就是你可以坐进去的计算机。方向盘和踏板一样可以是键盘的按键。
跟一切其他东西一样,汽车也被计算化以促进新功能。当一个程序负责风门和刹车时,在你距离另一辆车太近时它可以放慢车速,或者控制燃油喷射来帮助你省油。当它控制转向器时,它可以在你开始漂移时保持在自己车道内,或者引导你进入停车区。没有代码你实现不了这些功能。你可以试试,没有代码的汽车就会变成庞大的、重达磅但无法移动的发条装置。
软件让我们做出了有史以来最复杂的机器。但是我们几乎都没注意到,因为所有的复杂性都被包裹进小小的芯片里面以及数百万行的代码之中。但仅仅因为我们看不见复杂性并不意味着它就没有了。
著名的荷兰计算机科学家EdsgerDijkstra在年曾经写到:“必须思考一个头脑此前从未面临过的概念层级。”Dijkstra把这当成一种警示。随着程序员热切地想要把软件植入到关键系统当中,软件日益成为建造世界的关键——Dijkstra认为他们已经高估了自己。
软件工程师并不理解也不关心自己试图解决的问题。
变成之所以如此困难是因为它需要你像计算机一样思考。在计算的早期这种陌生感会更加鲜明一点。当时的代码还是0、1的形式。跟这些枯燥数字打交道的程序员与其实际要解决的问题距离实在是太疏远了。你不可能看出他们是在计算火炮轨迹还是在模拟井字棋游戏。像Fortran、C这样的编程语言以及“集成开发环境”的引入尽管有所改变,但却掩盖了这种基本的异化——事实上程序员并不直接解决问题,而是把时间花在给机器编写指令上面。
MIT软件安全专家Leveson说:“问题在于软件工程师并不理解也不关心自己试图解决的问题。”原因在于他们太过埋头于让自己的代码可以工作了。她说:“软件工程师喜欢为编码错误提供各种工具。”她指的是IDE。“但软件出现的严重问题其实跟需求有关,跟编码错误无关。”比方说,当你写代码控制汽车的风门时,重要的是何时以及如何打开风门打开多大的规则。但这些系统已经变得太过复杂,任何人脑子里都记不住所有东西。Leveson说:“汽车的代码现在已经超过了1亿行,你无法预料所有的事情。”
年9月,JeanBookout载上自己最好的朋友开着一项丰田凯美瑞正行驶在高速公路上,突然油门好像被卡住了一样。她抬脚松开油门,汽车并没有放缓;她试着踩刹车,但却似乎失去了动力。当她以50英里的时速转入匝道时她踩下了紧急刹车。车子划出了一道英尺长的滑痕然后撞上路边的路堤。乘客在这次事故中死亡。Bookout医院中醒来。
这次事故是众多对丰田汽车所谓的突然加速诉讼案中的一起。丰田把事故原因归咎于垫布的糟糕设计、踏板的“粘性”以及司机错误身上,但局外人怀疑该负责的应该是软件瑕疵。美国国家公路交通安全管理局征召了NASA的软件专家来对丰田的代码进行严密的审核。在将近10个月后,NASA仍未发现软件是事故原因的证据——但同时他们也说自己无法证明软件不是。
后来有人终于在Bookout事故的诉讼过程中找到了其中令人信服的关联。原告方的鉴定证人MichaelBarr有一个软件专家团队花了18个月的时间来研究丰田的代码,捡起了NASA丢下来的东西。Barr把他们发现的东西称为是“面条式代码(spaghetticode,多页嵌套的if语句与for循环,包含大量复制-粘贴的过程代码,且没有合适的分割)”。如果代码一项功能一项功能地堆积起来共生了很多年的话就会变成纠缠不清无法跟踪,跟不用说进行穷尽测试去追查缺陷了。
如果软件失灵了也是由同样一套程序处置的话,则这套程序是无法胜任的。
Barr的团队利用同款凯美瑞证明了其实车载计算机有超过0万种方式导致突然加速事故。他们证明了只需一位的翻转(从0变成1或者从1变成0)就能让汽车失去控制。丰田的自动防故障代码不足以阻止这一点。Barr作证说:“你让软件看管软件。如果这个软件失灵了还是由同一套程序或者应用来挽救局面的话是难堪此任的,因为它已经失效了。”
Barr的证词为Bookout及其朋友的家庭争取到了万美元的赔偿。据《纽约时报》,这是针对丰田的诉讼案中首起就电控节气门系统进行的审判,也是丰田首次被发现对突然加速事故负责的案子。后来丰田总共召回了超过万辆汽车,赔付金额接近30亿美元才了结了相关争端。
软件将来还会面临更多的坏日子。我们今后要更擅长做软件就变得非常重要,因为如果不行的话,随着软件变得越来越复杂以及连接更紧密,随着软件控制了更多的关键功能——今后的日子会变得更加糟糕。
问题是程序员已经很难跟上自己的创造物。自从年代以来,程序员的工作方式以及使用的工具几乎都没什么变化。大家逐渐开始担心这种情况难以为继。微软的IDE工具VisualStudio首席软件开发者ChrisGranger说:“即便是非常好的程序员对自己的系统理解起来也很困难。”Granger在微软的时候曾经安排过一次对VisualStudio的端到端研究。这是他唯一完成过的一次类似研究。他用了1个月的时间在单面镜背后观察大家是怎么写代码的。“这些人怎么用工具?如何思考?如何坐在计算机前,有没有碰鼠标?所有这一切都有教条但并没有经过经验测试。”
发现令人吃惊。他说:“VisualStudio是全世界最庞大的单一软件之一。它的代码超过了万行。我在研究中发现其中98%都是不相干的。也就是说大部分的代码都没有针对大家面临的根本问题。我的最大感受是基本上大家就是在脑子里玩计算机。”程序员就像棋手下盲棋一样——其思维精力都放在想象拼图在什么地方上了,以至于已经没有精力再去思考比赛本身。
过去40年计算机每18个月就能力翻番。为什么编程却一点都没有改变?
JohnResig在自己的学生身上也注意到同样的事情。Resig是著名的JavaScript(有一半网站都是JS编写的)程序员,也是在线教育网站可汗学院的技术领导。年初的时候,他一直在纠结于网站的计算机科学课程。为什么学编程就这么难呢?根本问题似乎在于代码太过抽象了。开发软件不像用冰棍棒造桥,你可以看清楚冰棍,可以触摸粘胶。要想“造”程序,你得敲字。当你想改变程序(无论是游戏、网站或者物理仿真)的行为时,你改变的其实是文字。所以程序写得好的学生是那些可以将代码在脑子里过一遍,像计算机一样思考,能跟踪每一次中间计算的人。Resig像Granger一样,开始猜测编程是不是就得这样。过去40年计算机每18个月就把能力翻番。为什么编程却一点都没改变?
这两个人同时在相同情况下思考同一个问题并不是偶然。两人都看了同一场演讲,那是计算机研究学者BretVictor个软件工程学生准备的。演讲在年2月被放到网上之后火了,它做出了两个大胆的判断。第一是我们写软件的方式基本上已经坏掉了。其二是Victor知道该怎么修正。
BretVictor不喜欢写代码。他说:“这听起来很怪异。当我想要做东西,尤其是想用软件做东西时,我得排除这种天生的厌恶感,因为我操纵的不是我想做的东西,我只是在文字编辑器写一堆的文字。”
“我有着相当强烈的信念认为这么做是错的。”
40岁的Victor思维敏捷但为人害羞,有着DavidFosterWallace的风采。尽管他管理着一个研究未来计算的实验室,但相对于技术他似乎对利用技术的人的脑子更感兴趣。就像任何好的工具制造者一样,他会从技术和人性的角度去审视这个世界。在那次令他一举成名的演讲上,Victor提出了他的发明原则:“创作者需要跟所创造的东西有直接关联。”编程的问题正是违背了这一原则。所以软件系统会如此难以琢磨,出现的bug会如此这多:程序员从写的第一页文字开始就是跟要做的东西是脱节的。
他说:“我们当前对计算机程序的概念是直接源自上世纪50年代的Fortran和ALGOL语言。那些语言是针对穿孔卡片设计的。”现在C或者Java等语言的代码都是屏幕上的字符形式而不是一摞打洞卡片,但还是像过去一样死气沉沉,还是一样的不够直接。
在Victor看来,盯着文字编辑器来理解癌症的做法是可怕的。
文字处理有一种类比。过去你在编写文档程序里面看到的就是文字本身,要想改变布局或者字体、边距,你得写特殊的“控制码”,或者告诉计算机“这部分文字应该是斜体字”这样的命令。麻烦的是除非你把文档打印出来否则是看不到效果的。你很难预测自己会得到什么。你必须想象代码如何被计算机解释——也就是说,你必须在脑子里运行一遍。
然后就出现了WYSIWYG(所见即所得)。当你把一段文字标记成斜体时,屏幕上的文字也会相应倾斜。如果你希望改变边距,你可以直接拖动屏幕顶部的标尺——然后看到改变的效果。文字因此感觉就像是真的,可以随便摆弄的东西。只需要看着你就能知道自己有没有做错。任何人只要能在页面上点击都能对复杂系统——文档布局以及格式引擎——进行控制。
Victor的观点是编程也应该如此。在他看来,像设计自适应巡航控制系统或者试图理解癌症这样的重要工作靠盯着文本编辑器看来完成是可怕的。确保有朝一日不需要这样做是程序员的恰当工作。
这个并不是什么疯狂的想法。因为有不少先例。比方说Photoshop把强大的图像处理算法交到了甚至不知道算法是什么的用户手中。这是一款非常复杂的软件,但那种复杂就像合成器式的复杂,上面有开关旋钮、按键、滑块等,用户可以像玩乐器一样去学习。Squarespace做了一款工具让用户只需点击就能建立网站,而不是用HTML和CSS写代码。它已经强大到可以做一度只能由专业web设计师才能完成的工作。
但这只是一小部分例子。压倒一切的现实是,当有人想要用计算机做点有趣的东西时,他们基本上都必须写代码。身为理想主义者的Victor对此的看法是这不是什么机会,而是大多数程序员的道德沦丧。他的演讲就是战斗号角。
演讲的核心是一系列试图表明现有针对各种问题(电路设计、计算机动画、调试算法)的工具究竟有多原始的演示,同时也展现了更好的工具可能的样子。够讽刺的是,抓住了每个人的想象的一个演示却是看起来最为微不足道的一个。演示展示了一个分屏,左边是类似超级玛丽的游戏,右边是控制游戏的代码。随着Victor改变代码,游戏世界里面的东西也会发生变化:他减少了一个数字,也就是重力的强度,然后马里奥的角色就漂浮起来了。他增加了另一个数字,也就是玩家速度,然后马里奥就会疾驰而过。
假设你想给游戏设计一关,让主角跳上一只乌龟然后反弹出去。过去游戏程序员往往要分两阶段解决这类问题:首先,你盯住控制马里奥如何跳跃、跑得多快、乌龟弹性如何的代码,然后在文字编辑器进行一些修改,用你的想象力来预测会是什么效果。然后你重放游戏来看看实际会发生什么。
Victor希望可以更加直接一点。他说:“如果你有一个及时的流程(指的是马里奥过关的路径),并且想马上看到变化情况,你得把时间映射到空间。”他点击了一个按钮,上面显示的不仅是马里奥现在在哪里,而且也会显示出未来每一刻的位置。此外,这条预测路径还是反应式的:当Victor改变游戏参数(通过拖拽鼠标完成)时,路径的形态也会跟着变。就好像拥有了游戏的上帝视角。整个问题已经简化为玩弄不同的参数,就好像调整立体收音机的旋钮一样,直到你让马里奥完成工作。有了合适的界面,你几乎都不用跟代码打交道,而是直接操纵游戏的行为。
观众第一次看到这个时都赞叹不已。他们知道自己看到的不是小孩的游戏,而是这个行业的未来。大多数软件都牵涉到以复杂的方式展现出来的行为,Victor已经表明如果你想象力足够的话,就可以开发出手段来看到那种行为并且改变它,就好像自己动手一样。一位看过这次演讲的程序员随后写到:“突然之间我所有的工具都感觉过时了。”
当JohnResig看到这场演讲时,他把自己给可汗学院转变的编程教程给废弃了。他希望网站的编程练习能够像Victor的演示一样工作。左手边会是代码,右手边则是运行的程序:这可以是一幅图画,一场游戏,或者一次仿真。如果你改变代码,它马上就会改变画面。Resig这样描述这个方案:“在一个真正响应式的环境里,你可以彻底改变学生学习编程的方式……他们可以马上看到结果,并且在没有明确解释的情况下凭直觉了解到底层系统固有的内在运作方式。”可汗学院已经成为全世界最大的计算机编程课,每个月平均有万用户在积极地使用这个程序。
在微软做VisualStudio的ChrisGranger也受到了鼓舞。在看到Victor演讲视频的那段日子里,他开发了一个新的编程环境原型。其关键能力是可以马上对程序的行为提供反馈。你可以在控制系统的代码旁边看到系统是怎么做的。这就好像是脱掉了眼罩。Granger把这个项目叫做“LightTable”。
年,他在Kickstarter上面为LightTable筹集资金。项目在编程界引起了轰动。在一个月的时间里,项目就募集到了20多万美元。这个想法传播出去了。现场感(liveness)的概念,也就是马上就能看见数据流经程序的情况,随后变成了Google、苹果旗舰编程工具的功能。iPhone和Mac的默认开发语言Swift是苹果为了支持名为Playground的环境而从头开始开发出来的,这门语言正是直接受到了LightTable的启发。
但在看到自己的演讲最终产生的影响之后,BretVictor的希望破灭了。他后来说:“很多东西似乎误解了我说的话。”当大家邀请他出席会议讨论编程工具时,他知道情况不对头了。他说:“每个人都以为我对编程环境感兴趣。”其实他感兴趣的是大家如何看待和理解系统——如他所概括那样,是“动态行为的直观表现”。尽管代码日益成为创建动态行为的工具选择,但仍然是理解行为最糟糕的工具之一。“发明原则”的要点是要表明你可以通过在系统行为与代码之间建立直接联系来缓解这一问题。
我不敢肯定代码是否一定要存在。
在随后的两场演讲“停止画死鱼”以及“画动态可视化”中,Victor又深入了一步。他演示了两个自己开发的程序——第一个是给动画家准备的,第二个是给试图可视化自己数据的科学家准备的——这两个过去都需要写很多定制代码但现在被简化为WYSIWYG(所见即所得)界面。Victor认为同样的做法几乎可以应用到编写代码解决的每一个问题上面。他说:“我不敢肯定代码是否有存在的必要。或者至少软件开发者有存在的必要。”在他看来,软件开发者的恰当角色是创建工具来消除对软件开发者的需要。只有这样有着最紧迫计算问题的人才能直接把握这些问题而不需要以代码为中介。
当然,为了做到这一点,你得让程序员本身买账。Victor在最近的一篇论文中恳求专业软件开发者不要再把自己的天才浪费到开发Snapchat以及Uber这样的app上。他写道:“日常生活的便利性不是重大问题。”相反,开发者应该把