本文是图灵奖得主 Edsger W. Dijkstra 发表的演讲,他结合自己的早年求学经历,阐明了软件行业如何一步步发展至今,以及我们可以从中学到的发展规律;他列举了对软件领域有重大影响的编程语言,并展望未来,告诉我们如何更好地应对软件危机。
点击这里,回顾该演讲上篇。
Edsger W. Dijkstra(1930-2002)
变革的发生看起来需要满足三个主要条件:
首先,整个世界必须认识到改变的必要性;
其次,来自经济上的诉求必须足够强烈;
第三,这个改变必须是技术上可行的。
就让我按照这个顺序来讨论这三个条件。
对于需要认识到软件的可靠性需求
我猜业界目前在这方面是没有任何分歧的。而就在几年前,情况都很不相同:那时谈论软件危机是亵渎神明的。转折点是 1968 年 10 月在 Garmisch 举办的软件工程会议。这次会议上,软件危机被首次公开承认,这引起了不小的轰动。到目前为止,人们普遍认为,任何大型复杂系统的设计,都将是一项困难的工作,每当遇到负责此类工作的人员时,人们都会发现,他们非常关注软件可靠性,这是正确的。简而言之,我们的第一个条件看起来是满足的。
现在来看一下经济诉求
如今人们经常会遇到这样的观点,在 60 年代,软件编程是一个薪水过高的职业,而且在接下来的几年里,程序员的薪水可能会被下调。通常这样的观点与经济衰退有关,但它可能是在表达一些不同但却十分有益的观点:也许过去十几年,程序员没有做好他们本应该做好的工作。社会对程序员的表现及其产品非常不满意。但还有另一个更重要的因素,目前,对于一个特定的系统,软件开发所付的薪水和当时的硬件价格处于同一个数量级,而人们或多或少认同这一点。但是硬件制造商告诉我们,在接下来的十几年中,硬件价格可能会降低一个数量级。但如果软件开发,仍然像现在这样笨拙而且昂贵,那么事情就会完全失去平衡。你不会期望社会接受这个现象的,于是我们必须学习如何将编程效率提高一个数量级。换句话说,只要机器是预算中最大的一项,那软件编程这个职业,就不存在技术笨拙的问题,但由于硬件价格下降非常快,所以这把经济上的保护伞也将会收拢得非常快。简而言之,我们的第二项条件看起来也是满足的。
现在到了第三个条件,它是技术可行的吗?
我想应该是的,我会给你六个论据来支持这个观点。
关于计算机程序结构的一项研究揭示出,有些程序即使是为执行同一任务而编写,即使用到相同的数学算法,他们在可管理性上也会有巨大的不同。人们发现了大量的规则,一旦违反这些规则,程序的可管理性将受到极大程度的损坏甚至被完全摧毁。这些规则分为两类。第一类可以很好地从机制上进行保证,即适当地选择编程语言,例如不要使用 goto 语句,也不要在函数里返回多个输出参数。对于第二类,至少我没有看见机制上的保证(也许是我所知有限),因为似乎需要某种自动的理论证明才能看到违反这类规则的后果,而我现在还没有这样的证明。因此不管现在还是将来,程序员都需要通过自我约束来遵守第二类规则。这其中的某些规则是如此显而易见,以至于程序员们可以通过学习来掌握,并且在讨论某程序是否违反了这些规则时,永远也不会产生争议,例如,程序中的循环结构如果不具备终止条件,或者反复执行循环中的语句会破坏程序的稳定性,程序员们是不会写下这样的循环代码的。
我建议我们仅设计和实现理解性优良的程序。如果某些人害怕这个限制太严格,那我可以向他保证:想要得到任何现实问题的算法解决方案,这类理解性优良的程序足以。我们必须记得,我们的职责不是制造程序,我们的职责是设计能得到预期行为的程序。而以上建议,将是我要阐述的六个观点中前两个的基础。
论据一,由于程序员们只考虑理解性优良的这些程序,那他们在这个范畴中再选择不同方案时,将会变得很容易。
论据二,一旦我们决定,只在理解性优良的程序中进行选择,那我们就可以很大程度地缩小候选方案数量。注意这个观点和第一个观点有所不同。
论据三,是基于程序正确性的一套建设性方法。目前编程常用的一个方式是先写一个程序,然后测试它。虽然程序测试是找到 bug 的一个非常有效的方法,但这种方法却不能证明,程序中没有 bug。为了让人们更加相信程序是正确的,唯一的方法就是给出一个有说服力的证明。但程序员们不应该先写程序,然后再证明它的正确性,因为这样会增加程序员们的负担。相反的,程序员应该一边证明正确性,一边写程序。本观点基于如下的观察:程序员如果先问自己,有说服力的证明具有什么样的结构,找到它,然后构建一个满足这个证明需求的程序,那么,关于证明正确性的这些考量,就会成为一个非常有启发,非常有效的编程指引。通过以上观察可知,只有在考虑理解性好的程序时,这个方法才适用,但是它提供了一种有效的手段,帮助我们找到这样的程序。
论据四,是关于某种途径的。通过这种途径,设计程序所需的脑力活动量依赖于程序的长度。据说,某种自然法则告诉我们,脑力活动量会随着程序长度的平方而增加。但是,谢天谢地,没有人能够证明这一点,这可能是因为这个说法本身是不对的。我们都知道,把有限的推理过程覆盖到大量的具体情况上,这样的思维方式叫做“抽象“。所以对于抽象能力的有效挖掘,应当是一名合格程序员所从事的最关键的事项之一。说到这里,应该指出的是,抽象的目的不是为了让事情看起来更模糊,而是在一个新的语义层面让人们看到更精确的东西。当然,我也曾经尝试过寻找更基本的触发因素,好让我们的“抽象”机制,显得不那么有效。但不管我多么努力去尝试,都没有找到这样的触发因素。所以我倾向于一个假设(这个假设到现在为止还没有被证伪),通过恰当地运用抽象能力,理解一个程序所需的脑力活动,最多只会与程序长度成正比增长。而这项观察的一个副产品,则具有更强大的现实意义,这也是第四个论据的基础。这个副产品就是在编程过程所展现出来的大量的抽象模式,它们在编程中扮演了关键角色。这些模式现在广为人知,所以你可以对它们中的每一个模式都举办一次讲座。当我清晰地意识到这些抽象模式的时候,我想到,如果 15 年前他们就广为人知,那从 BNF 到语法导向的编译器的发展,将只会花费几分钟,而不是好几年。所以我把近年来发现的关键抽象模式知识作为第四项论据。
现在我们来阐述第五项论据。它与我们正在使用的工具有关,这些工具影响了我们自己的思维习惯。我观察到了一个文化传统,它根植于文艺复兴时期,这个传统倾向于忽视工具的影响,把人类思维作为至高无上的存在,并且认为人类是这些工具的掌管者。但是当我开始分析我自己以及同事们的思维习惯时,我发现了一个完全不同的结论,不管我是否喜欢这个结论:我们正在尝试使用的工具,还有我们正用于表达和记录思想的语言或标识符号,竟然在我们思考和表达内容方面起决定性作用!编程语言对它的使用者思维方式产生的影响,以及认识到脑力是目前为止我们最稀缺的资源,这给我们提供了不同编程语言相对优点对比的衡量标准。合格的程序员,能够意识到他的脑力是有限的,所以他在处理编程问题时,会非常谦卑,并且会像躲避瘟疫一样去避免使用一些投机取巧的小技巧。在广为人知的交互式编程语言环境下,我从各方面都听说,一旦编程环境有了一个终端,就会出现一个特别的现象,它还有一个一语双关的名字:单行程序。它会呈现出两种不同的形式:一个程序员把单行代码发到另外一个程序员的界面上,他要么会很骄傲地解释这行程序做了什么,随后提出一个问题“你可以写出再简洁一点的程序吗?”这就好像是在进行意识领域的讨论!或者他仅仅会问“猜猜这行程序做了什么?”从这个观察中,我们可以总结出,作为工具的语言,可以提供很多投机取巧的小技巧,对那些想展示他们有多聪明的程序员而言,编程语言呈现出强大的吸引力。但是我很遗憾,我必须说,这是一个程序语言最可恶的地方。从最近的经历,我们还可以学习到,编程语言越来越丰富,越来越强大的功能,从某种意义上来讲是犯下的一个错误,因为这些巴洛克式的复杂建筑,这些混搭的功能,真的很难管理,不管从机制上还是理解上。我能看到,在未来,编程语言将变得系统化和简洁。我说的“简洁”的意思是,例如,不仅是 ALGOL 60 的 for 从句,还有 FORTRAN 的 do 循环语句都会被认为是巴洛克式的复杂度。我设计过一次小的编程实验,参加者都是编程方面极其有经验的志愿者,但是结果出现了一些意想不到的事情。没有一个志愿者能找到显而易见和最优雅的解决方法。仔细分析一下,就会发现一个共同的原因:他们的想法被紧紧地绑定在了一个需要加速的变量上,这种思维定势阻挡了他们看到显而易见的方法。他们的解决方法更加低效,这就无谓地增加了理解的难度,并且他们花了很长时间才找到这些方法。这是一段发人深省、令人震撼的经历。最后,从某方面来讲,人们希望未来的编程语言,将极大地区别于我们现在所使用的:用这些编程语言写下的代码,应当能很好地应对软件设计的复杂性。这就是未来工具的优点,也是第五项论据的基础。
此外,我想要警告某些人,他们认为现在编程任务的困难是工具能力的不足所引起的,他们可能会得到一个结论,一旦我们的工具变得更好,编程就不再是一个问题。但是我想说,编程将仍然是困难的,因为一旦从复杂的工具环境中解脱出来,我们将需要面对超出我们现有编程能力的问题。
你可以挑战我的第六项论据。因为还不太容易找到实验证据来支撑它,但这不会阻止我相信它的合理性。到现在为止,我还没有提及“层次体系“这个单词,但是可以公平地说,它是所有系统的关键概念,这些系统都包含了层次化的解决方案。我相信,我们解决问题的唯一方式,就是找到一个层次分得很好的解决方案。乍看起来,这一观点中的局限性,会让你感到沮丧。但相反的,我不这样认为!学习局限性的最好方法就是去了解它们。当我们谦卑到能够尝试层次化解决方案时(因为其他方法已经超出了我们的智力范围),我们就能够尽最大努力,以有效的方式给系统进行分层。而我们会发现,原本不能解决的问题居然能够被分解成若干小问题了。程序员发现,被称为“代码生成”的编译阶段所产生的大部分问题,都可以被分解成很多小问题,这些程序员能理解我所说的这一点。层次化解决方案的广泛应用,就是我的第六项也是最后一项论据,这为接下来的十几年内将可能发生的软件革命,带来了技术可行性。
总的来说,对我的考量赋予多少权重,我会把这个决定权留给你们自己,因为我太清楚,我不能强迫其他人来接受我的信念。就像每个重大的变革一样,它都会激起强烈的反抗,每个人都可以扪心自问,反对软件发展的保守力量将来自哪里。就我来看,这些保守力量不会出现在一些主流领域,甚至不会在计算机领域。相反,它们可能出现在教学机构,因为那些机构提供了训练课程;以及计算机使用者所在的一些保守组织里,他们认为自己以前写的程序太重要了,以至于他们觉得重写或者改进这些程序是不值得的。因此,我们很伤心地看到,在一些大学里,主要的计算机辅助工具的选取,是由一些已有且昂贵的应用决定的。在选取时,教学机构却忽视了一个问题:这些学生用户们,他们希望自己开发程序,但现在他们却不得不忍受这类教学工具的限制。高能物理学科,就经常用实验设备的昂贵价格向科学社区勒索。当然,这在技术上是完全不可行的,但是你需要一个强有力的论据来反驳他们。事实上,我们没法保证,哎,平均水平的程序员能够阻止这场变革的发生:因为还有其他程序员,他们的编程效率很高,平均水平的程序员将会被淘汰掉。
可能还会有来自政治方面的阻碍。即使我们知道如何训练未来的专业程序员,我们所在的社会也不一定允许我们这样做。教授一种方法,而不是传播知识,这带来的首要效果就是,继续提高已经具有一定能力的人的技能,这样会继续拉开人们智力上的差距。在我们的社会中,教育系统是建立同质化文化的一种工具,精英阶层被阻止进入最顶层社会,所以合格程序员的教育,可能在政治上是行不通的。
现在我们来总结。自动计算机已经陪伴我们度过了 1/4 个世纪。它们作为工具所展示的能力,已经为我们的社会带来了巨大的影响,但相较于将在未来带给我们史无前例的智力上的影响,这简直就是冰山一角。层次化系统,看起来有这样一种属性,在某一层上作为一个整体的实体,将可以在更低的层级被细分,细分模块将具有更多的细节。所以在层次化系统中,层级每降低一级,时间和空间的自然粒度也会有一个数量级的下降。我们通过砖头认识墙面,通过结晶体认识砖头,通过分子认识结晶体等等。所以,层次化系统中可以被有意义地区分开的层次数量,与最大和最小粒度之比呈对数正比。于是,除非这个粒度之比非常大,否则我们不会有太多层。在计算机编程中,基本的构建模块在时间维度上具有小于一微秒的粒度,但是我们的程序,可能要花费数小时的计算时间。我不知道是否还有其他什么技术,它的粒度之比是 10 的 10 次方或者更高:计算机以快速的计算能力见长,在计算机环境中,高度层次化的系统看起来是可能的也是必要的。编程任务带来的挑战是如此的独一无二,它可以教会我们很多东西,它会加深我们对设计和创造事物的理解,他会在我们思考时带来更好的控制力。
历史已经教给了我们一些训诫,而我在这个演讲中想强调的要点如下:我们应该在编程工作上做得更好,(实现这一目标的前提是)只要我们意识到,我们所面临的任务的巨大难度,只要我们坚持简洁而优雅的编程语言,只要我们对人类思维的内在局限性心存敬意,并且在解决程序问题时,成为一个谦卑的程序员。
(完结)
原文链接:
评论