Dave Plummer: 戴夫·普卢默:编程、自闭症与微软往事
#479 – Dave Plummer: Programming, Autism, and Old-School Microsoft Stories
嘉宾:Dave Plummer
§01文字实录 1
以下是我与戴夫·普卢默的对话。他是一名程序员,也是一位老派的微软软件工程师,曾参与 Windows 95、NT 和 XP 的开发,打造了许多了不起的工具,其中一些已被数亿人持续使用,比如大名鼎鼎的 Windows 任务管理器。没错,就是 Windows 任务管理器,还有 Windows 中的 zip 压缩/解压支持。他还把《太空军校生弹球》(Space Cadet Pinball,也称“三维弹球”)的代码移植到了 Windows 上。如今,他凭借自己出色的 YouTube 频道 Dave’s Garage 深受众多程序员和工程师喜爱。你们一定要去看看。
此外,他还写了一本关于自闭症和自己人生经历的书,名为《Secrets of the Autistic Millionaire》(《自闭症百万富翁的秘密》),书中就自闭症人士如何处理人际关系、职业发展和日常生活给出了非常有意思的见解。总而言之,这是一场非常有趣的对话,聊到了编程、计算机、科技的历史与未来,也聊到了在所谓的“车库”里捣鼓出各种酷东西。这里是莱克斯·弗里德曼播客。如需支持本节目,请查看节目简介中的赞助商。现在,亲爱的朋友们,有请戴夫·普卢默。
跟我讲讲你的第一台电脑吧。你还记得吗?
记得。我很长一段时间都没有属于自己的第一台电脑,但我用过的第一台电脑是一台 TRS-80 Model 1,Level 1,4K 内存的机器。那时我上五年级或六年级,大概 11 岁,骑自行车去了当地的 RadioShack。店里有常见的组合音响,还有 RadioShack 卖的其他各种东西,但也有一摞标着“电脑”的箱子。我就问店员这是什么,他们说刚到货,还没装起来。我那时挺早熟的,心想:“那我来帮你们装吧。”他们说:“好啊,你试试。”
你知道自己在干什么吗?
完全不知道。我是说,这不比组合音响难多少。唯一的问题是,Tandy 公司“英明”地把电源、视频,我记得还有磁带机,都用了同一种五针 DIN 接口,它们长得一模一样,要是插错了,机器就会烧掉。所以我读了标签,把它弄好了,然后就开始在上面瞎玩,对电脑一无所知。我就往里面敲英语命令,你知道,PRINT 2+2 完全没问题,但再往 Level 1 的 BASIC 解释器里输入更多简单英语,就走不了多远了。
所以你是在试着用英语跟它对话?
那时候不懂嘛。我现在还留着一张六年级时写的大页书写纸,上面是一个程序,有点不合逻辑却又算是对的,但在当时存在的任何解释器上都绝无可能跑起来。所以我花了一段时间才搞明白这些机器到底是怎么回事。不过我每周四和周六都骑车去那儿,他们也很大方地让我用那台机器。
那是什么时候?
79 年、80 年。
好的。那时候计算机领域最先进的水平是什么样的?我们说的是什么样的东西?
嗯,那时“三巨头”已经问世了。有 TRS-80 Model 1,有 PET 2001,还有 Apple II,它们差不多是同时推出的。
Apple II。你会说它是有史以来最伟大的电脑吗?
回过头来看可能是吧。嗯,我可能会把这个称号给 Commodore 64。
对。这点我们看法一致,那是我的第一台电脑,可能是在它发布很多年之后才用上的,不过没错,Commodore 64 太棒了。但确实,Apple II 对个人电脑的历史影响巨大。
对。长期影响很难衡量,但我觉得 64 本身可能影响了更多的人,所以这是我选它的理由。
你这么认为?
销量肯定更高。
所以 Commodore 64 卖得很多?
对。我是说,那些数字让人难以置信。取决于你相信哪个数字,但即便是中间值的估计也相当高。
好,酷。那你后来升级到了 Commodore 64。跟我讲讲那台机器吧。你在 Commodore 64 上都做了些什么?
嗯,我做的第一件事就是把它的软驱弄过热了,这很不幸,因为那台机器没有保修。我父母没多少钱,所以我们是从 Computer House 买的,而不是从大型零售商那里买的,这就意味着它坏了之后,得送回德国还是什么地方去修。所以我手头没了软驱,只剩一台磁带机,这在当时已经是能用的最好的东西了。于是我就写些小东西,我有一个可以从磁带加载的机器语言监视器。它没有内置汇编器,但有反汇编器,所以你可以用十六进制输入 6502 的操作码,只要你规划得仔细,就能写出一些基本的程序。
我差不多就是这么学会的,我在上面写的第一个东西是《大蜜蜂》(Galaga)的克隆版。当然,这是个很烂的克隆版,但它有那些会随着时间推移发动攻击的主要敌人,而且全都是手写的机器语言。6502 的代码没法重定位,所以如果你需要在中间加代码,就得手动跳转到别的地方,做完你的事,再跳回原来的位置。这就是一堆丑陋不堪的意大利面条式代码。但最后它全都跑起来了,于是我打算给它做个备份,留给未来的学者们研究,或者天知道我当时在想什么。结果我把空白软盘复制到了存数据的那张软盘上。这就是我第一次的数据管理经历。
哦,不。
所以我手里已经没有我第一个程序的副本了。
那是什么感觉?你还记得吗?就是那种,恕我直言,干了件蠢事的感觉,你懂的?这也是编程体验的一部分。
对,当时特别内疚,因为,你看,你毁掉了几个星期的……心血,而且你知道这是因为你太着急了,或者干了蠢事,或者做了个不明智的选择。
关于那个游戏涉及的编程,你能跟我讲讲吗?
那完全就是机器语言。
所以是机器……所以它都不是——
对,65 加上——
……甚至都不是汇编。
还不是汇编,因为没有内置汇编器。所以我本该把写一个汇编器当作第一项任务,但我当时没那么聪明。
那有多难?
很简单,而且我觉得这是那种会记住的东西。你做的次数太多了。你知道,如果我给你一个 C 语言的问题,C 里有某些语法问题你是永远不会忘、也不会搞错的。这就是其中之一。
那么作为程序员,用机器码编程有哪些局限?
最大的问题是你必须完全按顺序写,因为至少在 6502 这种情况下,你没法事后往中间加东西。你只能在末尾追加。所以某种程度上就像在给磁带编程。
你用机器语言做过的最复杂的东西是什么?
就是那个游戏吧。我是说,用汇编语言我做过不少复杂的东西,但用真正的机器语言,我想那个游戏是我唯一真正——
你实实在在地做出了一个游戏。
不是个好游戏,但它能跑。
好吧,好,然后你把它删了?
是的。
好。你是什么时候第一次爱上编程的?就是你意识到,这是,这是某种特别的东西的时候。
……我觉得对我来说有两个阶段。从 TRS-80 Model I 开始,我立刻就知道自己被这些机器迷住了。我唯一想做的就是骑车回那儿,多跟它待一会儿。我也确实这么做了,你知道,尽可能地蹭到让人家嫌烦为止。另一个顿悟大概是在大学二年级或三年级的时候,我意识到:“我热爱编程,但我完全不知道自己将来要做什么。我是要去某个地方做让录像机上闪着‘12’的那种东西?还是去开发操作系统?我完——完全不知道毕业后要做什么。但我热爱我做的事。”所以我觉得那给了我很大的安慰。就像是,我现在做什么其实都无所谓,因为我挺热爱做这件事的,所以……
所以,你总会想明白的。只要你跟随那种感觉,它在告诉你——
我知道我终于找对领域了。对。
对。好。你高中辍学了。
对。不是最明智的举动。
好。但你后来重返校园,在学业上非常成功,总的来说,作为程序员、开发者、软件创造者也很成功。你是怎么找到自己的路的?能讲讲你从辍学——……到重新找回方向的这段历程吗?
并没有某个辍学的时刻。你只是去得越来越少,越来越少,直到你意识到,要是再出现会很尴尬,因为你已经很久没去了,然后很快你就干脆不去了,高中就是这么辍掉的。所以,如果你发现自己正走在这条路上,别再这样了。但我恰恰就是这么做的。于是我不上学了,就得找工作,所以我在 7-Eleven 和一家油漆仓库之类的地方打工。7-Eleven 其实是一份挺有意思的工作,因为我觉得他们一直在为这样一类人轮换这份工作:这些人足够聪明,能胜任夜班,夜班要处理所有那些会计和行政之类的事务,但他们出于个人原因不得不在 7-Eleven 工作。
我就是这类人之一,因为我没有高中文凭。
在 7-Eleven 的那段时间,有哪些难忘的时刻?或者说,你对那份工作的艰辛有什么体会?
对我来说最糟糕的时刻大概是……我是说,我被人拿刀抢劫过之类的,那些都挺有戏剧性的,但最糟的……最……对我来说最烂的部分是量油。我们有一根很长的……大概 15 到 20 英尺长的木杆,上面标着英寸和英尺的刻度,你把它放进汽油罐里,再提上来,量一下汽油到哪个位置,因为那里没有电子传感器。我就干这个,第一次干的时候,杆子脱手了,我又一把抓住。结果大概有一千根木刺扎进手里,外面还是零下 40 度,那真是太惨了。
哦,天哪。
我意识到:“我不想一辈子都干这个。”这点我很清楚,所以……
好。所以你就冻僵地站在那儿,手里扎满了木刺。
然后在某个时刻,我对自己的人生有了个顿悟:下次我要换个方式来做。大约三秒钟后,我就意识到这想法有多荒唐,对吧?我觉得那真的是我意识到自己必须做出改变的时刻。所以即便我当时已经 21 岁了,我还是去找了本地高中的校长,说:“能让我回来上学吗?”他说:“不行,你年纪太大了,而且我们没有名额。”这是他的主要理由。我说:“嗯,从现在到开学这段时间,总会有人辍学的。所以你们会有名额的。那我们就假设你们有名额。我能回来吗?”他很宽厚,让我回去了。于是我修完了我需要的三四门课。
对,如果可以的话,在这一点上多停留一下,就是那种慢慢辍学的过程。这是你的大脑能做出的一件很奇怪的事。你自己意识到,你不必做其他人都在做的事,而这是一个危险的认识,因为,你知道,要做某些事情,你多少得是社会的一部分。
对。
如果你意识到你不必做其他人都在做的事,你要么会过上不可思议的人生,要么会过上非常艰难的人生。
嗯,这个过程的问题在于,你做的是一个小得多的决定。“我今天就不去上课了。”你决定的仅此而已,但这样做的次数够多,你其实就在做一个大得多的决定。问题就在这里。
所以最好是……如果你想以一种非常规的方式生活,最好明确地做出那个大决定,然后你就可以不去了。但别让自己一点点滑下去。
否则这个决定最终会替你做出来。
好。嗯,你回去了,最终上了大学,作为学生非常成功,而你以前并不是那么好的学生。
不,我高中时是个很差的学生,甚至到了大学第一学期,我还是没怎么认真对待学业,因为我的 Geometry 90 是被老师开恩放过的。那门课相当于12年级几何课的补修课,而12年级几何我没上过。这件事把我吓到了,因为我意识到,就差1%,或者说全靠那位放我过关的教授手下留情,我差点就在这里断送了整个大学生涯。幸好,这些分数不计入成绩单,因为它们是补习课程。所以下个学期我算是有了一个全新的开始,这次是动真格的,而且是为了我自己而学,这一点让一切都不一样了。
关于怎样才能成为一个成功的学生,你也许能给些什么建议?
嗯,理想情况下,学校里总有某些方面是你真正喜欢的,不管是美术、计算机科学,还是手工课,什么都行。所以,就去上那些课,然后忍一忍,把难的东西也啃下来,因为这比以后再去补要容易得多。当然,人到五十多岁说这话很容易,十五六岁的时候就没那么容易说出口了,但是……这很有道理。
好。你加入微软是怎么一回事?从 7-Eleven 到微软,你是怎么走到这一步的?
是啊,跨度很大。当时我已经回到学校读书,我想那是大学三年级。暑假我在电话公司打暑期工,负责把他们的 UBNet 转换成 TCP/IP 和现代网络。说白了就是换网卡,但换完还得搞清楚为什么他们的 config.sys 不再能让 Lotus 运行了,因为可用内存比以前少了10K。那真是在计算机行业干活最糟糕的年代,但我还是干了。午饭时,我坐在美食广场里,周围都是些老人和闲得无聊的人,我在读一本自己买的书,书名我记得大概是《Microsoft,或者说比尔·盖茨与微软的创建:Hard Drive》。这是本很棒的书。
它基本上就是一部平铺直叙的历史,讲微软是怎么诞生的、那里是什么样子、怎么运作、那里的人是什么样的。我读着读着,就被它深深吸引,着了迷,因为那听起来正是我想去的地方,可我人在萨斯喀彻温,我又能怎么办呢?我最后的办法是这样的:我是靠一个叫 HyperCache 的程序供自己读书的。它是 Amiga 上的文件系统缓存,因为 Amiga 出厂时没有自带任何文件系统缓存,而这个程序卖得还算不错。
于是我把注册卡翻了一遍。那个年代有一种4×6英寸的卡片,用户要填上姓名、地址,有电子邮箱的话也填上邮箱,然后寄回来,之后就能收到更新通知之类的东西。毕竟这是共享软件嘛。我把整叠卡片都翻了一遍,找所有留了微软邮箱地址的人,大概找到了三四个,然后就直接给他们发了陌生邮件,说:“嘿,我是萨斯喀彻温的一名操作系统方向的学生,正在寻找机会。”具体说了什么我记不清了。
但其中有一个人,Alasdair Banks,给我回信说:“我认识一个人,可以帮你牵个线。”于是他帮我联系上了,我想是一个叫 Ben Slifka 的人。他对我做了电话面试,最后想雇我暑假去做 MS-DOS。我就是这么进去的。
你靠……供自己读书。跟我讲讲 HyperCache 吧。你做了一款软件,
它就是硬盘的“减肥计划”。
它对足够多的人有用,多到他们愿意想办法付钱给你?
对,它赚得还不错。我是说,我卖了两千来份。每份20美元或40美元,具体看规则。
这个程序是用什么语言写的?
C。另外也有一些汇编。真正负责向缓存传入数据和从缓存传出数据的那部分非常紧凑的核心代码,是用68000汇编写的。其他的都是 C。
好。这算是文件系统 I/O?
是设备块 I/O。也就是说,从硬盘读取的任何数据块都会先经过我的缓存。它是一个 N 路组相联缓存,会尽量匹配硬盘的几何结构,并据此做预取,比如你想一次读取整个磁道,诸如此类。
在那个年代,想把你的软件推广出去是什么样的?你是怎么找到客户的?
嗯,挺有意思的。我想我是从 Usenet 和一些 Amiga 论坛起步的,发帖说:“这是我的试用版,试用30天,看看你喜不喜欢。”后来有几家零售商开始进货。我记得当时我和我……现在的妻子在她车里,她有一部手机,因为她爸爸非常担心她的安全。那是80年代末,她的车顶上装着天线,后备箱里放着个大盒子,全套配置。就在那时我们接到了一家软件零售商的电话,他们想以每份……20美元的价格买50份,对我来说那就是一千美元,在1989年,或者不管是哪一年,这都是件大事。后来就有不少公司直接进货囤了库存。
我们回到那个时代。比尔·盖茨和微软所处的那个时代太有意思了。你认为微软为什么在当时,乃至此后很多很多年里,都能主导软件和个人计算机领域?
在当时,那是我参与过的聪明人最集中、实力最强的群体。我待过学术界,也在一定程度上待过业界。你知道,当你在一家普通的计算机公司工作时,公司里那个唯一真正懂行的人,他那个更聪明的朋友呢?很可能就在微软工作。所以你到了那里,本来是小地方来的大人物,以为自己懂很多,突然之间就置身于这样一个环境里,心想:“糟了,我还是别开口了,因为我不想显得很蠢。”
好。那比尔·盖茨本人呢?你认为他身上有哪些特质促成了微软的成功?
我认为他对自己唯一的梦想有着不懈的追求,也就是他那句老口号:让每个家庭都有一台电脑,每张桌上都有一台电脑。那是他的特殊兴趣,而且他是个聪明人,意志极其坚定,他还雇用了和他一样聪明甚至比他更聪明的人来帮他实现这个梦想。他打造了一台几乎势不可挡的智力机器,去大展拳脚,做出了,怎么说呢,非常简单的产品。MS-DOS 无论怎么看都不是一个复杂的产品,但它恰恰是当时市场所需要的。
MS-DOS 改变了游戏规则。而那其实正是你加入的团队,MS-DOS 团队,我想你是在 Windows 95 发布之前加入的。那就跟我讲讲 MS-DOS 的故事吧。它的成功对微软的成功大概起到了关键作用。
在 DOS 之前,他们基本上是一家编程语言公司,为很多计算机做了 BASIC,还有 Fortran 编译器和 Pascal 编译器之类的东西。但他们达成的那项协议,让 MS-DOS 随每个版本、或者说每一台 PC 一起提供,这实际上让他们成为了一个标准,此后几十年他们都能借此发力。在某种程度上,他们是碰巧赶上了这个机会;但另一方面,他们这么做也确实很聪明。他们并没有向 IBM 收很多钱,但随着时间推移,让它成为标准这一点确实给他们带来了很大的优势。
所以当时的 MS-DOS 没有图形界面。你能讲讲 MS-DOS 到底是个什么东西吗?
它基本上就是一个命令启动器。你输入一个命令的名称,它会查找这个命令是否在当前目录里,或者在某个特定的文件夹路径上,如果找到了,就把它加载到内存里执行。MS-DOS 90%的工作就是这个。当然,它也有环境变量、一些复杂的部分,还内置了一种小型脚本语言,但它基本上就是一个操作系统外壳,让你可以使用计算机的资源,比如硬盘或 CPU,而且它不支持多任务。它没有图形界面。不过,我记得微软在 DOS 5.0 里确实为编辑器和 QuickBASIC 之类的东西加入了基于文本的图形界面,而在 MS-DOS 4.0 里还有一个 DOS Shell,算是一种图形化的文件管理器。
所以他们做过这方面的尝试,但它基本上就是个命令提示符。
它有没有和外部设备通信的能力,比如驱动程序之类的?MS-DOS 作为一个操作系统,覆盖面有多广?
嗯,它受限于最初的 x86 指令集,这把它限制在了640K。之后又在上面打了各种补丁,用来实现高端内存(high mem),以及再往上的扩展内存。而且要让任何东西在不占用基本内存的情况下运行,都得费很多周折。
是啊,你在 MS-DOS 上编过程序。那是什么感觉?有哪些有意思的细节?比如你说的,有640 KB 的内存限制。
对,640K 是永远都只能有这么多的上限,所以这并不是你作为操作系统开发者能随便用的量,因为你用掉多少,用户就少多少。所以如果你无谓地用掉了10K,你就会……现在全世界的每台机器都少了10K,所以这算是很大的责任。
比尔·盖茨真的说过那句话吗,就是他说过,
“没有人会需要超过640K的内存”?对,不,不是他说的。这句话一直被安在他头上,但并不是真的。
你作为实习生,以及正式加入 MS-DOS 团队和之后,做过哪些有意思的事情?
我最早做的事情之一,是拿磁盘缓存 SmartDrive 来,因为我对磁盘缓存很熟悉,给它加上 CD-ROM 缓存,因为那是新东西。CD-ROM 当时才刚出现。Microsoft Bookshelf 是少数能在上面运行的产品之一。你可以想象,如果做得巧妙,给 CD 加缓存能让它的速度提升几十倍。所以这是一个很大的性能提升,也是件很不错的工作。其中更大的一部分工作,是把 SmartDrive 的很多部分,以及后来的 DoubleSpace 压缩引擎,移到所谓的高端内存里。
不深究技术细节的话,x86 上有个东西,我记得叫 A20 地址线。我可能把这个说反了,反正我有五成把握说对,但如果 A20 地址线被置位,那么你的内存指针会在1兆字节处回绕。
如果没有置位,就不会回绕。于是你可以在内存里继续往上走。所以你可以把段寄存器和偏移寄存器组合成一个大于1兆字节的地址,去改写上面的内存,这样就多出了64K。你把代码放在那里,然后在低端内存里放一些存根(stub),从那里跳转过去。这样你就能从机器里再挤出64K,我们在几个产品里都这么做了。而那……我当时根本不知道 HIMEM 是什么,因为我是 Amiga 程序员,到那里之前从没写过任何 x86 代码,所以……
所以那是你参与过的一项很酷的优化。那 Windows 呢?当时同时还在开发 Windows 95,对吧?你有机会和那些人打交道吗?
其实我在 Windows 95 上做过大约三四个月。我在 COM/OLE 团队做呈现缓存(presentation cache),就是当你把比如一个 Word 或 Excel 电子表格或图表插入 Word 文档时用到的东西。你不希望每次渲染它都得加载 Excel,所以有一个由增强型图元文件组成的呈现缓存,我当时就在做这个。它随 Windows 95 一起发布了,但我在进入微软大约六个月后转到了 Shell 团队,所以从那以后我一直在做 NT。
好,那95是什么?NT 又是什么?
Windows 95 是从最初的16位 Windows 3.1 演进而来的,而 Windows 3.1 是第一个真正流行起来的 Windows 版本。Windows 95 加入了32位支持,还有 VxD 驱动程序和一大堆新技术,以及一套全新的用户界面。在当时,这是革命性的东西。人们晚上就去排队,等着买它。
你能带我们回到那个年代,讲讲为什么 Windows 95 相比 3.1 是这么大的飞跃吗?苹果当时已经有图形界面了,Windows 3.1 也有图形界面。为什么 Windows 95 是如此巨大的飞跃?
我不想把它简单归结为“开始”菜单,但我觉得……它确实是很大一部分原因。我记得第一次看到它的时候……我说不清它到底哪里不一样、哪里那么棒,但我意识到我想参与其中,这也是我开始写一个外壳扩展(Shell extension)的原因,它后来在某个时候变成了“压缩文件夹”(Zip folders)。我就是被这个新外壳迷住了,所以我最后加入了那个团队,负责把这套外壳移植到 NT 上,也就是今天的 Windows。
你会说那是有史以来最伟大的操作系统吗?有史以来影响最大的操作系统是哪个?
对我来说 Windows 95 排第二。我觉得第一名应该是 OS/360。
好,有意思。
因为你可以在 1962 年拿一台机器给它写一个 COBOL 程序,然后跳进时光机,到波基普西启动一台 IBM z17 大型机,今天照样能运行。他们这样做已经不知道多少年了。而且这都在商业领域,所以我们作为消费者接触不太到,但我认为它在商业领域的影响力大概和 Windows 95 在家用领域的影响力相当。然后对我来说第三名大概是 Linux。我把 Linux 排得比 Unix 更高,这其实说不通,因为两者缺一不可,但 Unix、BSD 等等的影响主要在学术领域。它是程序员为程序员做的东西。
是啊,Linux 创造了……我是说,它是开源精神在最大规模上的体现,对吧?所以它几乎创造了一个社区,也创造了一种延续至今的编程精神。确实,确实。规模很重要。
对,而且它现在在服务器端的渗透程度,我不知道能不能和 System/360 当年的成就相提并论,但几乎已经无处不在了,所以……
是啊,这个世界……我是说,这是宇宙中一个不为人知的秘密:它运行在 Linux 上。好,跟我讲讲你的工作日吧。那时候是什么样的?在 MS-DOS 和 Windows 95 的年代?带我过一遍高效的一天。
嗯,你一天的开始是进办公室,然后得下载通讯录,这个……那时微软有 1 万到 1.5 万名员工,我们都用 MS Mail。我们刚刚告别一台叫 Miss Piggy 的 PDP-11,它跑的是 Whizmail,现在我们改用 MS Mail。但是 MS Mail 有一份固定的通讯录,每个用户每天早上都必须下载,当 1 万个人都在下载一份 1 万人的通讯录时,场面就相当混乱了。我记得我们那时用的是 10 兆比特的网络,所以你的第一个小时都在下载通讯录,这一直让人很恼火。不过你会利用这段时间去看夜里发生的崩溃,这些崩溃来自一个我们叫作 Stress 的流程,也就是 NT……
所有闲置的机器整晚都在跑测试,它们会想办法让自己崩溃,如果真的崩溃了,就会进入调试器,通过串口线连到另一台机器上,你可以连上那台机器,远程调试崩溃的那台。所以你一进来,他们已经把 bug 分拣好了,比如说,“开始”菜单里出现了一次崩溃,那就分给戴夫,所以你进来第一件事就是连上去,因为你得把那台机器还给它的主人、把机器解锁。所以你一天的第一个小时基本上就是分拣 Stress 夜里发现的 bug,然后到那时候大概就回去写代码了,可惜 80% 的时间都是在修 bug,尤其在我的职业生涯里,主要的工作
就是移植代码和修 bug。我写的新代码不多,当然也有例外。我在本职之外写了很多新代码,算是过过瘾……以此摆脱日复一日总是在修别人代码里 bug 的苦差事,不过修别人的代码也是非常棒的学习经历。
所以你做了很多……在微软,你做了很多移植工作,是把 Windows 95 的代码移植到 NT 上吗?
对。我们把整个 Windows 95 的用户界面移植到了 NT 上,这首先意味着要把它改成 Unicode。所以原来所有 8 位的东西现在都变成 16 位。
好的。
……还有指针。你可以想象,把代码切换过去的时候,场面相当混乱。
能给我们讲讲移植具体都涉及哪些工作吗?
这就像闯进别人家里,翻遍他们所有的东西,看到他们抽屉里那些不想让你看到的东西。你会发现所有好东西,比如墙上挂的漂亮画,也会在床头柜里发现一些令人不安的东西。我见过大概 200 个字符宽的代码,里面还夹着脏话和骂人的话。到我离开的时候,这些年下来它们最终都被清理干净了。但它并不总是世界上最专业的代码。
对,因为每一段代码你都得过一遍。
一行一行地过,所以你全都看得到。
是啊。我是说,这就是程序员的故事。你写了一段代码,以为永远不会有人看到。但有时候,很多时候,那段代码会被非常多的人看到……那些后来的人,包括五年后的你自己。你自己回头看自己的代码。好,跟我讲讲 Windows NT 吧。那也是一次巨大的飞跃。
是的。它基本上是从零开始的全新设计。他们从数字设备公司(Digital Equipment)请来了戴夫·卡特勒,他为那家公司做过操作系统,VMS 和 RSX-11 都是他做的。我记得他是在 DEC West 的几个项目,应该是 Prism 和 MICA,被取消之后过来的。于是就有一整队人,他们的项目被取消了,基本上他们中的一大批人就来了微软。我不清楚这笔交易的具体细节,但他们全都来了。所以就有了戴夫·卡特勒、马克·卢科夫斯基,还有一群来自 DEC 的非常聪明的人,他们基本上是从零开始,但也有 OS/2 作为起点。不过 OS/2 当然是用汇编语言写的,而 NT 要用 C 语言写。
所以他们在多大程度上利用了其中的东西,我其实并不清楚,但至少他们有一个可以起步的系统。
你说过戴夫·卡特勒是 Windows 背后的那个人、那个头脑。能解释一下吗?
戴夫·卡特勒是内核的架构师。在 Linux 世界里是林纳斯,在 Windows 世界里就是戴夫·C(Dave C.)。
对。戴夫·C,好的。
当然,并不是说没有其他人做出贡献,确实有人贡献了很大的部分。但我认为他是背后的推动力,而且一直很大程度上都是。他现在还……我想他现在 85 岁了。他还是每天写代码。他是微软技术院士(Microsoft Fellow)。据我所知,他还在去上班,所以……
能谈谈这个人的天才之处吗?比如,和戴夫·卡特勒共事、打过交道之后,你觉得他的头脑有什么有意思的地方?
嗯,这家伙聪明得要命,但他也有点像个农夫。他就是那种会跟在你后面、确保事情做完而且做对的人,确保你没有往他的操作系统里提交任何垃圾代码。他是不会容忍的。在这方面他是个非常严格的监工,但我觉得这真的很值得,因为对微软的开发者来说,接受戴夫·卡特勒那种数字设备公司风格的领导,是一次非常大的范式转变。
从中你学到了哪些关于成功软件团队的东西,特别是有大量人员协作的团队?因为微软当时有很多才华横溢的工程师,还有你说的戴夫·卡特勒。他们必须创造全新的系统,其中很多我们今天仍在使用。关于优秀的软件工程团队,你从那个时期学到了什么?
首先,我觉得工具就是一切。人也是一切,这点我们承认。但工具集是一个巨大的因素。如果当时我们能用上 Git,事情会容易得多。我们用的是 Diff,还有,你知道的,手工做 Delta……来做这些移植之类的工作。所以能够从源代码分叉出一个分支,对我来说是后来才有的奢侈。在当时,那会非常方便。
那个时期有没有什么令人难忘的对话,比如你走到隔壁——
嗯,有件事……
……跟这些人聊天的时候?
……发生时我并不在场:有人在抱怨,一个新员工进了团队,在做一个我记得叫 Cairo 的项目。Cairo 本来要成为下一代的未来操作系统,会很漂亮,会有一套比 Windows 95 更新的全新用户界面,但它最终没有问世。不过在他们做这个项目的时候,做 Cairo 的一个人在公开的 NT 开发邮件组上(那个组有成千上万人)发火痛骂 NT 的启动体验有多烂。结果回过来的是一封史诗级的骂战邮件,我真希望当时存下来了,我不会说出写信那个人的名字。他自己知道是谁,但是……那简直是一件愤怒骂战邮件的艺术品,有点像你偶尔看到林纳斯就内核问题发的那种邮件。所以情绪非常相似。
那时候有没有那种智识上的争论,比如——
哦,有。
……工程师之间有没有一些很激烈的交锋?
那是……对,会闹得很僵。你有一群聪明的头脑在较劲,到最后,对有些人来说技术上的是非变成次要的了,重点变成了要在争论中压倒对方。到那一步,一半的时候就已经没有建设性了,但这种情况相当多。
是啊,我在编程语言设计社区里见过这类争论,比如吉多·范罗苏姆,那些社区的领导者,这会把他们消耗得筋疲力尽,因为人们会……你几乎会忘了自己的使命,开始对细节非常吹毛求疵。我是说,工程师的头脑凑到一起,就会为了最愚蠢的、比如说某个语法上的细微之处大打出手。
没错。
嗯,我不该说愚蠢,但对编程语言来说那只是一个很小的语法细节。我相信在具体的内核组件上也有内部斗争。
是啊,我是说,有一场我输掉的争论,我想直到今天还让我耿耿于怀。
好,是吗。是什么?
因为我仍然认为我是对的。当时我们在做外壳,要把所有东西从 ANSI 移植到 Unicode,所以每个原本 8 位的字符现在都变成 16 位。问题是我用的是一台 MIPS 机器,因为我要把它移植到 RISC 上……而在这种机器上不能有未对齐的地址。但如果你拿两个 ID 列表,它们基本上就是路径组件,你拿 C:\ 的那个,拿 Windows 的那个,再拿 System32 的那个,把它们拼在一起。可如果字符数是奇数,那你在这个结构里就处在一个奇数地址上了,我得花大量功夫去打开异常处理程序,做未对齐的字节访问,把字符串取出来再手动复制。
而在 MIPS 机器上,因为未对齐,从这个 ID 列表里读出一个字符串,工作量简直是原来的一百到一千倍。所以我主张,虽然 Windows 95 已经到了后期,他们已经发布了一个测试版,但我们现在应该保证 ID 列表总是偶数个字节,或者用某种变通手段确保这种情况永远不会发生,这样所有引用它们、要做这些繁重工作的代码就能飞快地跑过去。结果这变成了一场大吵,有点演变成私人之间的较量,那一场我输了。我到现在仍然认为,而且我知道,今天 Windows 上运行的那段代码比它本该有的速度慢了几千倍,没人在乎,因为它已经足够快了,但是……它本可以快得多。
是啊。你提到了 MIPS 和 RISC。你得对最底层理解到多深?也就是对你所构建的东西的最底层软件,甚至硬件。为了在 NT 上、以及在那之前的工作中取得成功,你必须理解哪些抽象层……
嗯,你一天里大约有一半时间要花在调试上,而且大部分时间都耗在纯汇编语言的调用栈里,因为那时没有源码级调试。所以不像现在用 Visual Studio,命中一个断点,界面弹出来,源代码就摆在那儿。你可以去翻源代码,但你始终看着的是机器吐出来的原始汇编转储。
所以就算你是用 C 编程,调试也是在汇编层面?
对,百分之百。
天哪。
所以有点麻烦。
噢。
更妙的是,我们要应付四种指令集,因为我们同时在做 Intel、MIPS、Alpha 和 PowerPC。所以取决于在哪台机器上崩溃,你面对的就是一套完全不同的指令集……还有寄存器。所以这四种你都会调试得相当熟练,不过我在 MIPS 上经验更多,所以 MIPS 相关的问题就会落到我头上。
那真是一场耐力赛。我是说,能聊聊这个吗?这里的折磨就是调试,尤其是那种没有配套工具的调试。我是说,你知道,编程——现在的年轻人啊——编程不全是创造美好的东西,对吧?也包括修东西。
是的,我会说我职业生涯里 20% 在创造,80% 在调试和修复。而且我多少有了个「能修东西的人」的名声,所以这类活儿就会流到我这儿,我也就在这上面花了更多时间。我并不以那种灵感迸发、新点子层出不穷的创意型 UI 天才著称。所以我负责修那些难看的烂摊子,但你会因此变得非常擅长。所以我并不介意,除非碰上那种你已经追了太久、不知道下一步该怎么办、搞不懂它为什么不工作、或者它当初怎么能工作的情况,或者不管你碰巧处在什么处境,而且你知道,折腾上一整天,会相当磨人。
是啊,调试真的可能是种折磨,可能真的非常非常难。我觉得这里面有一个心理层面的因素,就是毅力。
我觉得那些要花你一整天的问题,结局无非两种。要么是「噢,多了个分号」,然后你终于看见了……要么就是某种跨线程 COM 单元(apartment)问题的某种可怕表现,那就真的很难。但两种情况都有可能。我遇到过一个 bug。其实不是我的 bug,但它在任务管理器里表现出来:时不时地,总 CPU 使用率会显示超过 100%,这对一个任务管理器来说看起来挺傻的。所以我试着解决了很长时间,还跟内核组的人谈过我的问题,他们嘛,可以说不太同情,因为内核组的人是一类特殊人群,他们对我那些用户态的问题不感兴趣。「多半是我代码里的什么问题」,对吧?
他们多半是对的,但这次不是,而且我很确定,所以我在代码里到处加断言(assert),确保把各项加起来的准备步骤从不超过 100,最终的总和也从不超过 100,结果断言始终没有触发。但我们偶尔还是会收到这个 bug,还是有人会看到它,所以我最后把我的电话号码写进了断言里,写着:「如果你看到这条消息,请致电 DavePL,425-836」,也就是我的电话号码。最终,我们真的在我之前提到的那个压力测试调试器里逮到了一次,碰巧发生在一个连着调试器的人身上。
我们得以一步步排查,结果其实是内核的计数统计问题,而不是任务管理器的问题,所以等我能证明它确实是内核问题之后,他们就在内核里把它修好了。你可能以为我们接下来会把我的电话号码删掉,但我们只是把它注释掉了,所以它就这么随产品发布了,而且出现在外面流传的所有那些该死的 NT 源代码泄露版本里,所以……
太棒了。
……我就是这么找任务管理器代码的。我在 Google 上搜我的电话号码,它就能反查出……
噢,对,那太妙了。
……NT 源代码。
能聊聊断言这件事吗?顺便说一句,我看到过,我记得你发过推文或者在哪儿说过,如果你想认真对待你的断言,就把你家里的电话号码写进去。这是真的,这是真的。
有点开玩笑的意思,因为这大概不是最明智的做法,但……
不,确实不是。
……你一定会知道的。
不过我是说,断言本身就已经是件很严肃的事了,因为它会中止所有执行。我是说,这正是我非常非常喜欢断言的原因之一,因为它会让一切停下来,逼着你去处理问题。
是的,我对断言也有点近乎信仰般的执着。我不会去断言那些我希望不成立的事情。我断言的是我知道不可能成立的事情,我认为这才是断言的真正用意。所以我是在说一件显而易见的事,但当它真的触发时,那就是 bug,简单明了。它不是警告。
挺神奇的,它常常真能帮你找出问题,因为如果你到处都加断言,就能很快定位到问题的根源。
是的,我倾向于……这不是我建议你事后再回头补上的东西。这是你在构建代码的过程中就应该自然而然去做的事。
在构建的过程中。
所以对每个函数,如果你有一些假设,比如「我知道这个指针永远不为空」,那就断言它。如果你知道这个计数总是小于字节宽度的两倍,那就断言它。而且别害怕,因为如果它触发了,那是在帮你的忙。我觉得有些人会害怕。你知道,这就像你从路口转弯出去的时候,心想可能有人过来,却不往左边看。也可能只有我会这么干。但就是那种感觉。人们不写断言,是因为怕它们会触发。可是不对,你是想知道的。
你提到了任务管理器。显然我们必须聊聊这个,你创造的那个传奇程序——Windows 任务管理器。把你如何构建它的每个细节都告诉我。Windows 任务管理器是什么?
Windows 任务管理器是一种途径,让你可以进去查看系统上有哪些应用在使用这台电脑,在使用硬件、CPU、内存,以及哪些可能用得太多、卡死了或者失控了。它还让你能够终止、杀掉那些应用。所以它既是一个检查工具,也是一个修复工具。
是的,它会列出所有进程。我是说,这是一个传奇软件。太疯狂了。你就是把它当成理所当然。它就像开始菜单一样,对吧?简直是天才之作。
嗯,我很幸运,参与过很多大家都熟悉的东西。任务管理器就是其中一个副业项目,我一开始是因为自己想要才做的,最终它被纳入了公司内部。所以我是在家里开始写的,把基本功能跑了起来。我当时用的,我记得是注册表里的 HKey Current Performance 或者 HKey Performance 来获取统计数据,因为我在家工作,接触不到内部 API,而且在家工作的时候我也不会调用那些。
等我把它带进公司之后,我就能调用 NtQuerySystemInformation 或 NtQueryProcessInformation 这类函数,非常快地拿到真实结果,这让它成为一个非常快速、响应灵敏的应用。所以大家渐渐依赖它,因为我把它写得尽可能可靠。我并不操心功能。它就是我想要的一组基础功能。我想要的都有了,但我希望它非常健壮。而且小巧。最初的版本大概只有 87k。
好,你能聊聊要构建这样一个不会卡死的软件,需要做到什么吗?
你不做太多假设,对吧?如果你要调用 shell 去运行一个应用,那它可能是一个位于 TCP/IP 共享上的网络路径,要 90 秒才会超时。所以任何时候你做那种可能耗时的 API 调用,最终都会把它放到一个单独的线程上去做。所以这个应用会变得稍微复杂一些,因为一切都是多线程的。
好,那你当时用的是什么编程语言?
C++。
所以这是给 Windows NT 做的?
是的。
好。
它最初是在 NT 4.0 中发布的。
好,那这个程序有哪些有意思的细节?因为你得让它尽可能简单,同时又尽可能健壮。比如说,你必须实现哪些有意思的优化?
有几件事现在看来有点硬核。我自己都惊讶当时会这么做。比如,我完全不想链接 C 运行时库。所以我确保从不调用任何运行时函数,也不链接它们,这为我省下了 C 运行时库那部分体积,大概 96k 之类的吧。所以,只要你碰了任何一个 C 调用,应用的体积几乎就会翻倍。所以我很小心地避免这样做,但我实际上是用 C++ 写的,它更多地就是带对象的 C。但为了让它能跑起来,我得逐一从分派表之类的地方手动调用所有对象的构造函数,因为没有运行时库替你做这件事。
所以你是在用一个没有运行时库的编译器干活,我不想在技术问题上扯太远,但要让它跑起来得多做很多工作,不过一旦做成了,它就极其小巧紧凑。
刚才谈的是程序的体积。那么在追踪每一个进程以及该进程占用多少 CPU 方面,有哪些有意思的地方?
我见过的比较酷的一件事是……我不想说我发明了汉明码,但我算是在不知道汉明码存在的情况下发明了汉明码。任务管理器里的每一列和每一行都有一个位,记录它是否变「脏」了,然后我可以基本上像汉明码查看 X 列和 Y 列那样,找出哪些行发生了变化,逐一检查,找出哪些真正需要重绘。所以任务管理器效率极高,它和 ListView 控件协同工作,这个控件提供了相应功能,可以逐一检查并重绘,小到只重绘帧与帧之间发生变化的单个单元格。所以它绘制得非常快,调整大小也非常流畅,而调整大小大概是我个人在这个应用上最大的目标。
所以你可以把它调成任意大小,它照样能用,而且就算你有 32 个 CPU——这在当时是不可能的——它也能绘制,我记得只画八个图,然后换行,但它今天依然能用。所以我对这点挺自豪的。
真是了不起。你有机会见证了任务管理器的演变。从某些方面看,它真的没怎么变。也许有一些更漂亮的地方,以适配它所在的那个 Windows 版本,但它基本上真的还是同一个东西。
§02文字稿 2
功能非常一致。报告的内容更多了,因为他们加上了 GPU、温度之类的东西,有这些真的很好。而我们当年没有这种能力,所以……
我是说,你怎么看?你知道吗,比如,有没有做过什么重构,还是基本上还是同一套代码?
据我所知,原来的代码大部分都还在,所以上面叠了一层层的绘图代码、深色模式代码以及其他各种东西,XML、schema 代码,这些叠在上面,让它变成了 4 MB 而不是 87k,不过这就是我们所处的世界,所以……
是啊,这是那种你创造出来、一旦存在就会一直留下来的软件。它真的就像开始菜单一样,我敢肯定如果你把它移除,人们会抓狂的。
是啊,这个可能会被锁定一阵子。这也许是好事。
是啊,我以前觉得大眼夹(Clippy)也会是这样,但大眼夹总有一天会回来的。好,你当时还创造了哪些其他传奇软件?你参与过《三维弹球》(Space Cadet Pinball),至少是移植工作。
是的,他们走进我的办公室说:“嘿,你在忙什么?”我跟他们说了我在做的事,他们就问:“那你接下来三个月想干点什么?”我说:“我完全没想法。”他们就说:“你想不想移植《弹球》(Pinball)?”我之前见过《Space Cadet Pinball》,它是 Win95 平台上的一款单独游戏,有几张不同的球台,挺酷的,所以我还有点兴奋。他们想给 NT 弄点视觉上的亮点,用来展示 NT 能跑高速图形,至少是响应灵敏的图形。这是按当时的标准说的。
于是我就试了一下。不巧的是,很多代码是用汇编写的,而我用的是 MIPS 机器,所以我得先用 C 把代码重写一遍,然后才能移植到各个平台上。这个游戏的核心是一个巨大的状态机,就像一个庞大的 switch 语句,如果我没记错,里面大概有 50 个分支。
它里面还内置了一个彩蛋。要解读它的状态,就像在跑一个神经网络,你不断用不同的状态去触发它。所以我干脆把它放到一边,当成黑盒处理。我的代码跑在它上面,负责绘图、声音和其他所有东西,但原始的游戏逻辑仍然在运行。最近有人问我,为什么它跟 Windows 95 版本有点不一样,物理效果略有差别。按理说它应该是同一套代码,因为我一直非常努力地保留原样。真正的原因是我当时有个 bug:我会以尽可能高的帧率去绘制,而在现代电脑上,《弹球》能跑到每秒 5,000 帧,因为它是个相当简单的游戏。
所以你所有的物理计算每秒插值 5,000 次,而不是旧机器上大概每秒 30 次之类的。可以说你得到的物理效果更好,至少是不一样的。不过后来他们已经把这个问题修复了,所以……
这个游戏为什么这么好玩?
我觉得是它的设计好。我是说,这完全不是我的功劳,全都是 Cinematronics 那帮人做的。原版游戏的设计非常出色。它跟《Black Knight 2000》很像,我自己就有一台这款实体弹球机,布局其实非常相似。我不知道它是不是受了那台机器的启发。总之,这是个好游戏。
是啊。我有时会想到《俄罗斯方块》,想到那些画面相当原始、却能让一大批人着迷的游戏。也许正是一大批人的兴奋,成就了游戏的魅力。很多人一起为它兴奋、一起谈论它,这种感觉就会植入你的脑子里。不过它确实是伟大的游戏之一。我是说,还有《纸牌》和《扫雷》。整整一代人都在《扫雷》里“征战”过,对吧?
嗯,这些东西被放进操作系统,并不是当游戏用的,而是作为教学工具,让你学会用鼠标。
哦,有意思。
所以《纸牌》是教你怎么拖放的。《扫雷》大概是教右键点击,我记得是插个旗子之类的东西。我不是玩《扫雷》的那种人,不过它们每一个都在教你点什么。
“玩《扫雷》的那种人”?真好笑。是啊。哇,我以前不知道这个,挺有意思的,确实是这样。但我都不知道自己在这些游戏上花了多少个小时,数百万人在这些游戏上花了数百万个小时。
我以前在孩子的学校做志愿者,教计算机科学,你知道的,给三年级之类的学生上课。其实与其说是计算机科学,不如说是教他们登录。那些孩子的爸爸当然都在微软上班,所以你做什么都没人觉得了不起。不过后来有个孩子发现我参与过《弹球》,他们就说:“哇,你做过《弹球》?”因为那时候他们都知道这个游戏。现在的孩子大概已经过了那个年纪,不再知道它了,但曾经有过那么一小段时间。
Windows 激活是你弄出来的。
你说得好像这是件坏事似的。
一切都看角度。那讲讲这个故事吧。Windows 激活是什么?你是怎么参与进去的?
他们是在 XP 发布流程的后期找到我的。我不确定当时 beta 版发出去没有,我觉得应该还没发。他们原本打算把 Office 的激活代码拿过来改一改,给 Windows 加上激活功能。可负责这件事的人已经拖了好几次,眼看是做不成了。我那时算是有点名声,能很快把东西搞定,所以他们来找我说:“你能赶在 XP 之前把这件事做完吗?”“我不知道,但我会试试。”后来在做 DRM 的那帮同事,还有为产品密钥等等做数学计算的研究团队的帮助下,我们赶在 XP 之前把它做出来了。
我不知道它对收入的实际影响有多大,但我猜一旦开始强制执行许可证密钥,影响应该相当可观。
我很好奇到底是多少。
我不知道。
因为它也挺烦人的。
确实,尤其是需要电话激活的时候。那是我们一直甩不掉的沉重包袱。你得把数据上传到激活验证中心,也就是负责批准你密钥的那些后端系统。你得告诉它你所有的硬件参数,比如内存多大、硬盘空间多少,以及硬件密钥所绑定的各种东西,再加上产品密钥。这些还都得编码成字母和数字,让人愿意在电话里念出来。如果你觉得通过电话激活产品很痛苦,那你能想象在电话另一头工作的人吗?我是说,一天八小时听人念产品密钥,那肯定是一份让人头脑麻木的工作。
是啊,Windows 的难处之一,就是使用它的人类型太多了。这一直让我很沮丧,不过我理解从设计角度来说这非常难。让人沮丧的是,随着时间推移,Windows 越来越偏离高级用户的方向,我应该这么说,这也是为什么 Linux 一直都非常棒。但无论是激活,还是任何一种配置,它都一直让人很沮丧。
是啊,我最近比较受欢迎的一期节目,讲的就是为什么你不能移动 Windows 任务栏。我原先完全没想到,但大家的愤怒非常明显,那些人以前——
没错。
……就是把它放在左边或顶部,现在却不行了,这对他们来说简直是对自身存在的冒犯。在某种程度上我能理解。
嗯,这正是我真心不喜欢 Windows 的主要原因之一。Windows 11 有很多地方我都不喜欢,其中之一就是你没法那么自由地定制东西,比如任务栏的位置,这种最基本的定制。我们就不能自己配置一下吗?总会有一小部分高级用户,只要你给他们这个选项,他们就会爱死这个操作系统。这对你来说没有任何成本,就给他们这份自由吧。
嗯,其实是有成本的,对吧?因为允许把开始菜单放在左边、顶部或右边,会大大增加相关代码的复杂度,这些代码负责渲染开始菜单、布局标签和处理其他所有事情。这样一来,出 bug 的面就大得多,要维护的代码量也大得多,所以你可能需要更多开发人员,或者再加一个开发人员,或者占用某个开发人员的一部分时间。于是问题就变成:满足一小部分用户的小众需求,到什么程度为止还值得?这些决定不归我做,但我能理解双方的立场。
我觉得这就像拍电影的人,会放进一些非常细腻、只有少数人才会注意到的细节,这会带来真正的回报。随着时间推移会积累起一种口碑,产生非常强大的连锁效应。我认为这有很多好处,包括有助于招到优秀的软件工程师。就好像你营造出一种氛围:这是一个在每个细节上都倾注心血、真正照顾高级用户、照顾开发者的地方。我觉得微软已经越来越朝这个方向走了,比如 GitHub,收购 GitHub,还有切实照顾开发者。但在 Windows 界面这边,拜托,给点定制空间吧。
在 VS Code 里,你什么都能定制。为什么我们就不能定制开始菜单,对吧?还有任务栏,乃至 Windows 界面的方方面面。我不知道,也许你是对的,也许这确实会增加代码复杂度。但我怀疑事实并非如此。
我敢打赌就是这样。我敢打赌,这是他们重写开始菜单时做的一个排期决定。我觉得他们是重写过的,因为它跟旧的任务栏不一样。
当时有人接到任务:“你必须交付这一组功能。”而如果我砍掉放在左边、顶部和右边的选项,砍掉两行标签以及其他所有很酷的功能,我就能提前四个月交付。我不是说这是正确的决定,但我猜可能正是这类事情促成了它。而且他们现在的发布节奏已经完全不同了。以前是……除非有人长期负责一个组件,让它稳定到一定程度,你才能在此基础上打磨、精修,否则你不会看到太多匠心,对吧?但如果它一直在变动,每个版本 UI 都在改,那它永远也达不到那种打磨程度。不过我觉得现在的 UI 还挺不错的,但是……
是啊,确实不错,但我觉得这是匠心的问题。就像你做任务管理器那样,如果团队里有那么一个人,不管男生还是女生,真正把它当成自己的东西,满怀热情……对他们来说,这是一件可以长期引以为傲的事,他们靠自己一个人就能在短时间内做出真正出色的东西。
没错。
而且我觉得,如果你有庞大的软件工程团队,有经理、有会议排期之类的一大堆东西,好吧,那你的论点成立。但如果你让那些能做出酷东西的个人自由发挥,让他们做自己的副业项目,谷歌在这方面就做得很好。
他们试过这种做法,对吧?在谷歌,是的。
是啊,就是尽情去玩。去做些疯狂的东西,然后我们再把它整合进来,试着整合进整个生态系统。我不知道。我不知道,因为对我来说,一个开发者能做出开始菜单或任务栏定制这样的东西,是莫大的乐趣,因为你知道会有数百万人使用任务栏。你还知道,可能会有成千上万、数以万计的开发者用它来定制任务栏,哪怕是很细微的地方。你知道你能创造多少快乐吗?能让人们享受多少定制的乐趣?比如弄个 JSON 之类的东西,让你能定制任务栏的某些方面。
好吧,但你怎么回应史蒂夫·乔布斯的那种观点:给你提供定制选项,就意味着我们没能替你找出正确答案?又或者根本就没有正确答案,四种答案都同样正确。我也不知道,但是……
对。我一直觉得……我很高兴苹果存在。它是个美好的东西,那种设计理念很棒,但我一直认为 Windows 正好形成了对照。Windows 的意义就在于做一个能在各种设备上运行、理应更加开放的操作系统。他们也通过 Windows Subsystem for Linux(适用于 Linux 的 Windows 子系统)越来越朝这个方向走,这是一整套对开发者友好的生态系统。我觉得界面也应该秉承这种精神。不过我也确实认为,这样做可能会带来安全漏洞。问题不只是代码复杂度,因为 Windows 一直在遭受攻击。
要保证它的安全非常困难。总之,话题先岔开一下:你还为 Windows 开发了 ZIP 文件支持,做出了 Visual ZIP,它后来演变成了 ZIP 文件夹。讲讲这个故事吧。
所以那又是一款我在家里写的软件。事情是这样的:我和妻子出门,我记得是一个周日下午,我们开着车四处转。那是1993年,我们住在公寓里,只是想看看房市行情怎么样。有个人,他有一栋漂亮的三居室房子,车道上停着一辆1993年款的红色克尔维特(Corvette)敞篷车,火炬红。那栋房子在出售,价格我记得大概是30万美元。那时候我根本不可能拿出30万,连首付都拿不出来。于是我拿了那张宣传单,把房子的照片剪下来,用胶带贴在我的显示器上。那就成了我晚上写点东西的动力,因为我下班回到家,其实是在做两件事。
第一,我在释放一种创造力,这种创造力在工作中只是修 bug 的时候是发挥不出来的;第二,我想多挣点钱。于是我写了一个 Shell 扩展。其实在我真正调到 Shell 团队之前,我就开始写它了,也正是它让我产生了去 Shell 团队的兴趣。它基于一个 MSDN 示例,或者说当时的 MSJ,我看到的一个 MSJ 示例,讲的是怎么,比如说,打开一个文件夹。嗯,一旦有了最基础的“打开文件夹”模板,再往里加 ZIP 文件支持,就完全是一点一点累加的事了。我把它作为共享软件发布了。
我记得是19.95还是29.95美元,我卖了大概几百份还是几千份吧。有一天,我正准备去上班,接到一个电话,是一位女士,她问:“你是戴夫·普卢默吗?”我说:“是。”她说:“你就是写 Visual ZIP 的那个人?”我说:“是。”她说:“我是微软的 Betsy,我们想请你过来一趟,谈谈收购它的事。”我说:“好啊,你在哪栋楼?”她说:“什么意思?”我说:“我过去找你就行。”她说:“不行,你得先跟差旅部门谈,还得跟法务部门谈,这些都得事先安排好。”我就说:“我不明白,我们俩在同一个地方上班啊,我为什么不能直接过去一趟?”我不知道我当时是不是真的原话这么说的——
……但我们来回说了好几分钟,才双双意识到她不知道我就在微软上班。
是啊,这太好笑了。
他们只是冷不丁给作者打了个电话,然后才发现那个作者就是我。
是啊,真好笑。
于是他们给我开了个价。这种事情是这样的:如果我不接受这个报价,那我现在的选择就是:要么继续卖我自己的版本,从微软辞职;要么停止卖我自己的版本,继续在微软工作。这两个选择都不太理想。我是说,我当然想保住工作,但我也还想——……保留这份收入来源。另一个选择就是接受他们的报价,我最后也是这么做的。然后我就买了一辆二手的1993年款红色克尔维特,然后……
那你还能在公司内部继续开发它吗?
可以。我们删掉了很多功能,对吧,为了简化。因为它带有加密功能,还有一些在当时的 ZIP 程序里很常见、但可能不适合放进 Windows 的功能。而且在当时,加密差不多被当作军火来看待,所以你不能随随便便往操作系统的各个部分里加加密功能,于是我们删掉了这类东西。多卷(分卷)支持,我记得也是为了简化而删掉的。
你能大致讲讲 ZIP 吗?就是 ZIP 的历史,还有,你知道,压缩,那一整套东西?
好。它其实诞生于 BBS 时代,当时人们用调制解调器拨号,从网上的 BBS 下载试用软件、共享软件和其他东西,并且要把这些东西压缩。可执行文件压缩后大约是原来一半的大小,其他东西的压缩率要高得多。有个叫菲尔·卡茨(Phil Katz)的人,为 MS-DOS 写了一个叫 PKZIP 的命令行程序,可以对程序进行压缩。他的人生轨迹相当悲惨。但 PKZIP 在整个 PC 行业里变得无处不在,几乎所有人都在用它。所以 Windows 出来的时候,没有办法打开 ZIP 文件,可大家已经制作 ZIP 文件整整十年了,这就真正推动了人们希望 Windows 直接内置 ZIP 支持的需求。
是啊,这又是一款一直陪伴我们到今天的软件。
嗯。它其实还有很大的改进空间,但你知道,它是在单核时代写的,所以完全不支持多线程。你有一颗96核的7995,结果它只用其中一个核来给你解压文件。
你在微软还参与过哪些很棒的项目?还有哪些软件?
我参与过 Windows Media Center 最初的原型。我们做了——
不错。
……那是在1996年,我记得是。当时我们没有任何片源,所以只有一张光盘,里面是一些 MPEG 视频文件,有《Raging Rudolph》,还有我记得是最早的《南方公园》(South Park)视频——……圣诞节的那个,这些放在今天的职场里都极其不合适,但是——那就是我们手头仅有的内容,直到我们真的……我们让人在楼顶装了一个卫星天线,DSS,就是那种18英寸的天线,因为我们没法把有线电视接进楼里。于是我们搭出了这个东西,它后来看起来非常像 Media Center。它是 Windows 的远距离观看界面,这样你就可以拿着遥控器坐在一台台式机前面,你知道……现在的开始菜单在20英尺外看可不怎么样。
给我讲讲那个臭名昭著的蓝屏死机的故事吧。
它是这样的:当 Windows 别无选择的时候,当内核进入某种发生了非法操作的状态时,比如说某个设备驱动程序试图写入一块不属于它的内存,或者试图把同一块内存释放两次,总之是根本不应该发生的事情,内核别无他法,它就会把机器关掉,来保存你的工作。嗯……其实不是保存,而是防止进一步的损害。它会显示一个蓝屏,并打印出堆栈信息,具体取决于你的设置。有时候只有一个哭脸,在现在的 Windows 里是这样。
我很好奇蓝屏最早是在哪个版本的 Windows 里出现的。
Windows 3 就有蓝屏,但它跟 Windows NT 里的蓝屏完全没有关系。我跟写 Windows NT 蓝屏的那个人聊过,他叫 Jon Viert。至于他为什么选蓝底白字,我原本以为,我一直听说是因为在实验室里,你可以走过一间有50台电脑都在跑压力测试的实验室,“哦,那台蓝屏了,它——”“崩了。”其实没那么简单。只是因为他开发时所用的 MIPS 固件是白底蓝字的配色,他用作编辑器的 Visual SlickEdit 也是同样的配色方案。所以你写代码、启动、崩溃、重启,全都在同一套配色里。
你觉得为什么电脑的那么多问题,关机再开机就能解决?
我觉得电脑运行久了,主要会发生两件事。一是内存被占用了却没有被释放,于是它在堆上、在交换文件里或者别的什么地方不断累积,运行就变得迟缓。另一个是代码进入了开发者没有预料到、或者没有好好测试过的状态。也许那是一种很少见的状态,但现在记事本、Word 或者 Excel 正处于那种状态,你的系统就会变得怪怪的。所以如果你直接重启它,或者关机、重新启动,你就得到了一个全新的状态,也没有内存泄漏,所以基本上,它能掩盖很多毛病。
而且好几个处于怪异状态的软件以错综复杂的方式相互作用,会形成一种“元怪异”状态,整个系统都开始有点不对劲。然后不知怎么的,这样一来就修好了。你在微软那段时间见过的最好和最差的代码有哪些?有哪些漂亮的代码和难看的代码会浮现在你脑海里?
说到漂亮的代码,有两个让我印象深刻。一个是整体上的内核。当你深入到 Windows 内核里——
……深入到真正的 NT API 之类的东西里,它写得非常好,而且遵循的标准是你在用户态那边看不到的,或者至少在用户态那边并不常见。在用户态那边,我记得见过的最酷的代码,大概是一个叫 Bob Day 的人写的,他写了一套命名管道实现,用来取代对共享内存的使用。Windows 95 在所有 Shell 进程之间有一个很大的共享段,用来存放所有 Shell 共用的东西。我们不想那么做。在 NT 上,从工业级的角度来看,共享内存是个坏主意,所以他想出了一种用命名管道来实现的办法。我记得我对它做过代码审查,逐段走读那段代码的时候,真的非常让人佩服。
那是那种让你觉得“哦,就算让我试着做,我大概也做不出来”的东西。
你遇到过的最伟大的程序员是谁?
你知道吗?我觉得没有哪一个人能算唯一的答案。我见过不少伟大的程序员,但我给你讲一个让我印象很深的故事。那时我刚进公司,才待了大概六周,正在做我之前提到的那个 OLE Presentation Cache(OLE 呈现缓存)。我在 Windows 95 上,把 Excel 插入到了 Word 里,我在用内核调试器,调度器里出了点问题。而我那时候,你知道,几乎没写过什么 x86 代码,我盯着 Windows 调度器,想弄清楚我的东西为什么死锁了。
最后我卡住了,有点超出我的能力范围,于是我给 Windows 95 内核团队发了封邮件,说:“能派个人过来一趟吗?”大约10分钟后,一位开发者溜达着走进来,手里只拿着一根零调制解调器线缆,用来把我的两台机器连起来,这样就能用一台去调试另一台,以防我还没接好,不过我其实已经接好了。于是对方坐下来,用的是 WinDbg,那是个糟糕透顶的调试器,简直是被诅咒了。
但对方用起它来非常非常熟练,飞快地翻过一个个调用栈,检查内核里的各种对象,想找出谁在等谁、为什么会死锁、哪些东西已经发出信号、哪些还没有。那就像一场调用栈飞速掠过的水银芭蕾,我在旁边看着,相当震撼,因为我自认是个不错的程序员,但这个人是个了不起的调试高手,我从没见过这样的表演。大概五分钟后,我只听到一句:“哦,我明白了。”然后对方就断开连接,起身走了。那就是 Laura Butler,她后来成了微软的杰出工程师。我想她可能现在还是;我不确定她退休了没有,不过……
所以她某种程度上给我定下了一个模板,你知道,就是微软开发者调试时是什么样子,内核开发者是什么样子,甚至女性开发者是什么样子,因为我的样本量实在太小了。但那是一个非常高的标准,所以……
人生中没有几件事比看到在任何领域都极其能干的人更让我喜欢的了,真的。不过在工程领域,越底层越好。比如说,他们能够运行或维护计算机基础设施。不是单台计算机,而是计算机之间相互通信、协同工作。那些人简直就是魔术师。这太鼓舞人心了……就像看一位出色的木匠,或者……
我喜欢任何做得非常非常好的东西。
是啊,看到这些真美。看到人类能够做到这样的事情,真美。即使在土木工程里,我看着那些桥梁,就会想到得有多少人齐心协力才能把它建起来,而现在每天都有数百万人在使用它。而软件呢,有时候你没法直观地看到一个东西影响了多少人。想象一下有多少人受到 Linux 以及构成 Linux 的各种开源系统的影响。这太不可思议了。任务管理器就是这样一个软件的例子。这些年来有多少人用过它,又用了多少次?太疯狂了。大概是,有几十亿吧?几十亿人用过它。
是啊,大概每月20亿之类的。
20亿?
差不多是那样。我看过那些数据,这个数字确实很高。
哇,想想都觉得疯狂。
确实。不过我喜欢它的一点是,我相信你也有过这种经历:有时候你设计一个软件,它很复杂,你先在脑子里让它跑通,把底层的管道打通,你知道它会怎样运行、怎样流转,然后你最终写出代码,代码做的正是你脑子里设想的那件事。而现在,我脑子里设想的那个东西有数十亿份拷贝,在数十亿人和机器上运行,这件事本身对我来说就非常酷。我想,这与其说是虚荣,不如说是我自己也被它震撼到了。
这些年你的编程方式有什么变化?
如今我对复杂性要谨慎得多。以前的做法是写代码,然后一直写、一直写,到某个时候再回头清理。现在我反过来写。我会尽量先写出非常干净的初始骨架代码,然后再把它充实起来,因为我参与过太多项目,有我自己搞的,也有别人搞的,最后弄得一团糟,根本没法修了。所以有时候前期投入的功夫是会有回报的,你懂吧?
这些年你用过哪些编程语言?你最常用的主力语言是什么?
对我来说,一直是 C++ 和汇编语言。
直到今天,你主要依靠的还是 C++?
是的,不过现在我百分之百在用 Lua 和 Python,但那只是因为我在做一个业余项目。
能聊聊你绕道去用 Lua 和 Python 的事吗?还有,你喜欢 C++ 的哪一点?
我在做的是,我想打造一个 AI 来玩《Tempest》这款游戏。就是雅达利那款老游戏《Tempest》。这款游戏的世界纪录其实就是我保持的。
能带我看看这款雅达利游戏《Tempest》吗?好,雅达利《Tempest》。这是一款什么样的游戏?
它是 1980 年的一款 3D 矢量游戏。
好的。
而且它是一款非常复杂的游戏。你可以做完整的 360 度移动,屏幕上可以有八发子弹,大概有 11 个敌人,还有尖刺。所以这是一款非常复杂的游戏,可不像做个《Pong》之类的东西。我最后的做法是,先把 ROM 从机器里取出来,对代码进行逆向工程。这样我就大致弄清了《Tempest》里所有代码放在哪里、做什么,零页变量在哪里,各种东西都放在哪里。对,那里就有一个。
哦,哇。这非常几何化……好,关于玩法你能给我讲讲吗?
对,那就是我在玩这个游戏。
这真的是你本人在玩?
是我。你会看到,正上方中间显示的最高分就是 Dave。
能给我解释一下我看到的是什么吗?
嗯,这是一个 3D 几何世界。它基本上就是把 3D 版的《太空侵略者》包裹成一个形状,敌人从管道中心向外侧逼近,而且它们各自有不同的行为。
哇。
长话短说,要把这款游戏玩好相当复杂,我想看看能不能让 AI 做到。所以一旦我弄清了游戏里所有关键部分在内存中的位置,我就把它们作为参数加进去,并做了一个 Lua 程序,在游戏运行时从游戏内存中提取所有信息,把它们组合成参数,通过套接字发送到 Python 端,然后由 Python 端进行强化学习(RL)。我用的是对决深度 Q 网络(dueling Deep-Q),而且我相信……有两个,带着头和尾,它们互相追逐。现在它大约能玩到第 36 关,这比大多数人类强得多。但那是第 96 关,所以它还有很长的路要走。
你就是那个在射击的红色东西?
是的。
你控制的是那个在射击的红色东西?好。有哪些操作?你只能顺时针或逆时针移动,然后可以射击。
对,你有一个旋钮……那是一个光学旋转器,还有一个开火按钮,以及一个紧急情况下用的超级电击(super zapper)。但就这些了。基本上就是开火和旋转。
好,我们回到你最爱的 C++。你喜欢 C++ 的哪一点?为什么这么多年你一直在用它?
因为它让我可以把我最爱的 C 代码封装到类里。我并不是特别……
你骨子里其实是个写 C 的人。
嗯,其实我……
好,我懂了。
对,我骨子里其实是个写 C 的人。不过我会写两种 C++。一种是非常现代的 C++20,不用指针,不用字符串,或者说不用字符数组字符串,所以就没有……你知道,在我看来,它基本上和 Rust 一样安全。另一种是我写带类的 C,也就是标准 C,但带有多态和封装。我的大部分代码是后者,但两种我都会尽量去写。
我想问问我们大致跳过的那一整段时间。这些年你做了很多软件,有在微软期间业余做的,也有离开微软之后做的,很多都很成功。你的公司之一是 Software Online,我想它因为过于频繁地纠缠用户而惹上了麻烦……
没错。
……要求他们升级。这是我看到的说法。那到底是怎么回事?你从那段经历中学到了什么?
那是……除了家人健康方面的惊吓,你知道,比如孩子生病的时候,那是我一生中最可怕的一段时期。而在那之前的一段时间,又是我最振奋、最激动的时期之一。当时的情况是:我还在微软的时候,写了很多共享软件工具,在业余时间卖,就像我们之前聊过的,还卖了一个给微软,而且它们开始卖得非常好。然后我发现了在线横幅广告。于是我用信用卡在一个网站上注册了,我记得叫 Fast Click,你可以设定:“每次横幅广告展示我愿意付这么多钱,这是我的横幅。”然后它会把你的广告轮播进去。我没有设置上限。周一回来一看,我已经在横幅广告上花了大约 10,000 美元。
我当时想:“我的天。我该怎么跟我妻子解释?这是个 bug,是个失误,是我的错。”然后我看了看销售额,结果它带来了大约 38,000 美元的销售额。我就想:“天哪。那我只需要在某个时候把规模放大就行了。”接下来的几年我基本上就是这么做的。而我们惹上麻烦的原因是,总检察长(AG)介入了,他们有……嗯,我当时惊呆了,因为他们大概列了 12 项诉由,其中 10 项离谱至极,作为一个自闭症人士,我怎么也过不去这个坎。就好像,我知道这 10 件事绝对不是真的,我们为什么还要坐在这里讨论它们?然后他们真正在意的只是那两件可能属实的事。
那两件可能属实的事,一件是:它是 30 天试用版,30 天到期后,如果你继续运行它,既不购买也不卸载,它就会每天提醒你一次。不是每 10 分钟一次,而是每天一次,或者每次你启动电脑时提醒,但最多每天一次。总检察长认为这太频繁了,相当于垃圾信息。于是我们同意了他们的要求,我记得是把提醒限制为每周一次。而且,你知道,必须有一个一键卸载的按钮。所以我们做了这类改动。另一件事是,在那个年代,有人买软件时,即使是在网上买并通过下载获得,他们也完全预期会有实体介质寄到家里。
所以在 2001 年,我们说的是 2001 到 2003 年这段时间,如果你买软件,大家会预期有一张光盘寄过来。于是我们把用光盘交付设为默认选项,要额外收 3.95 美元或 4.95 美元,这一点标得非常明显,但它是一个复选框,并且默认勾选了把光盘寄到你家。因为我们发现,如果不这样做,就会接到大量电话:人们会等,下单两周后打电话来问:“我的光盘呢?”我们一查:“哦,您没有订购光盘。”“那就全部取消。
我不要了,因为我不想等。”所以在我们不附带光盘的时候,退货非常多,于是我们决定附带光盘。但在华盛顿州,这本身就直接违反了关于负向确认计费(negative affirmation billing)的规定,因为你给了他们一个默认的更高购买价格。
那软件与用户之间的关系呢?这很有意思,比如该多久拿某件事去烦用户一次,对吧?如果你从不提任何东西,他们可能永远发现不了自己真正想要的东西。但如果你提得太多,他们又可能会烦。
对。而你不希望出现的情况是,他们必须去做某件事、买某样东西,或者采取某种行动,才能摆脱它。
这正是让我困扰的一点……我觉得 Windows 直到今天还在一定程度上这么做,它会问我一些问题来烦我,比如“你想要这个吗?”举个例子,我真的不喜欢用我的微软账户登录 Windows。我觉得现在这基本上是强制的了,我认为已经没有办法绕过去。但他们让不这么做变得非常困难。就好像他们觉得可以骗我……真的感觉像是我被骗着不去做我想做的事。
就是……我得想一想:“好,我需要点‘跳过’。”然后它又会弹出点什么:“你确定吗?”就好像我要动用太多脑子才能做成我需要做的事……作为一个界面,你明明知道我想干什么。你却在想办法骗我不去做我想做的事。我讨厌这一点的地方在于……当然,它在转化用户方面可能很有效,但从长远来看,它真的不利于照顾用户的利益。
对,真正让我犯难的是“使用推荐设置”。我刚做了一次 Windows 升级,一步步走完流程,你知道,我在走这个新的对话框或者说向导,“使用推荐设置”听起来像是你应该选的,但我很确定它会把你重置回使用 Edge 浏览器……还有其他各种东西。所以,是的,那是他们推荐的,而不是为我推荐的。难就难在这里。
这是个很好的例子。你觉得把默认浏览器重置为 Edge 会带来什么影响?你觉得这样做真的能赢得用户的忠诚吗?你不觉得其实……你会制造出的是……你会在一部分用户群中制造出某种被动的忠诚,所以从指标上看,可能确实显得 Edge 的用户数增加了,但实际上,你会随着时间推移承受声誉上的打击,慢慢形成一种印象:Edge 是那个你没法完全信任的东西。这并不公平,因为我觉得 Edge 是一款非常棒的浏览器,但就是有这种不舒服的感觉。我不知道那是什么,而且……
嗯,你不会希望自己的操作系统成为你的对手,对吧?而 Windows 有时会让人感觉带有敌意。就好像它并没有真心为你的最大利益着想,这在一定程度上让我很不爽。
我的意思是,我们会有这种感觉,我觉得当有人对你超级友好、而本质上是在推销东西时,我们普遍会产生不信任。那种互动带着某种特定的气场。而当一个操作系统以那种方式和你互动时,就像……
对,我宁愿每年花 199 美元买 Windows Pro,或者每月 20 美元,或者不管收费方案是什么,只要不再被进一步追加推销,我的数据也不被拿去变现,诸如此类,所以……
你从那段经历中学会如何找到合适的平衡了吗?
是的,我的意思是,我现在的自我觉察强多了。有些事情我会用很不一样的方式去做,尤其是在广告方面。我一直认为……有个人叫大卫·奥格威,他很久以前为大众甲壳虫做过一则广告,上面是一张黑白的甲壳虫照片,只写了一个词:“Lemon”(次品),下面是一段文字。所以它先是有点标题党,然后提供信息,我一直试图遵循这种模式。不过我认为,卖东西有三种方式:你可以利用性、恐惧或贪婪。性对软件来说不太管用。恐惧对杀毒软件之类的很管用,但对于优化工具、让你的电脑更快的那类实用工具就没那么管用了。
所以我一直试图迎合人的贪心。你懂的,让你的电脑更快、腾出更多可用内存,不管价值主张是什么。但我现在意识到,我是用自己的知识在看这件事;作为一个自闭症人士,我现在明白了,别人会用他们自己的背景知识来看,可能会得出不同的结论。所以我本来只是想激励人,或者调动他们的贪心本能,结果可能是在吓唬人。所以如今我会对这类事情更敏感一些。
问个有点可笑的问题:你觉得排名前三的 Windows 操作系统是哪几个?我是说不同的版本。
我挺喜欢 Windows 2000 Server 的。那是
真的?好吧。……等等,等等,请——
我自己的生意就是用它来运转的,我兄弟的生意也是我用它来跑的。我们为好几家美发沙龙搭建了系统,彼此之间全都用 VPN 连起来,还用 SQL Server,还有……
我不确定自己有没有用过 Windows 2000 Server。那 XP 是什么时候出的?
2001 年。
XP 之前是哪个?
2000。
2000。它好用吗?
嗯,我挺喜欢的。我是说,它没有 XP 带来的那种视觉上的炫酷,但作为一个系统,尤其是作为服务器操作系统,在当时它很出色。
不过 XP 嘛,嗯,我会说,从完整度、影响力以及它延续的时间来看,它大概是面向消费者的最伟大的 Windows 操作系统。
我也这么认为。论寿命它当然够格。现在还有人在用它。我是说,如果还能拿到安全更新,我也还会在一些设备上跑它,因为我需要 Windows 做的事,它能做到 98%,但是……
是啊,那真是了不起。我是说,Windows 95……对我来说,我大概会把 Windows XP 排第一,然后 Windows 95 排第二。
你的衡量标准是什么?个人偏好,还是对行业的影响,还是……
行业影响、稳定性,还有某种……就像编程里有“代码异味”(code smell)一样。就是所有功能之间协调得有多好,有没有一种贯穿整个系统、始终保持一致的设计理念。功能不会太多,也不会简化过头。
对。
但也不会过于复杂。多久会蓝屏崩溃一次。所有这些方面。
我不知道这个描述是否贴切,但我会把它形容为“利落”。没有太多毛糙的地方。它该做什么就做什么,而且做得又快又干脆,还有……
你说过你玩老虎机,既然你热爱硬件和软件,你就是问这个问题的最佳人选:老虎机是怎么运作的?
嗯,我很乐意帮你把它们的乐趣毁掉。
好。
所以——我玩老虎机这件事在我看来挺讽刺的,因为我知道从总体收益来看,这是个不划算的赌局,但那里有一场多巴胺盛宴,明亮的灯光、高对比度的色彩,我很享受。所以我确实会玩。但实际情况是,在内部,基本上有一个黑箱机制,它做的仅仅是生成下一个随机数,并按照概率和赔付决定结果是什么。然后游戏会说:“我得编一段动画来配合这个结果。”也许是三个 BAR 图案之类的,但两者之间并没有关联。它不是转动转轴、看它们停在哪里,再去查表看你赢了什么。完全是反过来的。它先决定你有没有赢,然后再编造出一些东西来配合这种情况。
这,这确实是把所有人的乐趣都毁了。
有一点吧。
运行它们的是什么样的代码?
我其实不太清楚。我试过深入下去、拿到接触一台机器内部的权限,结果非常难。他们不想透露太多相关信息,我敢肯定这也不是什么很深的秘密,但……它们全都是普通的 Windows PC,只不过这些普通的 Windows PC 运行在某种非常安全的隔离环境(enclave)之上,这部分我了解得不多。
对,它肯定得极其安全,对吧?
对。嗯,在 70 年代还是 80 年代,拉斯维加斯有个技术员到处跑,他给老虎机烧录自己的 ROM,里面带有后门,所以他维修机器的时候,就直接把他的 ROM 装进去。
厉害。
然后过了六个月他再回来,然后……
厉害。
触发后门,然后……
我太爱人类了。总之,你还有其他类似这样、你喜欢的系统吗?
我喜欢很多老硬件。我修复汽车,所以我弄很多 1960 年代的肌肉车,轿车和卡车都有。
不错。
还有老电脑,我修复 PDP-11。这是我过去大约六个月以来着迷的东西,也是我的特殊兴趣,我已经组装了好几台。
对,我看到你发了相关视频,那台 PDP-11/83。整个项目是怎么回事?
基本上是这样的:我之前组装过好几台 PDP-11。这些年下来,我攒了一大堆零件,于是我决定:“好吧,那我就造一台我能造出来的最好的 PDP-11。”所以这有点像一次征程,就像你会想把一台 PC 的配置拉满一样,我也试着把一台 PDP-11 拉满。它有 4 MB 内存,在当年那可是海量。对,就是那个。它有很多闪烁的指示灯,为了让这些灯正常工作,我不得不重写 BSD 内核,还有……
我们现在看的是什么?这是……
最上面是一块 PDP-11/70 的控制面板,基本可以先不管它,下面是两个机箱。其中一个装着——
那些不同的旋钮是干什么的?不好意思,问些傻问题。
那些旋钮,呃——……控制你从 LED 上看到的是哪种视图。
哦。
通常你能看到数据总线,也能看到地址总线。你可以暂停机器,可以编辑总线上的地——地址,还可以用开关把东西存入内存。
天哪,触感加上 LED。这才是人们想象中电脑该有的样子。
是啊。
太酷了。太酷了。那这些是什么?这些是什么?这些是 DU1、DU2?
对。这是一种很怪的软驱。它是双软驱,但只有一个步进电机。所以两个磁头像连体婴一样一起寻道。
好。那你用它做些什么?你是在——……你是在修复它们吗?
对。我修复它们,然后——
它真的能运行吗?哦,所有这些闪烁的灯都是真的?
对,全是真的。
哇。
然后我还得重新构建内核之类的,所以我必须去学 BSD 内核。现在我对它挺熟了,为了……因为你没法只是加一个设备驱动,对吧?要支持某个设备,你得重新构建内核。比如你加了一个新的磁盘控制器,那就该构建内核了,所以你得去找源码、找到相应的代码,然后……
你能在这上面运行代码吗?你写过几本关于自闭症的书。你自己就是自闭症人士,我想请你谈谈,自闭症人士的思维与,比如说,神经典型者的思维之间有哪些根本差异。
嗯,关于自闭症思维的基础理论叫作“单向注意”(monotropism)。基本上,它的意思是我的大脑一次只做一件事,而且做得非常投入,做完之后我才能转去做别的事。但我不是一个能多任务处理的人。不管怎么说,我都是一个一件接一件做事的单任务者。自闭症通常伴随着感官敏感和重复行为,以及让情况更加复杂的行为问题。如果这些问题严重到一个人无法在生活中调节或适应它们,它就成了一种障碍。这大概占人口的百分之一到百分之二。
带着自闭症生活,最大的好处是什么?
我能在某一项特定任务上投入惊人的专注和执着。它必须是我热爱的事,必须能带来回报,必须是我能取得进展的事,它必须同时满足所有这些条件。就像一个小孩玩火车一样,我会有同样的感觉。
话虽如此,你也说过你受 ADHD(注意缺陷多动障碍)困扰。
对,困扰还不小。
所以那是其中一部分原因,比如在维持专注方面?
其实问题在于进入专注状态。我很容易分心。我要么戴着降噪耳机入睡,要么就睡不着,诸如此类。但一旦我进入状态,就很难被打扰。所以这有点矛盾。
哦,真有意思。
要进入那种状态很难。
§03文字稿 3
好。带着自闭症思维生活,最大的挑战是什么?
我不知道别人在想什么。我知道如果我处在你的位置、我就是你的话,我会怎么看待这次互动。这已经是我能做到的极限了。但我觉得大多数神经典型的人能感觉到:“嗯,Lex 大概是这样或那样的感受,因为他表现成这样,他的反应是这样,他的面部表情说明了这个……”这些我基本都接收不到。所以对于我打交道的每个人,我都会在脑子里跑一个小小的代理 NPC 游戏。
所以我想这会让社交互动变得有点复杂。
有可能,是的。打电话尤其困难,因为我依赖很多其他线索,而当对方只是在电话里、我只能听到声音时,人与人之间有太多隐含的东西我都会漏掉。所以用 FaceTime 我就好得多,如果有人开了个玩笑,他们之后可能会笑一下——而在电话里,我不知道你是在讽刺还是认真的,诸如此类,所以……
所以这些年这大概给你惹过一些麻烦。
是啊。和我妻子之间也有很多次……嗯,自闭症会带来某种字面化的理解方式。我们有好几年都是这样:她说了句话,我会说:“可这说不通啊。”她会说:“你知道我是什么意思。”我就说:“不,我知道你说了什么,我不是在故意抬杠。我真的只知道你说出来的字面内容。”我没有那种能力。我记得我们和别人开会时,如果会上有三四个人,而我是唯一的自闭症人士,我会告诉他们,他们之间形成了一个沟通回路,而我必须……你们得告诉我到底是怎么回事,因为我真的不知道这里在说什么。所以……
你跟我讲过一件与此相关的事,是早年和比尔·盖茨之间一次有点尴尬的相遇。你能讲讲那次互动的经过,以及自闭症在其中起了什么作用吗?
好。那是我在微软的第一个夏天,我拿到了实习机会,比尔把所有实习生都请到了他家。我想那年招进来的大概有 20 个,也可能是 25 个,去他家后院吃汉堡、喝啤酒、聊聊天。当然,那毕竟是比尔·盖茨,即便在那时他也已经是个大人物,所以你会有点紧张。我的经理 Ben,当时算是我的导师,他认识比尔,就带我过去把我介绍给比尔。他介绍说:“这是 Dave,我们从加拿大来的实习生。在四个月的时间里,他完成了这个功能,还有 copy 和 SmartDrive,”他把我做的所有东西都列了一遍。
但我打断了他,因为我心想:“嗯,其实是三个月。”我不得不打断他们,他们俩都有点“什么?”的反应,然后互相看了一眼,我才意识到那不是……纠正别人的合适时机。不过……
是啊。所以你对那种小小的不准确……?
哦,简直让我抓狂。
然后你当然不会……这种事可能对一次随意的社交互动造成的影响,对你来说并不容易察觉。
是啊。我比以前好多了。以前我不知道,也不知道在对话中毫无意义地插进一句纠正,会对对方产生什么影响、让对方有什么感受。现在我对此有了更好的认识,不过……
对于拥有自闭症思维的人,在如何在这个世界上过得好这方面,你有什么建议?
就事业发达和财务方面而言,我能说的最重要的一点是:推销你能做的事,而不是推销你自己。因为如果你去参加求职面试,试图用你的个性和你有多了不起来打动他们,结果可能好也可能不好。但如果你带着你的作品集进去,说:“看,这是我的 GitHub 历史记录,这些是我参与贡献的出色项目,这是我实际写出的算法,这就是我做的事,”我觉得这样你会走得更远。所以,无论你是弹钢琴还是写代码,都是如此。
话虽如此,在大型团队里,软件工程有很大一部分都带有社交成分,对吧?
确实,这对我来说曾是个短板。
你是怎么……我是说,关于如何解决这个小难题,你学到了什么?
我觉得对我来说,最大的短板是在我开始管人的时候暴露出来的,因为这时你得关心他们的希望、梦想、抱负,关心什么能激励他们。他们各自的整个人生对我来说都有点像个谜,因为我会默认他们希望被激励、被领导、被鼓励、拿到报酬的方式和我完全一样。可事实并不总是这样。有些人需要多得多的肯定,有些人只想要钱,有些人想参加重要的会议、参与做决定。但这些我基本上都没意识到。所以最后我不得不明白,你管理的每个人都有自己的一套动机和优先事项,而且跟我以为的可能完全不一样。
所以我想,你可以把事情说得更明确一些,更好地沟通,比如直接问他们对什么感兴趣。
对。这也是我后来开始做的事,就是直截了当地问。因为要我委婉地把一个人往那个方向引,对我来说很难。我不擅长那种社交上的你来我往,所以……
是啊,社交上的你来我往,有一部分就在于很多东西是不说出口的。你能大概琢磨出来……你能读懂别人。但如果……有自闭症的话,做到这一点可能会有点困难,所以你就得把事情说得更明确。再加上,比如讽刺、调侃和幽默,可能也比较难理解。我真想在你早年在微软的一些交往场景里当个旁观者,看看是什么样子。我是说,一些最伟大的工程师就是这样的头脑,所以……
是啊,我还被人朝我扔过笔记本电脑之类的,而且我敢肯定那是我自己的错,所以……
你写过一个“10 秒自闭症测试”。能解释一下它是怎么回事吗?
好。当然,这里得先说一句……任何只有两个答案的东西,出错率都很高,不过……问题是这样的:对整个社会来说,人们身上更重要的是合作还是创造力?如果你只能选一个,哪个最重要?大多数神经典型的人通常会倾向于选合作,而自闭症谱系上的人往往倾向于选创造力,也就是作为个体去解决问题。
当然,这里面会有一定的出错率。
所以,如果你想把准确度翻一倍,可以再用第二个测试,就是问:“一个房间里有 10 把椅子,进来了六个人,坐在了这些椅子上。还剩多少把椅子?”有些人会说四把,但我会说 10 把,因为椅子还是那么多把,一把不少地在那儿。字面上完全正确。而且我不是在故意抬杠。
嗯,好吧。
我不是想把事情搞复杂,但我的脑子就是这么运转的。所以我看到那个问题的时候,会觉得答案取决于你怎么理解它。
所以这测的是你对事情的理解有多字面化?
对。对我来说,一切都非常字面化。我记得小时候,家里的一位祖父辈长辈在厨房里给我妈做一个花盆架(原文 grandfather,未说明是爷爷还是外公)。他用的是那种很大的角码,我觉得有点用力过猛了,就问:“你觉得这个够大,能撑得住那盆植物吗?”他说:“撑一匹马都够了。”我当时才五岁,可我非常困惑:第一,为什么会有人把马牵进厨房?为什么要把一匹马放到花盆架上?所有这些对我来说都完全说不通,而那显然只是一种修辞说法。但我这辈子很长一段时间里,都把修辞说法当成字面意思来理解,所以……
你提到过“情绪后处理”,这是你用来替代社交互动的一种策略(原文为 replace;结合下一段的“回放”,此处用词可能有转写问题,待核对),让你可以通过某种逆向工程,帮助自己理解神经典型的世界。我觉得这对很多人都会有用。它具体包括什么?它是怎么帮到你的?
就是说,如果我见了某个人,尤其是新认识的人,而且是我跟他们最初的几次接触,比如今天跟你见面也算,那我晚些时候回到家,就会把所有我需要做选择的时刻重新回放一遍。而且大概会先回放最让人不舒服的那些时刻,去搞清楚:在那一刻我做错了什么?我漏掉了什么?对方当时在想什么?下次遇到这种情况我该怎么做得更好?还有,我是不是需要去补救,或者打个电话之类的,那是在情况不好的……你知道,在极端情况下。不过……这种事在我生活中发生过几次。比如,我有一辆车,是我爸在 69 年买的新车,后来我拿去修复了。那辆车现在还在我手里,我们家已经拥有它 50 年了。
大概 20 年前,我把它拿去修复,那是一个历时三年的过程,工匠们在这辆车上花了几千个小时。我去提车,检查车子,对他们的手艺非常满意,嘴上说着“哦,这里做得不错”“这个很棒”之类的。然后我坐飞机回家,开了支票,车子也送过来了。结果大概 10 年后我才意识到,有一大帮工匠在我的车上干了三年,我当时大概应该好好吹捧他们一番,夸他们干得有多好,可我从来没这么做过,因为那不是我当时想要或需要的东西。而我对这一点完全没意识到。
于是我给那家店的经理,或者说老板,发了封邮件,我说:“不知道你还记不记得,10 年前我来提车,当时我大概看上去不怎么满意,但我想让你知道,我其实对一切都非常满意,对做工质量以及其他各方面都是。”他回信了。他说:“我经常想起那一刻。”(笑)我心想:“现在我很庆幸自己提了这件事。”
是啊,人与人之间的互动里有一些微妙的东西,对人们意义很大,如果你直接问他们,他们可能说不清楚,但那确实很重要。而当它不对劲的时候,当某件事不对劲的时候,就会让他们心里不舒服。
没错。
但要对这些进行逆向工程、把它弄明白,对一个可能感知不到人际互动中这些细微之处的人来说,是很难的。
这也正好可以顺带说说共情,因为社会上有一种看法,认为自闭症患者缺乏共情,而我认为完全不是这样。我只能代表我自己。我觉得自己挺有共情能力的,但我认为问题出在沟通上,而且是双向的:我不知道你是什么感受,所以在你把你正在经历的东西告诉我之前,我很难对此产生共情。而一旦我知道了,一旦我理解了你脑子里在想什么,我会非常非常同情你。但在那之前,我会默认你会像我处在你的位置时那样去应对,就我而言,是以我现在所了解的东西去应对。
你会给另一方的人什么建议?他们怎样才能帮你成为更好的朋友、伴侣或同事?他们应该怎样跟你沟通才有帮助,比如说给你提供更多信息?
嗯。要说得非常具体。而且别以为我会领会到那些暗示、言外之意和微妙之处。所以如果你想引导我做出某种特定的行为,你最好直接说:“戴夫,这是你需要做的。”
我今天有哪方面做得不好吗?
没有,暂时还没有。
好吧。满分十分,你给我打几分?我是六分?七分?
7.5 分。
沟通方面?7.5?(笑)浮点数啊,不错。再说说“伪装”。你得跟我讲讲那是什么。对很多自闭症谱系上的人来说,这是一种很重要的经历。什么是伪装?再讲讲你自己在伪装方面有过哪些经历。
伪装就是,这么描述可能不太准确,但它就是“装作正常”的行为。也就是说,我在社交场合中该怎么表现,才能让其他神经典型的人以正确的方式接收和接受它?你在社交互动中做的每一件事,从挥手、做面部表情,到语气,再到姿势,都是一种刻意的设计,而且很费劲。对大多数人来说,这些是自然而然的,就是他们平常的样子,那些很酷的人还做得特别好。但对自闭症谱系上的人来说,这一切你都得装出来。
是啊,装作正常。
有一首 Rush 的歌,你知道这个乐队吧?叫《Limelight》。是尼尔·皮尔特写的。我只会对已经过世的人做这种猜测,所以我感觉他可能是自闭症谱系上的人。歌里有句歌词大概是:“整个世界确实是一座舞台,我们不过是演员,是表演者与扮演者,彼此互为观众。”他在这首歌里用了很大篇幅讲自己没法把陌生人当朋友对待,讲自己能装出某种情绪表现之类的,所以感觉他在这首歌里一直在跟伪装较劲。我完全不知道事实如何,但这是我从中体会到的。
你把崩溃描述为一种压倒性的体验。能描述一下崩溃是什么样的吗?通常是什么触发了崩溃?
一般来说,它是……就是你在情绪上被压垮到一定程度,再也没法控制自己的行为。在电影《雨人》里能看到,他要登机的时候,有点被强迫,然后开始失控。那就是一次崩溃。或者我还在……他们拍过一种……嗯,其实我在影视作品里看到的最好的呈现可能是……那个医生有自闭症的电视剧叫什么来着?他是……总之,有部电视剧里有个医生有自闭症,他是外科医生,最后因为自闭症被禁止做手术,而他一直都想当外科医生,于是他彻底崩溃了,这在电视上算是相当好的呈现。
那实际上发生了什么?比如说,是你越过了某个阈值,然后就……
对。开关一下子就被拨动了。
基本上就像蓝屏一样——
对。差不多吧。
……大脑算法的蓝屏?
就是开关被拨动了。你会切换到原始的大脑。我觉得你的额叶皮层会在某种程度上关闭,所以你就没法依靠决策和过滤功能了。在那种状态下,你基本上就是爬行动物的大脑。那其实是一种恐慌状态。所以它是一种恐慌,是面对无法忍受的当下现实时产生的战斗或逃跑反应。也许是一直以来太让人沮丧了,或者你被搞得晕头转向,或者那天旅途很糟糕,或者工作上跟人吵了一架,诸如此类,这些累积到一定程度,然后某件事触发了你,你的大脑就失去了充分调节你行为的能力。
那爱情和亲密关系呢?这方面有哪些挑战……你知道,有一档节目叫《Love on the Spectrum》。
我听说过。没看过,但听说过。
因为某些方面,比如对事情的字面化理解,在那种情境下,会让恋爱关系的复杂性变得更加显而易见。
你知道,我结婚 31 年了,在一起 37 年,所以我们有很长的共同经历。我觉得我们第一次意识到彼此非常不一样,是有一天晚上,天黑了,我们坐在房子前面的车里,街对面有一栋挺漂亮的房子,有一些很大的砖砌柱子,柱子之间用类似锚链的链条连着,围成了院子的围栏。我盯着这些柱子看,因为它们大概两英尺见方,顶上还有压顶石,我就说:“你知道吗,我在想它们是空心的,还是里面回填过?里面是灌了混凝土还是什么?”我现在的妻子看着我说:“你是怎么回事?你脑子里怎么会有一块地方在乎这种事?”
哈,太好了。
就在那一刻我们就知道了:我是全身心投入、真心在乎这件事,而她也是全身心投入的,只不过她觉得,你干嘛要操心这种事?我们知道我们非常不一样。
是啊。非常具体、看似无关紧要的细节。
但是……我一直不擅长跟人打交道。我想,我看不出别人什么时候喜欢我。我儿子也一样,毕竟有其父必有其子。我给他们买了件 T 恤,上面写着:“如果你在跟我搭讪,请告诉我,而且请说具体点,因为我完全看不出来。”我也差不多是这样。我是说,我得在别人身边待很长时间,慢慢让人对我产生好感,因为我完全不会撩人,完全没有能力去跳那一整套事情所需要的社交舞步。所以我唯一的选择就是做我自己,而这对有些人来说是行得通的。
你能说出“我爱你”这类话吗?
是啊。我是说,她家里对这类事情比我家开放得多。所以对我来说那是一个成长的阶段。不过,嗯,现在说这些对我来说不是问题。
好吧。行。但这似乎无关紧要。比如,这实际上能起到什么作用?
嗯,现在我们会做很多肯定和确认。最近这几年,我们有个习惯:她会直接问“你还好吗?”我就说“嗯。”这里面有两步。一步是“你还好吗?”,然后是我的回应,因为如果我只回一句“嗯……”,她就知道有什么不对劲了。
是啊。所以,
所以总有这种来回“ping”一下的过程,因为我没办法光看别人一眼就读懂对方、知道发生了什么,所以我们就有了这种明确的确认机制,我想,这是我们慢慢建立起来的。
所以“yeah”和“neh”之间有天壤之别。这又是人类沟通的那种微妙之处。你写过人们会有的一种感受,用原话说就是“有一点自闭症特征”。你能展开讲讲这个概念吗?
好的,我认为很多人,也许占人口的10%到20%,处在自闭症谱系的某个位置,但受到的影响还没到构成障碍的程度。不过他们仍然具有许多源于自闭症的特征。我认为,如果他们能以最佳方式理解、识别并管理其中一些行为,他们既能加以利用,发挥随之而来的一些技能,也能缓解随之而来的一些缺陷和问题。我写这个主要是为了我的孩子们,因为据我所知,他们都没有ASD(自闭症谱系障碍),但他们身上都有我的某些与之特别相关的行为特点,所以我想,基本上就是给他们写一本小手册。
嗯。你觉得为什么那么多程序员,那种出色的、了不起的程序员和优秀的工程师,都处在这个谱系上?
我想是那种心无旁骛的专注、把问题化繁为简的能力,以及对东西里面到底是什么抱有刨根问底的好奇心。这是我一辈子的执念:里面是什么?我非得把我妈的烤箱拆开,因为我必须知道那个翻页钟是怎么工作的。我觉得如果你要当程序员,这是个好习惯。
还有愿意、乐于深入细节。是啊。今年你希望编程做出什么很酷的东西?你在做什么?我们已经有了那个在学玩《Tempest》的强化学习(RL)。顺便问一下,那个你进展到哪了?比如,成功和称霸的预计时间是什么时候?就是,胜利?
嗯,已经非常接近能用了。我想现在是在调整模型大小、层数之类的东西,让它的学习能突破那道门槛。不过,你知道,那是几千行Lua加几千行Python,它们相互配合,全都能跑,所以差不多95%的工作已经完成了。现在就是调超参数,然后祈祷有个好结果。
所以从某种意义上说它已经成功了,但现在你是在看它能走多远?
对,我的目标是让它能打败我。
那可挺难的,对于……
确实难,不过现在很多游戏,你知道,它们玩得比人类还好,但也许还不是这么复杂的游戏。
你还在做哪些很酷的东西?今年你希望做出什么?
PDP-11那边,我在想办法弄到一台叫RA82的驱动器。那是个14英寸的大怪物,转速3600转/分钟,听起来像台洗衣机。然后我会找到控制器卡,写代码,把它集成进驱动程序,争取让整套东西都跑起来。
你想在上面跑什么样的代码?
我得让驱动程序栈能工作,所以必须把它的驱动程序整合进内核。
你最近组装了一台有1TB内存的机器。这是怎么回事,为什么要这么做?
我们有个项目叫GitHub Primes。你只要搜GitHub Primes就能找到,它是……
GitHub Primes。
……同一套质数算法,用大约100种不同的语言实现。所以是完全相同的算法,我们要求你遵守某些规则以保证公平。然后你用自己选的任何语言,尽最大能力把那个算法表达出来,我们每晚跑一次基准测试,汇总结果,看看哪些语言最快。
是这个吗?哦,原来就是这个。你用它来?哦,所以——
所以——
这台机器就是跑这些测试的?好,你得跟我讲讲这个项目。这是个史诗级的项目。所以你是在比较不同编程语言的性能。
所有这些语言的性能。它们各自被构建进一个单独的Docker容器,然后全部运行。所以——
这个项目太了不起了。真的非常非常酷。它真正在衡量不同语言的性能。那你从中了解到了哪些语言的情况?通常是哪种语言赢?
我想目前是Zig。
Zig。
是这样,不过会变动。有人会改进C++版本,然后它会领先一阵子,接着Zig那帮人就会不服气,回来把它弄得更快。
所以是Zig、Rust、C++、C?跑的是什么样的代码?他们为了衡量性能要跑的那段代码是什么?
他们做的是,在一个5秒的循环里,每秒尽可能多次地求出1亿以内的质数。
所以是个循环,明白了。一遍又一遍又一遍又一遍又一遍地跑。
对,在所有核心上。
那——
跨所有CPU。
那程序的写法呢?那个会不一样吗?
不会。你想怎么做都行,但必须是质数筛。每个整数最多只能用1个比特,所以你不能用一个字节,虽然那样开销更低、也更容易。还有一些类似的规则,比如你必须在计时循环内分配内存。所以我们有一套规则,也有一些不遵守规则的解法,比如6502,因为你只有64K,没法做1亿规模的筛。像这样的解法有很多,我们作为表演项目来跑,但在主要语言当中,它们都遵守相同的规则,所以差别应该真的就只在于算法在那种语言里是如何表达的。而且其中很多用的是同一个后端编译器,所以真的就取决于你怎么表达,以及那种语言的局限或优势。
每种语言允许有多个提交吗?
可以,可以。比如你看C的,我想大概有五个。
好的。那其中有些可能用的是不同的编译器,还是没有?
有,有些是GCC,有些是Clang、LLVM。
我在看几年前的一张快照,Zig排第一,然后是Rust,再然后是Nim、Haskell。哦,不对,这不是,这不是按慢的程度排序的吧,还是说是?是的。
所以C的耗时大概是Zig的1.5倍。
哇。好吧。太有意思了。嗯,这是个超酷的项目。
我们还收录了一些疯狂的语言,比如PowerShell。有一个PowerShell版本,诸如此类。
所以这是自动化的,比如在提交方式的组织上,是有一套结构的?很酷。
对,现在基本上是欧洲那边的两个人,Rucker和Tudor,在负责这个项目。一开始只有三种语言,我写了Python、C#和C++。我把它们提交上去,发布了那一期节目,然后大家开始往里面加更多解法,结果一发不可收拾,所以我只好找人来管理,他们帮我管得非常好。
你在编程、构建东西时,最快乐的时刻是什么?比如,你最享受的是什么?
我觉得对我来说最有乐趣的是:我构建了某个复杂的东西,事先想清楚了它应该怎么工作,然后一运行,它真的就按那样工作了。那会带来强烈的满足感。所以是看到结果按照我计划的那样出来、而且能跑通,因为第一次很少能成功,不过……
是啊。尤其是第一次就跑通的时候。
我从来不信那种情况。我总觉得自己漏了什么。
确实。不过你知道,用C++这类编译型语言,那总是一种很好的感觉。你写了一大堆代码,全部编译,没有警告、没有错误地编译通过了。那种感觉很爽。你觉得编程的未来是什么?现在,我不知道你真正体验过多少LLM代码生成带来的影响。你经常用Cursor吗,就是带代码生成功能的Cursor VSCode?
用过,我在Python那部分用得非常多,因为我Python不太行,而且算是刚接触。所以我觉得它非常有帮助,因为遇到我不知道怎么做的事情时,我通过看它生成的代码学到了很多。因为如果让我从零开始写Python,长度大概会是AI能产出的代码的四倍,因为如果你精通Python,它可以写得相当简洁。
哦,挺酷的。所以你基本上是为了这个项目学了Python?
对。
所以这是个很好的案例研究:一位出色的C++程序员如何快速学会一门语言。
是啊,我想我算是一路靠氛围编程(vibe coding)摸索过来的。
一路靠氛围编程摸索过来。我是说,用它来学一门语言确实是非常强大的用例。如果你已经是个好程序员,可以通过让它生成代码来学一门新语言,或者学一种解决问题的新思路,因为你大概已经能看懂它生成的Python代码了。
对。
就像根本不用去查任何语法。
对,一旦你看到了,基本都一目了然,但你知道,要凭空从头写出来,就有点不一样了。
是啊,但要那样使用它,你还是得先学会编程。
哦,还要能读懂它,知道接下来该让它做什么,诸如此类,没错。我认为如果你只是新手、从没写过代码,是没法靠氛围编程自己搞定的;但如果你是个好程序员,AI能让你变得极其强大。
你觉得编程的未来会是什么样,比如5年、10年、20年后,整个这套流程?现在,氛围编程有点像一个好玩的梗,因为你仍然得是……那些不会编程、只是在氛围编程的人,几乎全都在做无法用于生产环境的系统。它们不……这非常困难——
要做出一个产品是非常困难的。而那些本来就是优秀程序员的人,某种程度上用氛围编程只是为了……就像你这种用法。他们基本上……那就是个花哨的自动补全,最后他们还会去修改它,或者把它当作学习新API、新语言或者其他新东西、某个具体新用例的方式,也可能是某种不同的图形界面(GUI)组件之类的。但随着它们变得越来越聪明,我们不知道上限在哪里。这可能会改变“当一名程序员”的本质含义。你会思考这个问题吗?
会。我不想说是“提示词工程师”,但我觉得会是类似那样的东西。就好比你是一个建桥的建筑师,曾经有一段时间,是工人在下面把钢梁焊在一起,但现在你是在AutoCAD里拖拽东西,用预制好的大块构件来组装。我猜编程也会变成那样。你不会再一行一行地摆弄代码;你会去移动组件和接口,向AI描述这些交互应该是什么样,然后让它去构建这些组件。但我认为,我们离它能凭空完整生成……还有相当长的距离。你没法说“给我一个与Linux兼容的Linux内核”。总有一天我们能做到,它会直接把它产出来,但我们现在还没到那一步。
我们这么快地沿着抽象层往上攀升,这会让你感到难过吗?你作为一个以前写机器码,后来写汇编,再后来写C和C++的人,现在我们已经走到了用自然语言进行氛围编程的地步?
是啊,我觉得我算是赶上了一个特别幸运的时代,因为我得在三四十年的时间里跟着技术一路成长,所以我懂 TTL 逻辑,也会用 AI 写代码,中间的各个环节我也大致都了解。我的知识当然也有漏洞,但我觉得,要想达到那样的知识水平,或者对整个图景有那么完整的认识,唯一的办法就是亲身经历那么长时间。对于现在才入行的人来说,这很难复制。
你觉得这一切的意义是什么?存在的意义、生命的意义,不管这里到底在发生什么?
做酷的东西。我想,从根本上说,我在乎的是能做出对别人有用的复杂东西,这能发挥我的能力,让我既能有创造性,又能做出别人用得上的东西。要是只能搞绘画、雕塑之类的传统艺术,我就毫无希望了。所以对我来说,这就是生命的意义,然后也许再养大几个好孩子,把接力棒交给他们。
是啊,你这辈子做了很多很酷的东西,影响了数百万人,可能有几十亿人,而现在你又在激励……你在 YouTube 上做酷的东西给大家看,也以这种方式激励着人们。所以,无论是你过去做的一切,还是你现在在做的事,我都是你的忠实粉丝。我真的很感激你所做的——
太好了。
……你所做的事,也很感激我们今天有机会聊一聊。谢谢你,兄弟。
谢谢你。
感谢收听这期与戴夫·普卢默的对话。如需支持本播客,请查看节目简介中的赞助商。最后,让我用比雅尼·斯特劳斯特鲁普的一段话作结。他是 C++ 的创造者,顺便说一句,我很久很久以前采访过他,就是本播客的第 48 期。他说:“世界上只有两种语言:一种是人们抱怨的,另一种是没人用的。”感谢收听,希望下次再见。