受访者:Douglas Crockford |
---|
作者:Peter Seibel
关于JavaScript
Seibel:在程序学习之路上有哪些令你后悔的事情?
Crockford:我了解一些语言,但却一直没有机会使用。我花了不少时间学习APL并了解到其衰败的原因,但这门语言真的非常优雅,可我却没有花时间使用它,这太遗憾了。除此以外,我还了解其他一些语言,知道能用它们做什么,但实际上却并没有机会用这些语言思考。
Seibel:我听说你喜欢ES3版本JavaScript的简洁性。
Crockford:嗯,最终无论怎么对语言进行修订,其要义都是希望促进语言的不断成功。语言越成功,修改的代价就越大。随着你的不断成熟,再教育的成本就会变得更大,同时还有潜在的破坏代价,而这些成本和代价也会变得难以接受。如果你确实非常成功,那就更要小心提防所做的任何变化了。反之,如果你尚未成功,那么就有更大的自由空间来改变了。
JavaScript成为世界上最流行的编程语言纯粹是偶然。目前世界上JavaScript处理器的数量要高于任何其他语言。得益于其安全模型带来的种种问题,JavaScript是唯一一门可在任何机器上编写并运行的语言。 这些还嫌不够的话,再看看那么多嵌入了JavaScript的应用吧。Adobe的大多数应用都嵌入了JavaScript,这样就可以在本地编写脚本控制这些应用了。还有其他很多应用,不胜枚举。这么一看,JavaScript已经变得非常流行了。
JavaScript这门语言的问题在于推向市场以及标准化的过程都过于匆忙了。其大多数缺陷都没有出现在目前的实现当中——只存在于规范中。标准说照错的做,这听起来太吓人了,但这就是JavaScript的状态。它于1999年冻结了,接下来本应走向灭亡。但Ajax的横空出世改变了这一切,JavaScript变成了世界上最重要的编程语言。
于是,我们现在认为应该修复它。但这事应该是在2000年就开始做的,而那时并没有这么做,因为根本没人关注JavaScript。现在它已经长大了。
Web环境下的JavaScript还有一点非常怪异:如果编写服务器端应用、桌面应用或是嵌入式应用,你不仅需要选择语言,还要选择特定的编译器以及特定的运行时。但对JavaScript而言你别无选择,你必须在所有的环境下运行。
由于要在所有环境下运行,bug就没法修复了。如果某个浏览器厂商搞出个bug,他们会说“天啊,搞砸了”,下个月就会发布另一个版本,但我们却不能指望着所有用户都会升级。大多数人一旦在机器里装上IE就再也不会升级了,那些bug就会常年驻留在浏览器上。
Seibel:你希望JavaScript有哪些变化呢?
Crockford:我认为改进JavaScript最好的办法就是瘦身。如果我们能够取其精华,弃其糟粕,那JavaScript会变得更棒。我认为这个办法也适合于HTML、HTTP和CSS。我们应该仔细思考所用的各种标准,搞清楚需要哪些特性,遗漏了哪些特性并重新审视它们,绝不应该盲目地增加新特性。
代码阅读
Seibel:能否详细谈谈如何进行代码阅读呢?
Crockford:每次开会都让一些人阅读他们各自的代码,他们会引领我们查看其编写的所有内容,其他人则负责检查。对于团队的其他成员来说,这绝对是个学习的好机会,通过这个过程他们就可以知道自己的东西该如何与他人的相配合。
每个人都围坐在桌边,手里拿一叠纸,同时还把代码在屏幕上打出来,大家一起阅读。我们会在编写代码的过程中加上注释。有人会说“我看不懂这个注释”或是“这个注释与代码风马牛不相及”。大家的意见极具价值,因为作为开发者的你是不会阅读自己编写的注释的,你也根本没有意识到自己写的注释误导了读者。有这么多人帮助你编写整洁的代码是多么幸福的一件事啊——你会找到自己根本无法找到的缺陷。
我认为一小时的代码阅读抵得上两周的QA。这种剔除错误的手段真是很高效。如果你让能力很强的同事阅读代码,那么他们周围的新手们就会学到很多东西,而这一切是无法通过其他手段获得的;如果新手来阅读代码,那么他会得到很多极具价值的建议。
但这件事我们不能一直留到最后再做。回忆过去,我们会在项目完成之际安排代码阅读,但这个时候已经太迟了,只好取消。现在我深信代码阅读应该伴随着整个项目的生命周期。我花了很长时间才意识到这一点,这么做的好处不胜枚举。
首先,这么做有助于把控项目,我们能够真切地看到大家的进度,也能及早发现是不是有人已经偏离了轨道。
我曾经管理过一些项目,马上就到最后期限了,有人说“耶,马上就干完了”,然后我拿到了代码,发现里面什么都没有,有的也是一些垃圾,离完成还远着呢。管理层最厌恶这种事情了,我觉得代码阅读能够有效避免这种窘境的发生。
Seibel:那你需要指导别人如何进行代码阅读么?可以想象,既不想让代码编写者感觉受到侵犯,又能给出颇具价值的意见是很难的。
Crockford:没错,这需要给予团队成员充分的信任,要明确界定好边界。如果团队不和睦,那就别指望这么做了,这会导致团队分崩离析。如果还没有意识到团队的不和睦,那这么做很快就能发现。这个过程会让你学到很多,也会揭示出很多问题。起初会觉得不太自然,但一旦适应后就会觉得再自然不过了。 另外,我们要编写可读性好的代码。大家都知道,整洁很重要,而代码风格也同样如此。所有这一切会提升代码的质量并增强编程社区的能力。
Seibel:如何编写可读性好的代码呢?
Crockford:可读性有几个等级。最简单的一级是与表达保持一致,适当地保持缩进,在适当的地方使用空格。我有一个习惯来自于早年学习Fortran的时候,那就是,我往往会使用过多的单字母变量名,这个习惯可不好。我真的在很努力改掉这个坏习惯,但太难了——这么多年来还在与之斗争。
Seibel:有什么具体的举措可以提升代码的可读性呢?
Crockford:子集的想法非常重要,尤其对于JavaScript来说更是如此,因为这门语言包含了太多的糟粕,当然其他语言也一样。当还是个菜鸟时,我会翻阅语言规范并弄明白每个特性。我知道该如何使用这些特性并一直在用。但事实证明很多特性并非是深思熟虑的结果。
我现在想到的是Fortran,但其实所有语言都难逃这个宿命。有时语言设计者本身就错了。依我看来,C在设计上存在很多不妥之处。
Seibel:你如何阅读别人编写的代码呢?
Crockford:清理。我会把代码放到文本编辑器中并开始修复。首先,我会统一标点符号,适当缩进,等等这类的事情。我有些程序可以完成这些事情,但从长远来看自己完成会更加高效,因为这有助于我加深对代码的理解。Morningstar曾教会我如何完成这些事情。他非常善于重构别人的代码,并且这也是他所使用的方法,很好。
Seibel:你是否遇到过这种情况:看到代码写得一团糟,然后进行清理,但最后发现原来的代码其实写得很不错?
Crockford:还没遇到过。我认为随随便便写出来的代码肯定不好。好的代码意味着可读性要好。在某种程度上,如果我搞不懂代码的意图,那么写得再好也没用,有可能代码在我不关心的方面表现得很好,比如很高效、很紧凑,等等。
代码的可读性是我的第一要义。它比速度还重要,可以与正确性一争高下,可读性是正确性的重要前提。如果可读性不好,那就不是好代码,代码的编写者可能做出了错误的权衡。
Seibel:你偏爱K&R风格?
Crockford:是的,我认为他们是对的,其最初的风格没错,对于JavaScript更是如此。JavaScript会自动插入分号,这样如果将花括号放在左边而不是右边,那么程序的含义就会发生天大的变化,这种变化是很糟糕的。事实表明K&R风格不会遇到这个问题,但flush风格会。
对于JavaScript来说,花括号是有着正确的摆放位置的;而其他C风格的语言则不是这样,哪种摆放位置都可以看作是正确的。有些人喜欢flush风格的花括号,我也看过有人就风格的正确与否争论了半天,但这些解释都毫无意义,因为他们真正争论的是自己在学校里用的是什么、在第一份工作中又用了什么风格,或者是影响过他的某人使用了哪种风格,那这种风格就是正确的,而其他则是错误的。
这就好比是关于应该靠左还是靠右行驶的争论,结果当然是无疾而终。如果住在孤岛上,靠哪边行驶都无所谓,但如果大家能达成统一确定走同一边,整个社区都会受益无穷。
Seibel:在阅读代码时你会先排版,那你会对代码进行多大程度上的重构呢?
Crockford:我会重新编排代码以便所有东西都会在使用前声明和创建。有些语言提供了很大的灵活性,让你无需再这么做了。但这种灵活性我不需要。
Seibel:你曾在之前的一次演讲中引用了《出埃及记》第23章第10节和第11节的内容——六年你要耕种田地,收藏土产,只是第七年你要叫地歇息,不耕不种。并建议每次第7个sprint都应该用来清理代码。那什么时候做比较好呢?
Crockford:每6个周期——不管周期间是什么都该如此。如果你是每月交付,那么我觉得每隔半年都应该跳过一个周期,专门用来清理代码。
每个人的必修课:编程
Seibel:编程是不是越来越容易了,门槛逐渐降低?
Crockford:我对编程的兴趣在于帮助其他人编程、设计特定的语言或编程工具,这样会有越来越多的人能够从事编程工作——这也是Smalltalk的初衷。Smalltalk后来的发展方向出现了变化,但最初的方向确实吸引了我。我们如何设计一门面向儿童的语言,如何为那些并非程序员的人们设计一种语言?
Seibel:你是不是认为每个人都应该学习编程,至少了解一些?
Crockford:没错。当今世界快被计算机控制了,为了保护自己或是让自己更加全面,你应该了解这些东西的工作方式。
Seibel:有些人认为通过编程可以学到一种重要的思考方式,比如阅读和数学就是不同的思考方式,但都非常重要。
Crockford:我以前也这么想。在开始编程时我就有过这种想法:一切都是那么地井然有序,我看到了之前从未接触过的结构等东西。我在想“喔,这太神奇了。每个人都应该学习学习”,因为我突然之间感觉自己变聪明了。但不久之后,在与其他程序员交流的过程中发现,他们并没有开窍。程序员其实与常人也没什么区别,有时他们也会出现误解。当认识到这一点后我觉得很难过。
Seibel:那编程只是年轻人的专利么?
Crockford:过去我是这么认为的。几年前我患有睡眠呼吸暂停的症状,但没有意识到。我想可能是太累了,年纪也有些大了吧,结果发现自己的注意力很难集中,甚至都没法编程了,因为我的大脑没法承载太多的东西。很多时候编程都需要先在脑子里想好,然后再写出来,但我却不行。
我丧失了这种能力,想当然地认为是年龄太大的缘故。幸好,病情得到了好转,于是我又开始编程了。现在的我编程水平可能比以前还要好,因为我知道如何不过多地依赖于记忆。现在的我更喜欢将代码文档化,因为我不敢保证下一周还能记得写这些代码的意图。事实上,有时我会检查自己的代码,但会惊讶于自己怎么会这么写代码:我压根就不记得自己曾经这么写过,这些代码有的非常丑陋,有的却非常优雅。我实在不知道怎么会这样。
Seibel:你曾说过文学编程就像Donald Knuth所说的那样,是个非常棒的想法,那你使用过文学工具么?
Crockford:没有。我一直在考虑这个问题,并为我所使用的一些语言设计过文学工具,但我现在并没有从事文学编程工作。
Seibel:这仅仅是个工具链问题么?如果有现成的工具,你还会编写文学程序么?
Crockford:当然会了。比如说,如果使用文学风格编写JSLint的话,那维护工作就轻松多了。我所说的文学风格是指在设计程序时要特别考虑到阅读问题,这么做会给程序带来巨大的价值。
Seibel:你觉得文学编程工具的主要特征是什么?
Crockford:Knuth的主要贡献在于提出了以各种顺序编写代码的想法。这样,如果我所关注的东西涉及很多地方的代码,那么我会将这些代码整合起来并加以说明,然后工具会在适当的地方解决细节问题。 他还帮助你摆脱了函数大小的困扰。理想情况下,一个函数不应该超出屏幕的范围,这样就能一览无余了。如果达不到这个要求,那可以将一个函数拆分成多个函数,如果函数对程序结构起不到什么作用,那么它也没有存在的价值。
Knuth建议抓住函数的各个方面,它们很可能是紧密相关的——具有一致性,但就是太大了;有时函数确实过于庞大——他建议使用具有描述性的标签来表示每个函数,“这个函数是:”,然后列出这些标签。你当然可以使用函数达成目的,但这两者并不一样,如果使用函数,你必须要处理函数之间的通信,等等。这么做会引入更多与问题不相关的结构。
最后,我非常希望看到新的文学编程语言的出现。Knuth非常擅于将这些想法应用到Pascal和C当中,但我打心底想看到有人能真的设计出一种新的使用这种风格的语言。
Seibel:你读过Knuth的文学程序么?
Crockford:当然读过。
Seibel:如何读的?像小说一样?
Crockford:没错,就像小说一样。我像在读他的散文而非程序,喜欢他的展现方式,他写得确实好,偶尔还会搞个笑话出来。我很享受这种阅读体验。
Seibel:Knuth的大部头《计算机程序设计艺术》如何?你是从头到尾读过这本书呢,还是将其作为参考随时翻阅,抑或是把它束之高阁碰也不碰呢?
Crockford:除了你说的最后一种情形之外。在上大学时,有那么几个月我连房租都没交,就是为了买他的书。我读过这些书,从中得到了不少乐趣,比如在第一卷的索引有个关于拖车的笑话就很好玩。我到现在为止还没能把书上的内容全部搞懂。Knuth对某些地方的研究要比我深入得多,但我还是喜欢这些书并把它们当作参考资料。
Seibel:你是从头到尾逐字阅读,跳过那些不理解的数学部分?
Crockford:是的,我会很快略读过星号太多的部分。我试图将熟悉Knuth的书作为招聘标准,但结果却大失所望,根本没几个人读过他的书。依我看来,任何自称为专业程序员的人都应该读过Knuth的书,至少也应该买过他的书。
Seibel:也就是说Knuth讲述的是如何实现最根本的东西,然后才有全景。即便清理了平台,但使用理性的方式构建大型系统和设计也是非常困难的。请问你是如何设计代码的?
Crockford:编写程序与对程序的生命周期进行迭代是不同的。通常,编写软件的原因在于我们知道将要修改它,而修改任何东西都不那么容易,因为很多时候修改意味着打破旧有的东西。
你不能期望使用这种方式完成所有事情,但还是应该尽力保证足够的灵活性,这样不管做什么都能适应。这就是我的观点。如何避免误入死胡同?如何保证灵活性?
这就是我喜欢JavaScript的原因之一。我发现JavaScript可以轻松实现重构,而重构一个继承层次很深的类实在太痛苦了。
Seibel:你觉得自己是个科学家、工程师、艺术家、工匠还是什么?
Crockford:我觉得自己是个作家。有时我使用英语写作,有时使用JavaScript。归根结底,这完全取决于交流方式以及为了促进这种交流所采取的结构。人类语言与计算机语言在很多地方都是大相径庭的,我们需要阅读计算机语言,因此必须与之交流,我根据语言的这种交流能力判断计算机程序的优劣。在这个层次上,人类语言与计算机语言的差别不大。
Seibel:你对自学的程序员有什么建议呢?
Crockford:两个字:多读。现在有不少好书,去找些好书来看吧。如果从事Web开发工作,请找一些优秀的站点,看看他们的代码。话虽如此,其实我不太想这么建议。大多数Web开发者都是从“查看源代码”开始走上Web开发之路的,但直到现在,大多数源代码的质量都是非常低劣的。因此有一代程序员都被那些低劣的示例误导了,他们写的代码质量也不高。现在的情况已经有所改观,但依然有很多低质量的代码游离于你我之间,所以我是不太想给出这个建议的。