程序员必读经典长文:用十年时间自学编程
本文转自雷锋网,如需转载请至雷锋网官网申请授权。
相信很多做技术的同学都自学过,也看过「Teach Yourself Programming in Ten Years」这篇文章。虽然离初次发表已经好几年了,但所有试图自学编程的人都应该发自内心的同意它的说法(除去少数过时的具体技术部分)。直到今天,这篇经典的文章依然很有借鉴意义。以下是这篇文章的中文版。
为什么每个人都这么匆忙?
走进任何书店,你都会看到如何在 24 小时内自学 Java,同时你还可以看到很多在几天或几小时内学会 C、SQL、Ruby、算法等等的书籍。在亚马逊使用「title: teach, yourself, hours, since: 2000」进行高级搜索,我发现了 512 本这样的书。在排在前十名的书籍中,有九本是编程书籍,剩下一本是关于财务管理的。用「teach yourself」代替「learn」,或者用「day」代替「hours」产生的结果类似。
结论是,要么人们急于学习编程,要么编程比其他任何东西都更容易学习。Felleisen 等人在他们的书《How to Design Programs》中提到,「糟糕的编程很容易,即便是白痴都可以在 21 天内学会」时,请对这一观点表示赞同。
让我们来分析一下在 24 小时内学会 C++意味着什么:
-
自学:24 小时内,你将没有时间写几个重要的程序,并从成功和失败中吸取教训。你将没有时间和一个有经验的程序员一起工作,并理解在 C++环境中编程会是什么样子。简而言之,你将没有时间去学习多少东西。所以这本书只能说是肤浅的熟悉,而不是深刻的理解。正如 Alexander Pope 所说,只学会一点点点东西是危险的
-
C++:在 24 小时内,你也许能够学习 C++的一些语法(前提是你已经知道了另一种语言),但是你不能学到多少关于如何使用这门语言的知识。简而言之,如果你是一个基层的程序员,你可以学习用 C++语法编写 BASIC 程序,但是你不能学习到 C++真正的优缺点。那又有什么意义呢?Alan Perlis 曾经说过:「一种不影响你编程思维方式的语言,是不值得学习的。」有一种可能是,你必须学习一点 C++(或者是 JavaScript 之类的东西),因为你需要用现有的工具接口来完成特定的任务。但这种情况下,你不是在学习如何编程,而是在学习如何完成这项任务。
-
在 24 小时内:不幸的是,这根本不够,正如下面所说的那样。
用十年时间自学编程
很多研究人员发现,在各种领域要成为专家大约需要十年时间,这些领域包括国际象棋、音乐创作、电报、绘画、钢琴演奏、游泳、网球和科学研究、神经心理学和拓扑学等等。成功的关键是不断的实践:不只是一次又一次地做,而是每次都用一个超出你目前能力的任务挑战你自己,尝试去解决它,在做它的同时和之后分析你的表现,纠正错误,然后重复这个循环。人和事情都没有真正的捷径:即便对莫扎特来说也是如此。4 岁就被称为音乐天才的他,在开始创作世界级的音乐之前又花了 13 年时间来打磨自己。另一个例子是披头士乐队。披头士乐队似乎以一系列的热门歌曲和 1964 年在艾德沙利文秀上的亮相而一夜成名。但实际上自从 1957 年以来,他们一直在 Liverpool 和 Hamburg 的小酒吧里面演出,虽然很早以前他们就受到大众的欢迎,但他们第一次取得重大成功的专辑「Sgt. Peppers」是在 1967 年发布的。
Malcolm Gladwell 已经普及了这个想法,尽管他的观点是 10000 小时专注的努力,而不是 10 年。Henri Cartier-Bresson (1908-2004) 有一句名言:「你的前 10000 张照片是你最差的作品。」(他没有预料到使用数码相机,有些人可以在一周内就拍完 10000 张照片。)真正成为专家可能需要一辈子:Samuel Johnson(1709-1784)说:「成为任何领域的卓越人士都需要毕生的努力,投机取巧并不可行」。Chaucer (1340-1400) 抱怨说:「人生太短暂了,而知识是无穷的」。Hippocrates (约公元前 400 年) 因为那句名言「ars longa, vita brevis」而被人称颂,这句话的原文是「Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile」,意思是「生命很短暂,但是技艺却很高深,机遇转瞬即逝,探索难以捉摸,抉择困难重重」。
当然,没有一个数字可以作为最终的答案,假定所有的技能(如编程、下棋、跳棋和音乐演奏)都需要完全相同的时间来掌握,或者所有人都需要完全相同的时间是不合理的。正如 K. Anders Ericsson 教授所说,「在大多数领域,即使是最有才华的人也需要很多时间才能达到最高水平,这是非常值得注意的。10000 小时这个数字让你感觉到,我们说的是一周 10 到 20 个小时。」
你想成为一名程序员
以下是我的编程秘诀:
-
对编程感兴趣,因为兴趣而编程。请保持足够的兴趣,以便你愿意投入你的 10 年或者 10000 小时。
-
编码。最好的学习方式是实践。更严格地说,「在特定领域中,一个人的最高水平不是由于经验的积累自动获得的,而是经过深思熟虑的改进,经验丰富的人也可以提高水平。」,「最有效的学习需要有一个明确的任务,对特定的人来说难度适中,还要有信息反馈以及重复试错和纠正错误的机会。」「Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life」这本书正是这一观点的有趣参考。
-
与其他程序员交谈;阅读其他程序。这比任何书籍或培训课程都重要。
-
如果你愿意,可以在大学(或研究生院)呆四年。这将使你有机会获得一份需要证书的工作,让你对这个领域有更深的了解,但如果你不喜欢学校,你可以自学或在工作中获得类似的经验。无论如何,光靠书本知识是远远不够的。「The New Hacker's Dictionary」的作者 Eric Raymond 说:「计算机科学教育不能使任何人成为一个专业的程序员,就像学习刷子和颜料不可以使某人成为一个专业的画家一样。」我雇用过的最好的程序员之一只有高中学历,他开发了许多优秀的软件,拥有自己的团队,并且拥有足够买下一个夜店的股票期权。
-
与其他程序员一起做项目。在某些项目上你是最好的程序员,而在某些项目上你是最差的程序员。当你是最好的时候,你可以锻炼主导一个项目的能力,并用你的远见激励别人。当你是最坏的时候,你可以学习大师们做什么,观察他们不喜欢做什么(因为他们会让你为他们做自己不喜欢的事情)。
-
接手其他程序员的项目,理解别人写的程序。当原来的程序员不在时,学习需要怎样理解和修复程序。想想如何设计你的程序,让那些在你之后的人维护它们更容易些。
-
学习至少六种编程语言。包括一种强调类抽象的语言(如 Java 或 C++),它强调函数抽象的语言(如 Lisp 或 ML 或 Haskell),一种支持句法抽象的语言(如 Lisp),一种支持声明性规范的语言(如 Prolog 或 C++模板),一种强调并发性的语言(像 Clojure 或 Go)。
-
记住「computer science」中有一个「computer」。知道计算机执行一条指令、从内存中提取一个字符(有或没有缓存)、从磁盘中读取连续的字符以及在磁盘上寻找新的位置需要多长时间。
-
参与语言标准化工作。它可能是 ANSI C++委员会,也可以是决定你自己的本地编码风格是有 2 个或者 4 个空间缩进。无论哪种方式,你都可以了解到其他人对一种语言的喜好,他们的感受有多深,甚至可能了解他们的感受。
-
有很好的判断力,尽快适应语言的标准化
考虑到这一切,仅仅通过书本学习你能走多远是个值得怀疑的问题。在我的第一个孩子出生之前,我读完了所有的「How To」类型的书,但仍然觉得自己像个笨手笨脚的新手。30 个月后,当我的第二个孩子出生时,我重新学习了那些书本知识吗?不,相反,我依靠的是我的个人经验,这比专家们写的几千页书更有用,更让我放心。
Fred Brooks 在他的论文《No Silver Bullet》中指出了寻找优秀软件设计师的三个步骤:
-
尽早系统地发掘顶级程序员。
-
指派一名职业导师负责指导他,并谨慎对待履历。
-
为成长中的程序员提供相互交流和互相激励的机会。
这假设一些人已经具备成为一个伟大的程序师所必需的素质,那么你的工作就是适当地哄骗他们。Alan Perlis 的说法更加简洁:「每个人都可以学会雕刻,但 Michelangelo 必须学会如何不雕刻。对伟大的程序员来说也是如此。」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》. 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/100000000 秒,即 1 纳秒
-
从一级缓存中提取:0.5 纳秒
-
分支预测失误:5 纳秒
-
从二级缓存获取:7 纳秒
-
互斥锁/解锁:25 纳秒
-
从主存储器提取:100 纳秒
-
通过 1Gbps 网络发送 2K 字节:20000 纳秒
-
从内存中按顺序读取 1MB :250000 纳秒
-
从新磁盘位置(SEEK)获取:8000000 纳秒
-
从磁盘中按顺序读取 1MB:20000000 纳秒
-
将数据包发送到欧洲并返回:150 毫秒,即 150000000 纳秒
附:语言选择
有人会问,他们应该先学什么编程语言。这里没有标准答案,但请考虑以下几点:
-
参考你的朋友。当被问到「我应该使用什么操作系统,Windows、Unix 或 Mac?」我的回答通常是:「使用你的朋友使用的任何东西。」你从朋友那里学到的优势将抵消操作系统或编程语言之间的任何内在差异。还要考虑你未来的朋友:程序员社区的人,如果你继续的话,你将成为其中的一员。你所选择的语言有一个大的正在成长的群体还是一个小的正在消亡的群体?有书、网站和在线论坛可以得到答案吗?你喜欢那些论坛里的人吗?
-
简单实用。诸如 C++和 Java 这样的编程语言是由有经验的程序员团队设计的,这些程序员关心他们代码的运行时效率。因此,为了应对这些情况,这些语言有些地方是很复杂的。你关心的是学习编程。你不需要那么复杂。你需要的是一种语言,它对于新手程序员来说也可以可以很容易地学习和记忆。
-
互动。你更愿意用哪种方式学弹钢琴:普通的,互动的方式,你一按一个键就听到一个音符;或者「批量」模式,在这种模式下,你只在完成一整首歌后才听到音符?显然,互动模式使钢琴学习和更容易。对编程来说也是如此,坚持使用互动模式的语言并使用它。
考虑到这些标准,对于要学习的第一种编程语言我的建议是 Python 或 Scheme。另一个选择是 JavaScript,这不是因为它是为初学者精心设计的,而是因为它有很多在线教程,比如 Khan Academy 的教程。但每个人的情况都略有不同,还有一些其他的好选择。如果你还是隔小孩,你可能更喜欢 Alice 或 Squeak 或 Blockly(年长的学习者也可能喜欢这些)。这些都没关系,重要的是你要选择并开始。
附录:书籍和其他资源
有人问他们应该从哪些书和网页上学习。我再重复一遍:仅仅看书是不够的。但我可以推荐以下资源:
-
Scheme:「Structure and Interpretation of Computer Programs (Abelson & Sussman)」可能是计算机科学最好的导论书籍,它也确实将教授编程作为理解计算机科学的一种方式。你可以在网上看到关于这本书的讲座视频,以及完整的文本。这本书读起来具有挑战性,将淘汰一些可能通过这种方法获得成功的人。
-
Scheme:「How to Design Programs (Felleisen et al.)」是关于在实践中如何以优雅和实用的方式设计程序的最佳书籍之一。
-
Python:「Python Programming: An Intro to CS (Zelle)」很好地介绍了如何使用 Python。
-
Python:Python.org 上有一些在线教程。
-
Oz:「Concepts, Techniques, and Models of Computer Programming (Van Roy & Haridi)」被一些人视为 Abelson 和 Sussman 的现代继承人。读这本书会让你理解编程思想,它的涵盖范围比 Abelson 和 Sussman 更广泛,同时可能更容易阅读和理解。它使用的语言是 Oz,这种语言并不广为人知,但它却是学习其他语言的基础。
备注