Teach Yourself Programming in Ten Years

Posted by Morgan on March 15, 2018

推荐一篇编程届的经典文章『十年学会编程』,希望给你不一样的启发。

文章原名为「Teach Yourself Programming in Ten Years」,本文为译文,由于微信不允许外部链接,想看原文的朋友可以点击尾部左下方阅读原文来跳转文中链接。

文章作者 Peter Norvig目前就职于 Google,担任研发主管(Director of Research)一职,之前他曾指导谷歌的核心搜索算法小组,他还是 AI 领域内领先教科书「人工智能:一种现代方法」一书的合作者,同时还是 Udacity 的人工智能课程的合作教师,其中学生超过1w6千名。这位大佬同时还是 AAAIACM,以及加州科学院和美国艺术与科学学院的一员。附上一张大佬的照片,大家膜拜一下😁。

image-20190315204533849

正文开始

为何人人如此着急?

随意步入一家书店,铺天盖地的「24小时搞定 Java 编程」,还有琳琅满目的包括但不限于 C,SQL,Ruby,算法等书籍,它们同样都承诺在几天,甚至几小时以内让你学会相关技术。我在亚马逊网站高级搜索输入几个关键词查找:自学,小时,从2000年以后,然后发现了512种类似书籍。前十名中,有9本是编程书籍(另一本是关于记账的)。将自学替换为学习或者将小时替换为,同样会得到类似的结果。

我们从上面可以得出什么结论呢?结论就是要么人们普遍急于学习编程,要么编程在某种程度上比其他任何东西更容易学习。Felleisen et al.在他们的著作「如何设计程序」中明确指出了这种趋势,并且评论说:“垃圾的程序非常容易,傻子也能在21天学会,即使他们天生就是个白痴。” The Abtruse Goose 漫画同样也有他们的看法。(笔者注:是一个漫画网站,下图就是网站的关于这个观点的漫画)

image-20190316231756024

让我们看一下「24小时学会 C++」这种速成教材实际上意味着什么:

  • 学会:24小时内你不会有时间写任何有意义的程序,就更别说从编程中获得经验和教训了。你甚至都没有和有经验的程序员一起工作交流,也就别提在真实的 C++环境中工作是什么感觉了。总之,你不会有时间收获太多。所以这种书籍最多也就让你有个粗浅的印象,但是绝对不可能有深入的理解。就像亚历山大教皇说的那样,“浅尝辄止是很危险的”。
  • C++:如果你有其他编程语言的基础,24小时你可能学会 C++的语法,但是(凡事就怕但是)你还是无法理解如何使用该语言。简而言之,如果你之前是一个 Basic 程序员,你可能变成一个会使用 C++语法写出 Basic 风格的语言,不过这样是无法发挥出 C++本身语言的优势的。那这有什么意义呢?Alan Perlis(笔者注:另外一位大佬,链接是他写的编程警句文章, 值得谨记,后面有机会翻译出来给大家)曾经说过:“一个无法改变你思维方式的编程语言是不值得学习的。”另一种可能性是,你可以只学一点点C++知识(类似的,或者一点点JavaScript),然后就可以利用现有的工具制作应用接口,完成特定的编程任务了。但是这样的行为并不意味着你“会”编程了,你只是会使用这个工具完成任务而已。
  • 24小时:很不幸,24小时是远远不够的,往下看你就知道了。

十年学会编程

研究人员(Bloom(1985)Byran & Harter(1899, 见文后参考书目)Hayes(1989)Simmon & Chase(1973))的一系列调查研究显示,在各个领域内,要想获得专业级别的水平,大约需要10年时间的努力。参与此项调查的领域包括:国际象棋,作曲,发报,绘画,钢琴演奏,游泳,网球等。科学家们从神经心理学和拓扑学的角度对这些领域进行研究,并得出结论。若要在某一领域内达到专家级的水平,其关键在于“审慎地重复”,也就是说,并非是机械地,一遍又一遍地练习,而是要不断地挑战自我,试图超越自身当前的水平,通过不断的尝试挑战,并在尝试的过程中和尝试之后对自身的表现进行分析和总结,吸取经验,纠正之前犯过的各种错误。把这一“审慎”的过程不断重复,才能取得成功。

所谓的“捷径”是不存在的,即使对于莫扎特来说,也没有。尽管他4岁就开始作曲,但也花了13多年的时间,才写出了世界级的作品。同样另外一个例子,甲壳虫乐队(The Beatles),他们似乎在1964年凭借一系列热门单曲和其在艾德沙利文秀(The Ed Sullivan show)上的演出一炮而红,但是你也许不知道,他们早在1957年就在利物浦和汉堡两地进行小规模演出了,而在此之前的非正式演出更是不计其数。甲壳虫乐队的主要成名曲《Sgt. Peppers》,则是1967年才发行的。

Malcolm Gladwell推广了这一想法,尽管他关注的是10000小时,而不是10年。Henri Cartier-Bresson(1908-2004) *曾经说过,“你拍摄的前10000张照片都是垃圾。”(他没想到数码相机会让一些人在一周内达到这个标准。)真正的专业知识可能要一生。Samuel Johnson(1709-1784) 曾说过,在任何一个领域要想做到极好,势必穷尽一生的精力,否则根本无法企及。Chaucer(1340-1400)* 也发出过“生命如此短暂,技艺如此高深”的感叹。Hippocrates(c.400BC) 因写下了如下的句子而被人称颂:“ars longa, vita brevis”,该句是来自于一个更长的引用:”Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile”, 这段话翻译成英语就是:“生命很短暂,但是技艺却很高深,机遇转瞬即逝,探索难以捉摸,抉择困难重重”。

当然,没有最终答案,假设所有的技能(例如编程,国际象棋,跳棋和作曲)对所有人来说,需要完全掌握都需要相同的学习时间,这种说法是不合理的。正如 K.Anders Ericsson 所说,在大多数领域,即使最有才能的人想要达到技艺的最高水平,仍然需要10000小时左右的时间。

你想当程序员吗?

下面是我编程成功的秘诀:

  • 沉醉于编程,编程是为了兴趣。保持这种充满兴趣的感觉,以便于你能将其投入到你的10年/10000小时的编程时间中。
  • 程序。最好的学习方法就是“在实践中学习”。更技术一些地说:“一个人在某个专业领域方面能够达到最高水平,并不是因为这个人经验增长了以后而自动获得的,而是这个人为了进步所做出了专门的努力之后产生的结果。”(p. 366)“最有效的学习包括如下几个要素:明确并且难度适当的任务,适应学习者个人情况,及时的信息反馈,有重新开始和改正错误的机会)(p. 20-21) 「Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life」 这本书提供了上述有趣的观点。
  • 同其他程序员交流,多阅读其他人写的程序。这些远比你看书或者上培训班重要
  • 如果你愿意的话,就选择去读一个计算机科学专业吧(当然你还可以去念这个专业的研究生)。这样能给你机会找到一些需要计算机学位认证的工作,也会让你对这个行业有更深的理解。不过,如果你不是上学的料,那么你可以(当然需要有足够的毅力)靠自己学习,或者通过工作来积累经验。无论你采用哪种途径,光依靠书本是远远不够的。“如果说仅仅靠学习油画和调色技术无法创造出顶尖的画家的话,那么光学习计算机科学课程更不能造就顶尖的程序员。”,Eric Raymond 这样说过,他著有「新黑客字典」一书。我所聘用过的最好的程序员仅仅只有高中文凭; 他写了很多伟大的软件(XEmacs、Mozilla),他有他自己的新闻组,并且通过股权赚够了钱,还开了家属于自己的夜店
  • 与其他程序员一起做项目。在某些项目中要尽量做到最好,在某些项目中却别做那么好。当你是最好的时候,你的领导能力就会得到锻炼,并激发你高瞻远瞩的视野。当你做得不好的时候,你就能知道你的领导怎么做事,以及他们不喜欢哪些事(因为领导总是把那些他们不爱做的杂事丢给他们认为不得力的人去做)
  • 尝试跟随其他程序员一起做项目。尝试去理解其他人所写的代码。看看如果你无法找到代码的作者本人的情况下,理解和修正他写的代码需要花费什么样的代价。同时也思考,如何规划你自己的程序代码,让它们更容易被其他人理解和维护。
  • 至少学习半打编程语言。包括一种支持类抽象的语言(例如Java或者C++),一种支持函数抽象的语言(例如Lisp或者ML或者 Haskell),一种支持语法抽象的语言(例如Lisp),一种支持声明式编程的语言(例如Prolog或者C++模板),一种支持并发编程的语言(例如Clojure 或者 Go)。
  • 牢记“计算机科学”中包含着“计算机”这个词。了解计算机需要花多长的时间执行一条指令,花多长时间从内存中获取一个字(word)(包括缓存命中和不命中两种情况),如果连续从磁盘中获取数据,时间消耗如何?以及需要花多少时间才能再磁盘上定位一个新的位置?(答案见文末)
  • 尽量参与语言的标准化过程。往大了说,你可以试着加入ANSI C++委员会这样的专业组织,往小了讲,你也可以从自己的代码规范入手,限定代码缩进是需要2个空格宽还是4个空格宽。无论采用哪种方式,你都需要了解其他人对于语言的喜好,以及他们的喜好的程度,甚至你要知道他们为什么产生这样的喜好的原因。
  • 有良好的意识,能尽快适应语言标准化的成果。

要掌握上面所说的所有内容,光靠看书学习应该是很难做到的。当我的第一个孩子出生的时候,我几乎阅读了市面上所有的《如何…》指南书籍,但是我读完了以后还是觉得自己是个菜鸟。30个月以后,我的第二个孩子快出生时,我难道还要做一个书虫么?不!相反,我此时更依赖我的个人经验,这些经验相比于那些上千页的书籍,则更加有效和让我放心。

Fred Brooks 所著的著名的论文[「No Silver Bullets 没有银弹」](https://en.wikipedia.org/wiki/No_Silver_Bullet)里向我们揭示了发现和培养软件设计人才的三步骤:

1.有组织地辨认顶尖的软件设计人才,越早越好

2.安排一个职业导师,为其职业前景指点迷津,并谨慎对待自己的职业履历

3.为成长中的设计师们提供机会,让他们能够互相激发促进。

即使一部分人已经具备了成为优秀软件设计人员的潜质,也需要经历工作的慢慢琢磨,方可展现才华。Alan Perlis则说得更加直接:“任何人都可以被‘教’成一个雕塑匠,但米开朗基罗则被‘教’如何不要成为一个雕塑匠,因为他要做的是雕塑大师,。这个道理放到编程大师身上同样管用。” Perlis 认为,伟大的软件开发人员都有一种内在的特质,这种特质往往比他们所接受的训练更重要。但是这些特质是从哪里来的呢?是与生俱来的?还是通过后天勤奋而来?正如Auguste Gusteau(动画电影『料理鼠王』里的幻象大厨)所说,“谁都能做饭,但只有那些无所畏惧的人才能成为大厨!”我很情愿地说,将你生命中的大部分时间花在审慎地练习和提高上,这很重要!但是“无所畏惧”的精神,才是将促使这些练习成果凝聚成形的途径。或者,就像是「料理鼠王」里那个与 Gusteau 作对的刻薄的美食评论家Anton Ego说的那样:“不是任何人都能成为伟大的艺术家,不过,伟大的艺术家在成名前可能是任何人。”

结语

所以尽管去书店大买Java/Ruby/Javascript/PHP书籍吧;你也许会发现他们真的挺管用。但是这样做不会改变你的人生,也不会让你在整体经验上有什么提高。24小时,几天,几周,做一个真正的程序员?光靠读书可读不出来。你尝试过连续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. 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.

答案

典型PC系统各种操作指令的大概时间

执行基本命令 1/1,000,000,000 sec = 1 nanosec
从一级缓存中读取数据 0.5 nanosec
分支误预测 5 nanosec
从二级缓存中读取数据 7 nanosec
互斥加锁/解锁 25 nanosec
从主内存中获取数据 100 nanosec
通过1G bps 的网络发送2K 字节 20,000 nanosec
从内存中顺序读取1MB数据 250,000 nanosec
从新的磁盘位置获取数据(随机读取) 8,000,000 nanosec
从磁盘中顺序读取1MB 数据 20,000,000 nanosec
从美国发送一个报文包到欧洲再返回 150 milliseconds = 150,000,000 nanosec

附录:如何选择语言

很多人曾经问过我,他们应该选择什么编程语言作为入门之用?我想这个问题很难有一个确切的答案,但是下面几点可以用来作为选择的参考。

  • 随大流。当被问到“我应该使用什么系统呢?Windows, Unix还是Mac?”,我的回答通常是:“看你的朋友们用什么你就用什么。”这么做的好处是,有了你朋友的帮助,你就能有效地回避操作系统固有的一些差异,对于选择编程语言来说,也是同样道理。同时,你还要有点儿战略眼光:如果选择了一种编程语言,并成为其编程社区的一员,那么你选择的语言和社区是正在不断壮大?还是奄奄一息?如果你有编程方面的问题,能不能从相关的书籍,网站以及在线论坛中得到解答?你是不是跟论坛里的人合得来?这些都是要考虑的。
  • 简单实用。诸如C++以及Java这样的编程语言都是非常专业的开发语言,适用于有经验的大型团队进行开发,需要时常考虑代码的运行效率。所以,这类的编程语言就适合于那样(复杂)的编程环境。如果你是一个初学者,那么就不要搞那么复杂。你所需要的是一种简单易学的编程语言,你靠你自己就可以搞定的语言。
  • 交互。给你两种选择去学钢琴:第一种,常规做法,也是互动的做法,也就是你每敲一下琴键就能听到琴音;第二种,批量模式,等你把所有该按的琴键都按了一遍,然后再一次性放给你听。你选择哪一个呢?显然,交互式的方式对于钢琴学习来说更容易,对于编程学习也是如此。那么就坚持使用交互式模式学习编程吧。

基于上述的观点,我所推荐的编程入门语言应该是Phyton或者Scheme, 另外一个选择就是 Javascript, 并不是它对初学者很友好,而是因为网上有很多的在线教程以及解答,例如Khan Academy’s tutorial. 但是你自身的环境是非常复杂多变的,所以你们也许会其他更好的选择。如果你的年龄还不到两位数,那么你们应该考虑Alice语言或者Squeak语言或者 Blockly(很多成年的初学者也认为他们很有趣)。当然,做出选择并开始行动,这个最重要。

附录:书籍和其他资源

备注:

T. Capey指出,Amazon网页上那个Complete Problem Solver页面把『21天搞定孟加拉语』以及『21天学会语法』这两本书移到了“购买此书的用户还购买过这些产品”这个区域内。我估计大部分人就是从这个区域看到这本书的。感谢Ross Cohen的帮助。