返回 登录
0

Knuth:将计算机编程视作艺术

《ACM通讯》在1959年发行的时候,其社员发表过以下评论,在后来成为了ACM的追求:

编程如果能在计算机研究和发展方面成为一个重要的部分,必然存在着从艺术到一门严谨科学的过渡。

这个目标在接下来的几年中不断重现。例如,1970年“将编程从艺术过渡到严谨科学的第一步”发表了。同时,我们也成功地以最简单的方式将规则变成科学,称之为“计算机科学”(computer science).

一个领域一旦被归为艺术,就会产生一些让人不愉快的东西,在具备实质性的声望之前,必须先被认作科学。另一方面,我花了十二年写的系列丛书就叫做“计算机程序设计艺术”(The Art of Computer Programming)。经常会有人问我,为什么起了这么一个标题。甚至还有人不相信我用了这么个标题,在很多引用中,我发现他们错把书名引用为“计算机程序行为”(The Act of Computer Programming,这里,错把art当做act)。

在这次演讲中,我想解释一下为什么我觉得艺术是最合适的词、艺术和科学什么不同、艺术是好是坏以及正视这门学科对我们有什么帮助。

我第一次谈论起这个标题是在1966年。那是在加利福尼亚举办的世界性ACM会议上。那时候我的书还没有出版,我和一个早已了解我的自负朋友一起在酒店吃午饭的时候,他打趣道,“新书打算叫做高德纳导论吗”,我回击道,“恰恰相反,我打算用你的名字。”他叫Art Evans。

这个故事告诉我们,艺术(“art”)一词可以有不同的意义。实际上,最有趣的地方是,几乎所有的意思多多少少都和计算机编程有关。准备演讲的时候,我去图书馆查了一下有多少和用了“艺术”一词的出版物。几天之后得出结论,“艺术”可能是语言中最有意思的一个词了。

旧的艺术

如果追溯到拉丁文中,ars,artis表示技巧,和希腊的τεχνη有差不多的意思——技术和技巧的词根。

现在提起艺术,可能你的第一印象就是美术,例如绘画、雕塑之类的。但在二十世纪之前,艺术的意思和现在大不相同。即使现在,某些方言中还保留这艺术原来的意思,特别是和科学相比较的时候,我想花几分钟介绍一下艺术的经典含义。

中世纪时候,第一所大学是为教授七门学科建立的:语法,辩论,逻辑,算数,几何,音乐和天文,叫做“liberal arts”。注意,这和今天的文科大学有很大不同,七门课中至少有三门是和计算机密切相关的。那个时候,艺术一词指的就是人类设计制造的东西,反抗自然和天性。“liberal”就是自由和解放,和耕种等劳动是对立的。中世纪的时候,艺术本身的意思是逻辑,即三段论的学习。

科学 vs 艺术

很多年来,“科学”一词和“艺术”有着差不多的含义。比如,人们讲七门学科统称作“自由的艺术”,有时候也叫做“自由的科学”。15世纪时Duns Scotus称逻辑是“科学的科学,艺术的艺术。”随着文明和科技的进步,它们才逐渐有了区别,“科学”代表知识,“艺术”代表知识的运用。比如,天文科学研究原理,艺术就是研究如何利用其进行导航。和今天科学与工程的差别差不多。

19世纪有很多有关科学和艺术的讨论,我觉得最好的是John Stuart Mill,他写道:

很多时候,几门不同的科学相互联系,来完成一件事情。人们要结合不同的事物,来做到一件事,这需要懂得不同方面的知识。从某种意义上说,艺术就是组合不同方面的科学,将其付诸实践,而不止于空想。将不同的科学组合在一起,我们才有了探索宇宙真理的可能。艺术将关系偏僻的学科联系在一起,运用到现实生活中,来满足我们的需求。

在我研究艺术的意义时,我发现从艺术到科学的过渡持续了至少两个世纪。比如,1784年的一本矿物学教材的序言中有下面一句话:“在1780年之前,矿物学被认为是艺术,还不算作科学。”

大多数字典中,科学的意思是逻辑、系统地组织一般规律。科学就是可以让我们从更高层次的概念上来思考问题。就像John Ruskin在1853年写的,科学的工作就是将现实的现象进行抽象。

假如这些人能生活在我们这个时代,他们也许会同意以下观点:科学就是我们了解透彻的知识,我们能够把这些只是教授给计算机。如果我们没了解到这个程度,那么就还处在“艺术”的认知阶段。算法或者计算机程序的概念,提供了一种可以测试我们对某一领域了解有多深的方法,从某种意义上说,从艺术到科学的过渡阶段,也就是我们学习如何在这一领域实现自动化的阶段。

人工智能已经取得了重大进步,但是在可预见的将来,计算机能做的事情,和普通人类还有着巨大的鸿沟。人类能够语言,视听甚至编程的奥秘仍未解开,所以某种意义上,我们所做只可称之为“艺术”。

从这个方面说,将计算机编程变成一门科学是可行的,而且从演讲开头的地方我引用的那段评论起,已经过去了十五年,我们走了很长一段路。十五年之前,我们对编程了解的还很少,甚至不知道如何证明一段程序是正确的——直到程序正常运行之前,我们都是在盲目地尝试。只有在近几年我们才明白计算机处理的抽象过程。尽管只有很少的程序能够严谨地被证明正确性,这些理解还是带给了我们很多好处。重点是,我们今天在写程序的时候,我们知道,如果想要证明程序的正确性,是可能的。比起以前写程序,现在要可靠的多。

“自动化编程”是人工智能方面一个很火的分支。其倡导者或许会做这样的演讲:“将编程视作手工艺品(编程是很久之前的历史文物了)”。因为他们的目标是制造可以自动化编程的机器,代码写的比人类好,只要给出特定问题,就可以生成程序。个人来说,我这个目标是不可能的,但并不是说这个课题不重要,因为我们做的每件事都可以提高我们的“艺术技巧”,从这方面说,我们要力争将艺术的方方面面都转为科学:在这个过程中,我们不断推动着艺术的发展。

科学和艺术

从上面我们的讨论来看,计算机程序可以看做是艺术和科学,二者相辅相成。但是显然,很多人不管他们的领域是什么,都会得出这样的结论。我看过一本写于1893年的初级摄影的书,开篇说:“摄影的发展既是一门科学,又是一门艺术。”事实上,当我翻开字典查“艺术”和“科学”的时候,就看见字典的序言上写着,编著字典既是一门科学,又是一门艺术。数据和单词的整理归类是严谨的科学,而斟酌字句和定义则是一门艺术。科学失去了艺术也就失去了作用,艺术没有了科学则缺乏准确性。

准备演讲的时候,我在斯坦福图书馆的目录里面看别人都是怎么在书名里用“艺术”和“科学”的。结果相当有趣。

比如,我找到几本这样的书:《钢琴弹奏的艺术》、《钢琴演奏技巧的科学》、《钢琴练习的科学》,还有一本是《钢琴弹奏艺术:一种科学的方法》。

还有一个比较有才的标题是《数学的高雅艺术》,至少我觉得计算机编程算不上是“高雅艺术”。几年之前,我看过一本叫做《计算的艺术》的书,1879年在旧金山出版,作者是C. Frusher Howard。这本书是将使用的商业计算的,1890年之前,卖出了40万册。序言中作者的理论和我的截然不同,他说:“数字计算的科学并不重要,但是认知的艺术技巧不可或缺。”

还有一些书同时用了科学和艺术两个词,例如Maharishi Mahesh Yogi 的本体科学和生活的艺术。还有一本叫做“科学探索的艺术”,讨论的是科学如何做出重大探索发现的。

从上面可以看出,艺术可以有如此多的含义。但说实话,我在取书名的时候,并没有特意地去考虑这些。有一本很有意思的书,Robert E. Mueller的《艺术的科学》,所表达的意思最接近我今天的主题。他说:“曾经有人认为,搞艺术的丝毫不懂逻辑,而搞科学的在艺术方面就是呆瓜。”他解释了综合艺术和科学所带来的收获。

科学的方法是关乎语言逻辑,系统条理,客观,冷静,理性。而艺术关乎审美,创造,主管,激情,不合逻辑。对我而言,两者在编程方面都有价值。

Emma Lehmer在1956年写道,她觉得编程是“一门令人激动的科学,又是一门迷人的艺术。”H.S.M. Coxeter 在1957年写道,他感觉自己更像一个艺术家而不是科学家。同时,C.P. Snow也在反对两极分化,声称如果我们如果想做出真正的进步,就必须将科学和艺术相结合。

艺术的工作

我听长演讲的时候,一个小时左右注意力就开始不集中了。所以现在大家是不是也有点累了?不过希望接下来大家集中注意力,因为这是我最深入的部分了。

当我谈到计算机程序是一种艺术的时候,我说的是一种艺术形式,一种感官的审美。作为教育工作者和作者,我的工作就是帮助人们学习如何编写优美的程序。鉴于这个原因,最近我得知我的书被康奈尔大学放在美术图书馆的时候格外高兴。(显然,不会有人到这里翻这本书,八成是图书馆管理员因为署名弄错了吧。)

我认为,当我们写程序的时候,就好像在写诗或者谱曲,如Andrei Ershov所说,编程可以给我们理性和感性的双重享受,因为它的目标就是控制复杂的东西,用不同的规则建立庞大的系统。

还有,当我们读别人的程序的时候,就如欣赏艺术品一般来理解它们。我仍然记得1958年在SOAP II上读汇编代码的感觉。可能这听起来有点疯狂,但是我很好奇如此庞大的程序是怎样的。手写漂亮的代码是完全可能的,即使是用汇编语言。这就是我涉足计算机程序的原因。

有些代码很优雅,有些很精妙,有些则闪耀着智慧。我认为,写出宏伟、壮丽、高雅的代码就是一种艺术。

口味和风格

编程的风格在近几年成了热门的话题,推荐读一下Kernighan和Plauger的《编程格调》。需要强调的是,没有什么最好的“风格”,每个人都有自己的喜好,强迫别人适应一种风格是错误的。我们经常听说:“我不懂艺术,但是我知道自己喜欢什么。”重点是,你要喜欢自己所采用的风格,那应该是你表达自己的最好的方式。

Edsger Dijkstra在他的《计算机程序设计艺术导论》的序言中说:

我的目的是让人们认识到编码风格的重要性,但是特定的风格仅仅只能让人意识到风格化的好处。就像教授谱曲的老师,老师不会去教学生如何谱写特定风格的曲子,而是教他们如何挖掘自己的风格,表达自己。

现在,必须来谈谈什么是好的风格,什么是坏的。我们不能用死板的眼光来评判别人的工作,19世纪的哲学家Jeremy Bentham是这样说的:

评判风格和口味就是把自己放在了全人类的领袖的位置上,其实能影响的只有自己的风格而已。没有什么是最好的,除非你的工作是满足雇主的需求;没有什么是最坏的,除非你在故意恶作剧。

当你按照自己的喜好纠正别人的风格的时候,可能从潜意识里干涉了别人的权益。这就是我一般不去反对大多数程序员的原因。重要的是,他们在创造他们认为美的东西。

Bentham提出了一个关于审美的很好的建议——“实用性”。我们有选择风格的自由,但是如果能在符合我们自己的审美的同时,别人用起来又很方便,就更好了。我承认我很享受编程,但是更享受写性能良好的程序。

当然,评价一个程序是不是好的方面也有很多。首先,程序能够正确肯定是好的。其次,如果程序修改起来简单,能够自如应对以后的需求改变就更好了。如果在保证这两点的同时,程序又具备可读性,就完美了。

产品型的程序还有一个重要的地方——与用户的交互性,特别是处理用户输入数据的错误时。组织有意义的错误信息和引导减少错误的设计的确是一门艺术。

另一个重要的方面是程序运行时候的性能和占用的资源。但是现在很多人在谴责关注程序性能,称这得不偿失。现在的计算机进步了,不需要在乎那点性能。而过去的程序员因为过度关注性能, 写的代码极其复杂,导致以后维护和debug的时候非常困难,不足以弥补性能所带来的优点。

真正的原因是,程序员在错误的时间和错误的地方过度关注了性能。过早做优化是罪恶之源。

我们不能反对劳动,提倡懒惰,既不能疏于优化,也不能迷失在斤斤计较的时间和内存中。当我们买一辆车的时候,可能对50块或100块不怎么在乎,但是在商店买东西的时候,对几毛钱都会斤斤计较。我观点是,考虑性能要考虑时机和地点。在我的结构化编程的论文中详细讨论了这个问题。

更少性能,更多快乐

我发现,当我们用有限的工具完成了事情的时候,所获得预约会更多。例如,我曾经写过的一个非常自豪的编译器,仅仅使用了4096个字,每个字16比特。在限制之下做事情会让人有记忆超群的感觉。

同样的道理适用于很多场合。比如,比起加长型林肯,人们更爱他们的大众汽车。当我学习编程的时候,那还是一种消遣,程序是写在打孔纸带的上的,那时候大家在比谁用的纸带更短。现在我们教授编程的时候,如果不让学生在计算机上亲手实验的话,就很难激发他们的学习热情。大规模计算机以及他们的操作系统和编程语言很难从一开始就引起他们对编程的热爱。

如何将这些准则用于提高程序员工作上的预约比较模糊。如果经理突然宣布,新的机器内存只有之前的一半,肯定所有的程序员都会抱怨。任何人,即使是非常热爱编程的人,都不会愿意损失不必要的性能。一个很好的例子是,很多电影制片人在1920年的时候抵制有声电影,因为他们很自豪没有声音也能很好地传达电影的意思。相同的,可能有程序员也抵制性能更好的机器。今天机器性能的进步可能多少毁了一些代码的优雅性,但是却没有人愿意回到默片时代,不是因为懒,而是因为他们知道利用先进的科技,制作多彩的电影是可能的。艺术的形式改变了,但是供艺术家发挥的空间依然很多。

那么他们是如何提高自己的技术的?多年来,最好的制片人往往生活在电影工业不是很发达的国家,在艺术方面有很多限制。近年来,对编程事业推动较大的人都不是有很多机会接触大型计算机的人。这个故事告诉我们,应该在教育中限制资源,当我们认为设限,才会被迫将自己的能力超这个限制进步。我们不能永远生活在奢华的环境中,那会让我们丧失激情。竭尽所有的资源来解决问题会给我们磨练,当面对真正的问题时才能游刃有余。而且在限制下解决问题也会带来更多快乐。

同样都是艺术家,我们没必要因为有趣去做一些事感到有负罪感。我迷上编程就是因为一个解决素数问题的ALGOL程序,而不是产品化的东西。以前我有一个斯坦福的学生,发现了最短的可以打印出程序本身的源代码的FORTRAN程序而激动不已。我并不认为研究这种问题是一种浪费,上面提到的强调“实用性”的Bentham也不反对,他说“相反,这其中的实用性是无可争议的,快乐的源泉不就是最大的实用性吗?”

提供优美的工具

现代艺术还强调的一个方面是创造性。现今大多数艺术家都期望创造出美丽的东西,只有有创新性的想法才有价值。我不是说程序在这方面完全一样,只是这带给了我一方面的灵感。有时候我们会被分配一些很枯燥的工作,甚至几乎是不可能完成的,没有丝毫创造性。这时候有人可能会说:“编程还是美妙的吗?你没有压力,可以随便写优雅的代码,可以这样说。像我一样要处理这些东西,还能说编程是艺术吗?”

的确,不是所有的编程工作都是有趣的。比如家庭主妇,每天要一遍又一遍地打扫相同的地方,这种工作没有创造性。但是即使在这种情况下, 依然可以有乐趣:如果我们有漂亮的同居,那么即使是例行工作,也会有趣的多。想象一下,如果桌子是精心设计过的,非常漂亮,那么每天去擦也不会枯燥。

我想要呼吁所有设计系统和机器给我们用的系统工程师和计算机工程师们,求你们给我们方便的工具,尤其是那些常用的,而不要我们每天跟它们做斗争。请给我们有动力写出好代码的工具,让我们在编程中享受更多快乐。

对我来说,让大学新生接受“编程很有趣”的观点多少有些困难,因为一开始我就要教他们“xxxx任务等于这样这样和这样”,即使批处理语言可以设计的方便易用,而不是像现在这样这么死板。

硬件工程师可以将机器设计地更加易用,例如提供符合数学规律的浮点运算。现在机器上的运算让调试和分析异常困难,但是设计良好的运算可以鼓励数字分析源提供更好的子运算,具备更高的精度。

软件工程师可以做什么呢?一个绝佳的方式是,给系统用户提供可以交互的进程管理程序。系统不应该过度自动化,不能让太多的动作在后台默默进行,应该让程序员可以监视进程的运行。有些任务可以让系统自动完成,有些则应该让程序员手动操作。如何在两者之间取舍?这就是一个优秀的操作系统应该权衡的事情了。

程序度量工具也是一个重要的方面。多年来,程序员对自己程序的性能和开销大多估计有误。那时工具及其有限,也难怪性能总会和预期出入很大。这种工作就像是,新婚夫妇在不知道柴米油盐价格的情况下,做家庭开支预算一样。程序员所有的就是一个优化编译器,而且它的细节也不得而知。幸运的事,我们现在有了系统的监控工具,能实时反映程序指令和开销。这种系统已经取得了巨大的进步,不仅仅因为度量工具的成果,还因为使用起来非常方便。我相信不就的将来,普及只是时间问题。

众所周知,编程语言对风格的影响很多。所以语言设计者也有义务将程序语言超鼓励良好风格的方向发展。现在的语言在程序和数据结构方面的表现都不尽如人意,所以我很期待接下来纪念语言设计的发展。

总结

我们将编程视作艺术,是因为它需要知识的积累,需要技巧和才智,更因为它创造美的东西。将自己当做艺术家的程序员,在工作中能享受到更多的快乐,也会更加出色。我期待能在将来的计算机大会看到人们用这样的标题:艺术的现状。


这是Donald E. Knuth的Turing Award Lecture演讲,原文发表于1974年《ACM通讯》,译者赖信涛。

评论