图灵奖得主 Edsger W. Dijkstra:谦卑的程序员(1972 年)(上)

阅读数:1708 2019 年 9 月 16 日 15:34

图灵奖得主Edsger W. Dijkstra:谦卑的程序员(1972年)(上)

本文是图灵奖得主 Edsger W. Dijkstra 发表的演讲,他结合自己的早年求学经历,阐明了软件行业如何一步步发展至今,以及我们可以从中学到的发展规律;他列举了对软件领域有重大影响的编程语言,并展望未来,告诉我们如何更好地应对软件危机。

图灵奖得主Edsger W. Dijkstra:谦卑的程序员(1972年)(上)

Edsger W. Dijkstra(1930-2002)(图源:Hamilton Richards)

机缘巧合,1952 年春的第一个早晨,我正式进入了软件编程行业。据我所知,我是荷兰的第一个程序员。回想起来,最令人惊讶的,是编程行业发展的速度之慢,至少在我的那部分世界里,这简直令人难以置信。但是我的内心对那个时期的两段生动回忆充满感激之情,但这两段回忆也不容置疑地证实了软件行业缓慢发展的状态。
 
在经历了三年的编程之后,我与 A. van Wijngaarden 有过一次讨论,他当时是我在阿姆斯特丹数学中心的老板。这次讨论,让我觉得只要我依稀尚存,就会一直对他心存感激。那时,我本应该在学习编程的同时去莱顿大学学习理论物理,但我逐渐发现这两个科目越来越难结合到一起。因此我不得不做出决定,要么放弃编程,成为一名真正受人尊敬的理论物理学家,要么继续我的物理学习,用最少的努力正式完成学业,然后变成……是的,变成什么?一名程序员?但那是一个受人尊敬的职业吗?回到问题本源来看,编程究竟是什么?可以使编程成为一项高智力的、受人尊敬的学科的健全知识体系在哪里?我非常清晰地记得,我是多么嫉妒我那些搞硬件的同事。当被问及他们的职业竞争力时,他们至少能够说出,他们知道真空管、放大器和其他相关的硬件知识。但我觉得,当我面对这样的问题时,我只能两手空空地站在那里。我满怀疑虑地敲响了 van Wijngaarden 的办公室门,问他是否可以和他说上一会儿话。几个小时后,我离开了他的办公室,变成了另外一个人。因为,在耐心地听取了我的问题之后,他同意我的说法,此时此刻还没有计算机编程这门学科,但他继续静静地解释道,自动计算机就在这儿,我们才刚刚起步,而在未来几年,我能不能成为那个人呢?那个让编程变为一项值得尊敬的职业的人?这段对话成了我生命中的转折点。我尽可能快地正式完成了物理学业。这段经历也带来一个道德上的启示:当我们给年轻人提出建议的时候,我们必须非常慎重,因为有时候他们真的会照着你说的去做。
 
两年之后,也就是 1957 年,我结婚了。在荷兰的婚礼仪式上,需要你说说自己的职业。我说,我是一位程序员。但是,阿姆斯特丹市政当局不接受,理由是没有这样的职业。不管你信不信,在我的婚姻证上,职业这一栏下面居然荒谬地写着“理论物理学家”。
 
这就是在我自己的国家,编程行业发展如此之慢的原因。自那以后,我看到了更广阔的世界。在我的总体印象里,其他的国家也有着非常一致的增长模式,除了日期上可能有些差异罢了。
 
为了能对当前情况作出更好的理解,请允许我更详细地介绍一下。在我们进行分析时,各位将看到我们对编程的本质产生了多少常识性的误解,而这些误解可以追溯到很久之前。
 
第一批自动电子计算机是独一无二的单拷贝机器,它们是在当时研究热情高涨的实验室环境中被发明出来的。就当时的电子技术而言,发明这样的自动电子计算机是一项巨大的挑战。但有一点可以肯定:我们不能否认那些决定尝试打造如此出色设备的团队成员们的勇气。对于那些梦幻般的设备,人们回想起来不禁惊讶,它们竟然可以运转,至少有时可以。当时的一个大问题是如何让机器保持有序的运转。在该领域中较老的科学协会的名称中,仍然反映出对自动计算的物理方面的关注,例如计算机械协会或英国计算机协会这样的名称,其中明确提到了物理设备。
 
那可怜的程序员怎么办?好吧,老实说:人们几乎很难注意到他们。首先,第一批机器太庞大了,以至于你很难移动他们。除此之外,他们需要大量的维修,所以使用它们的地点,自然也就在发明这批机器的实验室里了。其次,程序员的软件编程工作成果不是可见的实物,这看起来没有任何吸引力:你可以向来访者展示这些可见的机器,这比几段代码要壮观几个数量级。更为重要的是,这些程序员对自己的工作也非常谦虚:他们认为这份工作正因这台绝妙的机器而体现出价值。由于这是一台独一无二的机器,他们非常清楚编出来的程序只能用在这台机器上,而且显然,这台机器的生命周期有限,他们很难知道现在的编程工作是否具有持久的价值。最后,还有另外一种情况对程序员的工作态度产生了深远的影响:一方面,除了机器不可靠,这台机器运行还很慢,内存也很小,这就像面对着一只夹脚的小鞋一样;另一方面,用这台机器写出来的或多或少有些怪异的代码,会产生非预期的的程序构建过程。在那个年代,许多聪明的程序员运用了很多编程技巧,才使代码符合了这台机器的诸多限制,不过这也让程序员们获得了巨大的智力上的满足感。
 
在那个编程时代有两种观点。我现在先提一下这些观点,稍后还会再提到它们。一个观点是说,一个具有真正竞争力的程序员,应该是喜欢思考疑难问题的,并且喜欢研究一些精妙的编程技巧;另外一个观点是,编程无非是从不同的方向来优化计算过程的效率。
 
之所以出现后面这个观点,是因为现有的这台设备就像一只夹脚的鞋子一样让人难受,所以在那个年代人们甚至产生了这样天真的期望,即一旦强大的机器出现了,编程将不再是问题,到那时,一切将现有这台机器的计算资源利用率推向极致的努力都不再是必要的,这不就是编程的所有意义吗?但是在接下来的几十年里,发生了一些事情,它们和后面这个观点完全不同:更加强大的机器确实出现了,不止是强大了一个数量级,而是强大了几个数量级,但是我们并没有解决编程上的所有问题,相反的,我们发现自己陷入了软件危机的困境中。这是怎么回事呢?
 
我们先来看一个次要原因:从某些方面来看,现代机器基本上比旧的机器更难使用。首先,新机器有 I/O 中断,他们的出现时机是不可预测的,并且不好重现。相比序列化运行的旧机器,其自动化过程被假定为是一个完全确定的过程。这是一个巨大的变化,许多系统程序员的苍苍白发见证了这个事实,那就是我们不应该只是草草地讨论该功能所引发的逻辑问题。其次,我们有了装配多级存储的机器,这样就给我们带来了管理策略的问题,尽管围绕这一方面的讨论有很多的文献,但这仍然是一个难以捉摸的问题。以上这些就是由机器结构变化而引入的复杂性。
 
以上这些,我只是称其为次要原因,那主要原因……就是现代机器已经比以前的机器强大了好几个数量级!直截了当地讲,没有机器的年代,我们不会想到用编程去解决问题,而当我们有一些能力很弱的机器时,编程也只能解决一些很小的问题。但现在我们有了更强大的计算机,编程也就水涨船高地需要解决更大的问题。从这个意义上讲,电子工业,从来没有解决任何一个问题,相反,它在使用它自己生产的产品制造问题。换句话说,当已有机器的性能增长了 1000 倍的时候,社区想利用这些机器来解决问题的雄心壮志也会得到成正比的增长。在这个爆炸式增长的领域,可怜的程序员们发现他们在目的和方式之间徘徊游走。增强的硬件性能及可靠性(相比性能而言,可靠性增强的幅度可能更大),使得程序员们几年前不敢想像的解决方案变得切实可行。所以在几年之后,程序员们不得不开始思考这些方案。更糟糕的是,他们不得不将以前的这些梦想变成现实!我们发现自己陷入了软件危机,这个现象会令人费解吗?不,当然不,正如你可能猜到的那样,它甚至是可以提前预测的;但是让小先知伤脑筋的是,你得在 5 年之后才能知道他们的预测是正确的。
 
后来,到了 60 年代中期,可怕的事情发生了:所谓的第三代计算机出现了。官方文献告诉我们,这些机器的性价比成为了主要的设计目标之一。但是如果你把机器不同组件的工作周期作为性能衡量因素,那你很可能得到这样一个设计:通过机器内部组件间的管理优化,来达到你的主要性能目标,为了达成性能目标而采用这个方式的必要性却值得怀疑。如果你对价格的定义是要付给硬件的价格的话,那你很可能做出一个硬件设计,这个设计将很难用于编程:例如不管依赖程序员还是系统的指令码,可能会执行早期绑定决策,这些决策可能会产生无法解决的冲突。而且从很大程度上来讲,这些令人不愉快的可能性,看起来正在变成现实。

当这些机器被公布出来,并且他们的规格为人所知之后,我们当中的很多人一定会变得非常悲惨,至少我就是。这些机器可能会充斥整个计算社区。所以这里重要的是,他们的设计应当是非常健全的。但实际上这样的设计有着非常严重的缺陷,这让我觉得,这些机器随便一次出错,计算科学的进展将会被延迟至少 10 年:也正是那时,我度过了职业生涯中最黑暗的一个星期。也许现在最悲哀的事情是,在经历了这些年这么多令人沮丧的经历后,仍然有这么多人仿佛受到某种自然法则的指引,他们真诚地相信,机器就应该是这样设计的。他们对质疑保持了沉默,因为他们看到许多人都在购买这些机器。通过观察,他们得到了一些对安全性的错误认识,毕竟有这么多人买它,那它的设计应该不会很糟糕。但是我们好好想想,基于这个逻辑,是不是可以说吸烟一定有益健康呢,因为有这么多人都在吸烟。
 
计算领域的科学杂志,还不习惯像审查科学出版物一样,审查最新发明的计算机,但是至少应当把审查机器作为同等重要的事情。对于这一点我表示很遗憾。在这里我需要坦白一下,在 60 年代早期,我写了一篇评论,目的是想提交给 CACM 的审稿人。我把这篇评论发给了我的几位同事,以征求他们的意见,尽管他们催促我,让我赶紧提交到 CACM,但是我并不敢做这样的事情,因为我害怕给我自己或编辑部的人带来太多的困难。对我来说,这种压抑是一种懦弱的行为,我因此不断责备自己。我预见到的困难是当时缺少一些普遍被接受的关于机器审查的标准,尽管我认为我所选择的一些标准是合理的,但是我仍然害怕我的评论会被拒绝,或者被认为仅仅是我自己的个人喜好而被抛弃。我现在仍然认为这样的审查将是非常有用的,并且我期待看到它们的出现,因为它们的出现,预示着计算社区走向成熟。

我之所以关注硬件场景,是因为我觉得任何计算工具最重要的一个方面,就是它对试图使用它的人在思维习惯上产生的影响,而且我有理由相信,这种影响比通常假设的要高很多倍。现在让我们转到软件场景上来。

软件场景中的多样性是如此之大,我必须得将此场景限制在少数几个软件领域的奠基石上。我痛苦地意识到我的选择如此随机武断,有太多的推进软件进程的贡献未曾提及和赞扬,请大家谅解。

首先是英国剑桥的 EDSAC ,我认为它非常令人印象深刻,因为从一开始,在这个机器的设计以及使用中,子程序库的概念就扮演了一个核心角色。25 年过去了,计算场景发生了巨大的变化,但是基本的软件概念仍然伴随着我们,封闭式子程序的概念仍然是编程中的关键概念之一。我们应当把封闭式子程序看作是最伟大的软件发明之一。它历经了三代计算机,而且应该会持续更长的时间,因为它迎合了人类最基本的抽象模式。但是遗憾的是,封闭式子程序的重要性在第三代计算机的设计中被低估了,在第三代计算机中,大量显示命名的算术单元寄存器,暗示着子程序机制的开销会很大。但即使那样也没有消灭子程序这个概念,我们只能祈祷,第三代计算机的这种突变不会遗传下去。

软件场景中第二个我想提到的的主要发展是 FORTRAN 语言的诞生。在那个年代,这是一个极具冒险精神的项目,而负责此项目的人应当受到极大的尊敬。它存在一些缺点,但如果因此去责备它,那将是不公平的,因为在广泛使用了数十年之后,它的缺点才显现出来:能够预测 10 年的团队,那都是非常罕见的!回顾往事, FORTRAN 作为一项编码技术是成功的,但它缺少有效的辅助工具来帮助人们理解其代码,这样的工具正是我们现在急需的,而在那个时候,他们认为这样的工具是落后的。我们能够越快地忘掉 FORTRAN,那就会越好,因为作为一个思想的载体,它已经不再适合我们:它浪费我们的脑力,并且风险太大,所以用起来会很昂贵。FORTRAN 的悲哀,正是因为它被广泛地接受和使用,而其历代版本产生的兼容性问题,使得成千上万的程序员感到困扰。我每天都祈祷,希望我越来越多的程序员伙伴们可以找到从兼容性诅咒中解脱出来的办法。

第三个我想提到的项目是 LISP,这个项目具有完全不同的绝妙特点。其底层仅有少数几个最基本的原则,因此它展示了极强的稳定性。除此之外,最复杂的计算机应用程序中,有相当一部分都使用了 LISP。 LISP 被开玩笑似地描述为“滥用一台计算机最聪明的方式”。我认为这样的描述是极大的赞美,因为它传达了解放的全部含义:它能帮助我们一些最有天赋的程序员思考以前所不能思考的问题。

第四个要提到的项目是 ALGOL 60。FORTRAN 程序员仍然倾向于就他们正在致力于具体实现的方面去理解他们的编程语言,因此八进制和十六进制转储变得普遍起来;而 LISP 语言的定义仍然是一个奇怪的组合,即该语言的含义和其工作原理的组合。相比而言,关于算法语言 ALGOL 60 的那份著名报告是一项不懈努力的成果,它在语言抽象上迈出了关键的一步,并以独立于实现的方式定义了一种编程语言。可能有些人会争辩说,在这个方面它的作者已经非常成功了,以至于他们怀疑这个语言究竟是否能被实现出来!这篇报告非常精彩地展示了 BNF 方法的力量,该方法现在被称做 Backus-Naur-Form(巴科斯 - 诺尔范式);同时他也非常精彩地展示了精心分词的英语的力量,特别是连 Peter Naur 这样出色的人都在使用它。我觉得这样说是很公平的:即很少有文档能如此短小,却对计算社区有着同样深远的影响。在后面的几年里,ALGOL 和 ALGOL-like 这样的名字被轻易地用作不受保护的商标,这为一些几乎不相关的新项目带来了好处。相对于该语言的地位来说,这多多少少有点令人震惊。作为设备定义语言,BNF 的优势反倒突显了 ALGOL 60 语言的缺陷,这门语言的过度复杂性,以及不那么系统化的语法,应该可以仅用少量几页文档描述清楚。有了像 BNF 这样强大的方法,ALGOL 60 算法语言报告本应变得更短。除此之外,我非常怀疑 ALGOL 60 的参数机制:他允许程序员有如此多的组合自由,这要求程序员们具有强大的自律性。除了实现起来很昂贵,用起来似乎也比较危险。

最后,虽然这不是一个愉快的主题,但我必须要提到 PL/1,这是一种编程语言,其文档的大小和复杂性令人恐惧。使用 PL/1 必须像驾驶一架飞机一样,在驾驶舱中操纵 7000 个按钮、开关和手柄。我绝对看不出我们是怎样把不断增长的程序,牢牢地把握在我们自己的智力控制之中,因为它使用纯粹的巴洛克式的编程语言。我需要提醒一下,作为我们最基本的工具,它都有这么复杂,已经超出了我们的智力控制。如果我不得不描述 PL/1 在它的使用者身上的影响的话,我能想到最接近的比喻就是毒品。我记得在一个关于高级程序设计语言的专题讨论会上,一个男人称他是这门语言的忠实用户,在他一个小时的演讲中,他不断地赞扬 PL/1,同时他设法要求额外增加 50 个新功能,而他几乎没有意识到,他的问题来源可能正是因为这门语言已经包含了太多的功能。这位演讲者所说添加额外功能的要求令人沮丧,而演讲者本人则处于不断要求添加更多、更多功能的精神停滞和麻木状态。当 FORTRAN 语言被称为处于婴儿紊乱状态阶段时,PL/1 就像是一个肿瘤在不断地增长,它可能会癌变。

俱往矣,除非我们能够从错误中学到经验教训,否则没有必要再犯像之前一样的错误。事实上,我认为我们已经学到了很多,以至于在几年之内,编程可能会成为一项和以往完全不同的活动,我们最好为之做充分的准备。让我为你描绘一个可能的未来。乍一看,在不久的将来,这种编程愿景可能会让你觉得非常棒。因此,人们也许会得出结论,说这样的愿景,可能很好实现。

这个愿景就是,在 70 年代结束之前,我们将能够设计和实现一种系统,这种系统可以充分利用我们现在的编程能力,其成本只有我们现在人力的百分之几。除此以外,这些系统几乎没有任何 bug。这两项改进是相辅相成的。在后者方面,软件产品似乎不同于很多其他的产品,这些产品的质量越高,价格也就越高。而如果想要得到真正可靠的软件,就必须找到一种避免大部分 bug 的方式,在这种方式下,编程过程将变得更加便宜。如果你想得到更有效率的程序员,你会发现,他们不会在调试程序上浪费时间,他们一开始就不会引入 bug。换句话说,上述两个目标都指向了同样的改变。

如此短暂的时间内,进行如此剧烈的变化将是一场革命。对所有人来说,都是基于他们的经验。从最近的历史平缓地推测未来,一些不成文的社会法则和文化惯性起到了强大的作用,这意味着发生剧变的概率似乎可以忽略不计。但是我们知道,有时候变革确实会发生,那这次变革发生的几率有多大呢?

(敬请期待本文的下半部分)

原文链接:
The Humble Programmer

评论

发布
用户头像
2019 年 09 月 23 日 14:11
回复
用户头像
原来,他逝世的那年,我正好在学最短路径算法
2019 年 09 月 17 日 09:12
回复
用户头像
期待后续!
2019 年 09 月 16 日 19:41
回复
用户头像
好文!
2019 年 09 月 16 日 15:48
回复
没有更多了