虎嗅

他创造了一个价值十亿美元的错误,却让每一个现代程序员受益至今

该文章尚未提供 English 解读,以下为中文版内容。

核心内容总结

Tony Hoare是现代计算机科学的“定海神针”之一,他的一生都在和“软件复杂性”这个看不见的敌人作战。从发明快速排序算法(让排序变简单高效),到提出霍尔逻辑(让程序像数学定理一样可证明),再到设计CSP并发模型(解决多程序协作的混乱),他的成果都围绕一个核心:如何让软件变得可理解、可验证、不混乱。他经历过大型项目失败(503系统因太复杂崩溃),也做过务实妥协(引入空引用,虽然后来被称为“十亿美元错误”)。他的思想对今天AI生成代码的时代尤其重要——当代码越来越容易生成时,谁来保证它的正确性?霍尔早就给出了答案:追求简单性和形式化验证。

详细拆解

1. 一生的“对手”:软件复杂性

霍尔从接触计算机开始,就被“复杂性”困扰。早期机器翻译时,计算机内存小到只能存一句话,排序单词都要反复读磁带;后来开发大型软件系统,团队想做太多功能(操作系统、编译器、文件系统全上),结果内存不够、运行慢到崩溃。他发现:软件的最大问题不是技术不够,而是人类无法理解和控制越来越复杂的系统。所以他一辈子都在找方法:用简单算法减少复杂度,用逻辑证明保证正确性,用合理妥协避免更糟的混乱。

2. 快速排序:用“分而治之”搞定复杂排序

快速排序是霍尔最有名的发明之一,核心思想很简单:把大问题拆成小问题。比如要排序[7,2,9,1,5,8,3],先选7当基准,把比7小的放左边([2,1,5,3]),比7大的放右边([9,8]),然后再对左右两边重复这个操作,直到所有数排好。

这个算法的厉害之处是“原地排序”——不用额外空间存中间结果,省内存(对早期计算机太重要了)。当时他上司不信这算法比 existing 的快,打赌六便士,结果输了。现在快速排序还是计算机里最常用的排序算法之一,连AI生成代码时都经常用到它。

3. 503项目失败:复杂到失控的代价

霍尔团队曾想给新计算机做一套完整软件生态(操作系统、编译器、文件系统等),结果项目彻底崩溃:软件占满了所有内存,客户连自己的程序都跑不了;频繁在内存和慢15倍的后备存储之间交换数据(叫“抖动”,像反复开关抽屉浪费时间),编译器每秒只能处理几个字符。

这次失败让他总结出名言:“软件设计有两种方法:一种是简单到明显没有缺陷,另一种是复杂到没有明显缺陷。” 意思是:宁可做简单到一眼能看出没问题的系统,也不要做复杂到藏着一堆暗病的系统。这对现在的AI生成代码也适用——别让AI生成一堆复杂到没人懂的代码。

4. 霍尔逻辑:让程序像数学题一样可证明

以前程序员靠测试保证程序正确(输入几个例子看结果),但霍尔说:“测试只能发现bug,不能证明没有bug。” 他借鉴数学证明的思路,提出“霍尔三元组”:P{Q}R,意思是如果程序Q运行前条件P成立,运行后条件R一定成立。

比如:前置条件是“x是正整数”,程序是“如果x>1就x+1,否则x*3”,后置条件是“x>2”。用霍尔逻辑可以反向推导:

  • 若x>1:运行x+1后要x>2,那运行前x>1就行(正好符合条件);
  • 若x≤1:运行x*3后要x>2,x=1时1*3=3>2,也符合。

这样就能证明程序在所有情况下都正确。现在AI生成代码时,用霍尔逻辑可以自动验证代码是否正确,避免AI写出有隐藏bug的程序。

5. 空引用:务实的妥协与“十亿美元错误”

霍尔设计ALGOL W语言时,遇到一个问题:引用(类似指针)没指向任何东西时,该用什么值?如果追求“完美”,要在编译期严格检查每个引用是否合法,会让编译器和代码变得极其复杂。他选择引入“空引用”(Null)——简单,但有风险:后来NullPointerException成了程序员的噩梦,霍尔晚年道歉说这是“十亿美元错误”。

但从当时的条件看,这是合理的妥协:内存小、编译器能力有限,与其让系统复杂到无法使用,不如接受一个小缺陷。这体现了霍尔的智慧:对抗复杂性,有时需要务实的折中,而不是追求绝对完美。

结语

Tony Hoare的遗产不是某个具体算法,而是一种思维方式:软件的本质是为人服务的,必须保持简单、可理解、可验证。在AI生成代码的时代,他的思想更重要——代码可以自动生成,但理解和正确性不能交给机器。我们需要像霍尔一样,用逻辑和简单性来驯服复杂性,让软件真正可靠。