十年学会编程 Teach Yourself Programming in Ten Years

本页内容

本篇为 Peter Norvig《Teach Yourself Programming in Ten Years》 之简体中文译稿


为什么人人都这么匆忙?

当你走进任何一家书店,你总会看到一本《24 小时学会 Java》,以及无数本将不同时间(从几小时到几天)与技能(C、SQL、Ruby、算法等等)排列组合所得到类似标题的书籍。使用亚马逊的高级搜索来寻找 2000 年后出版的标题含有「小时」、「学会」等字样 的书籍,你能找到 512 本这样的书。这其中最火的十本里有九本都与编程有关,剩下一本是关于记账的。把「小时」换成「天」,或者把「学会」换成「掌握」来重新搜索,也能得到类似的结果。

由此可以得出一个结论,要么大家都非常匆忙地学习编程,要么编程本身比其他技能要容易掌握得多。Felleisen 等人在他们所著的《如何设计程序》 1中提到「差劲的编程是容易的,就算是木头脑袋的白痴也能在 21 天内学会它」,表达了对这一趋势的认同。漫画 The Abstruse2 Goose 也表达了同感

我们分析一下《24 小时学会 C++》 3这种标题是代表什么意思:

  • 24小时:很遗憾,这点时间不够,见下节
  • 学会:编写数个有意义的程序,并从其中的成败里学到东西;抑或是与一位有经验的程序员共事,了解了熟悉 C++ 的语言环境是一种什么体验。别想了,这些事情不可能在 24 小时内完成。总之,这么短的时间内你学不了什么东西。所以这本书只能涉及到浮于表面的熟练,而非深层次的理解。如 Alexander Pope 所说:「一知半解是件危险事」。
  • C++:24 小时内你或许可以学到一些 C++ 的语法(前提是你已经会了另一门编程语言),但是你恐怕无法学懂使用这门语言的方法。简而言之,假设你是一名 Basic 程序员,你可以学会用 Basic 的风格写出 C++ 的语法,但是你学不到 C++ 真正擅长(或者不擅长)的地方。那么,这有什么意义呢?Alan Perlis 曾经说过:「不会对你的编程思维产生影响的编程语言不值得学习」。当然,也不排除有这种可能性:为了完成某一项工作,你被迫要学一点点 C++(也许更可能是 JavaScript 或者 Processing)来与现有的工具进行交互。然而这种情况下你就不是在学习编程,而是在学习完成这项工作而已。

十年学会编程

研究人员们(Bloom(1985) , Bryan & Harter (1899) , Hayes (1989) , Chase & Simon (1973) 4)已经证实,一个人差不多需要十年的时间才能在一个领域内达到专精的水平,成为行家。这些领域包括但不限于国际象棋、编曲、发电报、绘画、钢琴演奏、游泳、网球、神经心理学研究以及拓扑学。秘诀就是——刻意练习——不仅仅是重复,而是用稍微超出自己现有能力的任务来挑战自己,并在尝试的过程中以及事后分析自己的表现,以及纠正犯过的错,然后再不断重复这个过程。这条路似乎并没有真正的捷径可走:就连在四岁时被认为是音乐神童的莫扎特,也是在十三年之后才谱出世界级的乐谱。换个类型来说,披头士在 1964 年通过一系列热门歌曲以及上了《埃德·沙利文秀》而在荧幕上突然走红,然而他们从 1957 年开始就已经在利物浦和汉堡的小俱乐部里表演了。尽管他们早些时候就已经赢得了大众的喜爱,但是那张让他们首次获得真正意义上的成功的专辑《佩珀军士》也是到了 1967 年才发行。

Malcolm Gladwell 将这个观念做了通俗化处理,只是他更聚焦于「一万小时」,而非「十年」。Henri Cartier-Bresson(1908-2004)也有着另一套衡量标准:「你最差的照片是你照的头一万张」(他没意料到有数码相机这个东西,有些人一周就能照一万张)。真正的行家也许需要一辈子:Samuel Johnson(1709-1784)说过「在任何一个部门做到卓越都需要一生的努力,不能付出比一辈子更小的代价来交换卓越」。乔叟(1340-1400)也抱怨过:「人生太短,学路太长」。希波克拉底(约公元前 400 年)的一句名言「艺长,寿短」,出自「艺术长,寿命短,机会稍纵即逝,试验充满诡谲,事事皆难断」。当然,最终答案肯定不是一个确切的数字:假设所有的技能(比如编程、国际象棋、跳棋、演奏),或者所有人都需要完全相同的时间,来(被)掌握,这并不符合常理。如 K. Anders Ericsson [译注3] 教授所说:「在绝大多数领域,就算是最具有天赋的人也需要花费巨量的时间才能达到最高的水准。一万小时这个数只是给人一个概念,它代表的是,就算与生俱来就已经最具有天赋的那个人也需要年复一年日复一日地每周练习十到二十个小时,才能达到顶级的高度。」

所以,你想成为一名程序员

想要在编程领域获得成功,这是我给出的秘诀:

  • 培养编程的兴趣并乐在其中,确保它能足够有趣以至于能让你奉献十年/一万小时的光阴。
  • 动手。最好的学习方法是学以致用(Learning by Doing) 。更准切地说,「一个人在某个领域内的顶级水准,并不是随着经验的增长自动得来的。就算是一个经验已经很丰富的人,如果刻意付出努力来提升自己,他/她的水准仍然可以得到提升。」(第 366 页) 1,而且「最有效的学习需要一项明确的任务,并需要针对个人情况调整到合适的难度,提供详尽的反馈,以及重复和改错的机会」(第 20-21 页)。这本书《Cognition in Practice》 也是这个观点的一个有趣的参考。
  • 与其他程序员交谈,阅读其他程序。这比任何书或者培训课程都重要。
  • 如果你愿意,用四年的时间去大学进修(或者花更多时间进入研究生院深造)。这将让你接触到那些需要认证的工作,以及加深对该领域了解。但是,如果你不想上学,你同样能够(付出努力)来独自或者通过工作获得类似的经验。不管怎么说,只从书本中学习是不够的。《The New Hacker’s Dictionary》的作者 Eric Raymond 曾说过:「如果学习笔刷和颜料不能让人成为杰出的画家,那么计算机科学教育也并不能令人成为杰出的程序员」。我雇过最优秀的程序员中,其中一个人只有高中文凭;他产出过许多伟大的软件 ,拥有他自己的新闻小组 ,并且通过股票期权赚到了一笔能买下一家属于他自己的夜总会 的钱。
  • 与其他程序员一起参与项目;在一些项目里成为拔尖的程序员,并在其他的项目里垫底。当你拔尖时,你能磨练你领导项目的能力,并用你的远见鼓舞人心。当你垫底时,你可以学习大师们的所作所为,也可以了解他们不喜欢干什么(因为他们会强迫你替他们做这些事情)。
  • 在其他程序员之后参与项目;理解别人所写的程序,看看怎么才能在原程序员不在场时理解并修复它;想想你可以把程序设计成什么样才能让在你之后的其他人维护它时更轻松。
  • 学习起码半打(六门5编程语言。其中一门强调类的抽象(如 Java 或者 C++),一门强调函数的抽象(如 Lisp 或者 ML 或者 Haskell),一门支持语法抽象(如 Lisp),一门支持声明式制定规范(如 Prolog 或者 C++ 模板),一门强调并行计算(如 Clojure 或者 Go)。
  • 切记,「计算机科学」的名字中有一个「计算机」。了解你的电脑需要花多久去执行一个指令,从内存中取出一个单词(分为缓存是否命中两种情况),从磁盘读取相邻的单词,以及在磁盘上寻找新的位置。(答案在此
  • 参与一门语言的标准化工作。可以是 ANSI C++ 委员会,也可以是你决定自己的本地代码风格是两个还是四个空格锁进。不管用哪种方式,你都能了解到别人喜欢一门语言的什么特质,以及他们喜欢的程度,甚至他们为什么喜欢。
  • 具备可以尽快脱离语言标准化工作的悟性6

考虑到这一切,是否仅靠学习书本就能走到更远的地方,还是得打一个问号。在我第一个孩子出生之前,我读过所有教人如何做的书籍,却还是觉得自己是一个毫无头绪的新手。三十个月后,我第二个孩子出生了,我有回到书本去寻找慰藉吗?没有,相反,我更依赖于我的个人经验。结果发现,这对我来说要比那些专家们写的上千页的文字更有用,更能令我安心。

Fred Brooks 在他的文章《没有银弹》 中提出了寻找优秀软件设计者的三个步骤:

  1. 系统性地识别出顶尖的设计者们,愈早愈好
  2. 指派一名职业导师负责有潜力的人才的发展,并一丝不苟地保存好职业档案
  3. 为成长中设计师们提供交流与相互促进的环境

作为以上计划的前提,部分人应该已经具有了成为好的设计师所必须的品质;而剩下要做的只是把他们哄好。Alan Perlis 用更简明扼要的方式表达过同样的意思:「每个人都能学会要雕刻什么东西,而米开朗基罗则必须学会不去雕塑什么。优秀的程序员也是如此」。Perlis 的意思是说,伟大的人们拥有超出他们修为的内在品质;然而这些品质却从何而来?是与生俱来的吗,还是通过勤奋而逐渐获得?就像 Auguste Gusteau(《料理鼠王》中虚构的厨师角色)说过:「人人都可以烹饪,但只有无畏之人才能做得出色。」我更愿意把它看作是把自己一生大部分时间奉献给刻意练习这件事本身的意愿,但也许无畏是概括它的一种方式。又或者,如 Gusteau 的批评者 Anton Ego 所说:「不是任何人都能成为优秀的艺术家,但是一位优秀的艺术家可以来自任何地方。」

那么,就去买那本 Java/Ruby/Javascript/PHP 书吧,或许你会用上他的。只是,不论是 24 小时或者 21 天,这些时间都不足以让你改变你的生活或者提升你作为程序员的整体技能。何不考虑一下在 24 个月内通过努力来稳步提升自己?这样的话,你就已经准备开始扬帆远航了……



参考资料

    Bloom, Benjamin (ed.) Developing Talent in Young People , Ballantine, 1985.

    Brooks, Fred, No Silver Bullets , IEEE Computer, vol. 20, no. 4, 1987, p. 10-19.

    Bryan, W.L. & Harter, N. “Studies on the telegraphic language: The acquisition of a hierarchy of habits”7 Psychology Review, 1899, 8, 345-375

    Hayes, John R., Complete Problem Solver Lawrence Erlbaum, 1989.

    Chase, William G. & Simon, Herbert A. “Perception in Chess” Cognitive Psychology, 1973, 4, 55-81.

    Lave, Jean, Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life , Cambridge University Press, 1988.



Answers

一台典型的电脑上执行各类操作的大约时间:

执行典型的指令 1/1,000,000,000 秒 = 1 纳秒
从 L1 缓存中获取 0.5 纳秒
分支预判错误 5 纳秒
从 L1 缓存中获取 7 纳秒
互斥锁/解锁 25 纳秒
从主内存中获取 100 纳秒
在 1Gbps 的网路上发送 2KB 数据 20,000 纳秒
从内存中连续读取 1MB 250,000 纳秒
在磁盘上获取新的位置(查找) 8,000,000 纳秒
从磁盘中连续读取 1MB 20,000,000 纳秒
将数据包从美国发至欧洲并返回 150 毫秒 = 150,000,000 纳秒



附录:语言的选择

一些人对于他们该先学什么编程语言有疑惑;这没有一个唯一的答案,不过可以考虑一下这几点:

  • 问朋友。当你问我:「我应该用哪个操作系统,Windows、Unix 还是 Mac?」我的回答通常是:「你朋友用什么你就用什么。」你从你朋友身上所得到的帮助可以抵消掉任何操作系统以及编程语言之间内在的差异性。同时,不要忘了考虑你未来的那些朋友:当你继续学习,你会成为使用这门语言的程序员们交流社区中的一份子。这门语言的社区是日渐壮大还是已经式微,是否有相关书籍、网站、在线论坛能让你获得帮助,以及你是否喜欢这些论坛里的人。
  • 保持简单。像 C++ 和 Java 这类编程语言是针对专业开发人员所设计的,他们的设计者们都是一些专注于代码的运行时效率,并且经验丰富的程序员。所以,这些语言就顺理成章地囊括了针对这些应用场景所的复杂设计。而你关心的其实是学习编程本身,并非这些复杂设计;你需要的是一门新手也很容易去掌握和记忆的编程语言。
  • 游玩。让你选一种学习钢琴的方法,你会选哪个?一个是正常、有互动——每按下一枚琴键你都能听到一个乐音;另一个是「批量」模式——当你弹完一整篇乐章才能听到声音。很显然,互动的模式让钢琴的学习更简单,学编程也是如此。使用一门有互动模式的语言吧,并坚持下去。

结合以上几个标准,我推荐你从 Python 或者 Scheme 开始,作为你的第一份编程语言。Javascript 也是另一个选择,但它并没有针对初学者设计得很完美,推荐它是因为网上关于它的教程太多了,比如可汗学院的教程 。不过具体情况因人而异,也有其他不错的选择。如果你的年龄还是个位数,或许你会偏向于AliceSqueakBlockly (即使年纪稍大的学习者也同样可以乐在其中),重要的是选择然后开始行动。



附录:书籍和其他资源

一些人对于他们该从那些书或者网页里学习有疑惑;我重复一遍「仅仅靠书本学习是不够的」,不过我可以推荐下面这些:



注释

T. Capey 指出Complete Problem Solver 的亚马逊页面上的「购买此商品的顾客也同时购买」这一栏里出现了《21 天学会孟加拉语》和《学会语法与风格》,我猜大多数人查看了那本书的人都是来自这个页面。感谢 Ross Cohen 提供的关于希波克拉底的帮助。



  1. 原文部分链接已失效,已替换为 https://archive.org/ 的版本 ↩︎

  2. 原文将The Abstruse Goose错拼成了The Abtruse Goose,已做更正 ↩︎

  3. 原文部分链接带有商家推广链接,已移除 ↩︎

  4. 原文将 Chase & Simon 的顺序反转并拼错,导致原页面内的 named anchor 失效,本篇中修复 ↩︎

  5. 原文的当前版本只列了五类编程语言,但某些旧版本 中确实列举了六类 ↩︎

  6. 此处似乎也可译为意思几乎相反的「请根据自己的判断尽快启动语言标准化计划。」指「不要等到项目不得不标准化时才去制定标准」。感谢 V2EX 网友 @Aoang 的指正 ↩︎

  7. 原文为句号,无反引号 ↩︎

  8. 原文用作者名代指书籍,因中文无此使用习惯,此处直接用书名代替 ↩︎


此页面最后编辑于2022年10月13日 (星期四) 14:32。