十几年前的旧文,译一遍,冗长的部分有一定压缩

原文:Teach Yourself Programming in Ten Years

为什么大家都这么急功近利?

走进任何一家书店,你会看到《Java 24 小时速成》以及诸如此类的各种 xx 小时、xx 天 C、SQL、Ruby、算法速成手册。在 Amazon 上搜索 【title:teach, yourself, hours, since:2000】,能找到 512 本这样的书。前 10 个里有 9 个是讲编程的(另一个是讲会计的)。把 【teach yourself】换成【learn】,或者把【hours】换成【days】,也会得到类似的搜索结果。

这说明,要么是人们学习编程的心态非常急躁,要么就是编程学起来轻而易举。Felleisen 等人在 《How to Design Programs》中也提到“糟糕的编程方式很容易学会。傻瓜在 21 天里就能学会,即使他们之前完全是小白。” 在 Abtruse Goose 的漫画里也有类似的调侃 ⬇️。

我们来分析一下《Teach Yourself C++ in 24 Hours》到底表达了什么:

  • Teach Yourself:只有 24 小时的话,没有时间去写几个重要的程序,并从程序的成功和失败中进行学习。没有时间和资深程序员一起工作,理解如何在 C++ 环境中生存。简而言之,没有时间去学习很多东西。这样的书只是带你进行蜻蜓点水式的学习,而非深入理解。正如 Alexander Pope 所言:半瓶醋很危险⚠️。
  • C++:在 24 小时内,可能可以掌握 C++ 的一些语法(如果你本来就会另一门语言),但学不到很多如何使用 C++ 的内容。简而言之,如果你会 Basic 语言,可以使用 C++ 语法来编写 Basic 风格的程序,但学不到 C++ 的长处和短处。那么,核心要点是什么?Alan Perlis 说过:”一门语言,如果没有影响你编程时的思考方式,就不值得学”。一种情形是你需要学一点儿 C++(或者类似的语言,比如 JavaScript、Processing)以对接现有工具来完成某个特定任务。但接下来你不会继续学习如何编程;你只是在学习如何完成这项任务。
  • in 24 Hours:不幸的是,24 小时不够,下一个环节会说。

用十年学习编程

研究(Bloom(1985)Bryan & Harter(1989)Hayes(1989)Simmon & Chase(1973))表明,大部分的领域需要十年左右才能成为专家,包括国际象棋、乐曲、电报、绘画、钢琴演奏、游泳、网球、神经心理学和拓扑学研究。关键就是刻意练习:并非单纯的重复,而是用一个刚超出当前能力的任务来挑战自己,尝试任务、分析自己在任务中和任务后的表现,修正错误,然后不断重复。没有捷径:即使强如莫扎特这样 4 岁就是音乐神童的天才,也花了 13 年才创作出世界级的作品。另一个案例,披头士乐队的爆火似乎是从 1964 年的 Ed Sullivan 的节目开始。但自 1957 年以来,他们一直在利物浦和汉堡的小俱乐部表演,虽然很早就有广泛的吸引力,但直到 1967 年才取得第一次关键性的成功。

Malcolm Gladwell 完善了这个观点,虽然关注点在 10000 小时,而非十年。Henri Cartier-Bresson (1908-2004) 提供了另一种衡量指标:“你的前 10000 张照片最糟糕。”(他并不反对使用数字相机,一些人可以在一周内就达成这个指标)。要达到顶尖水平可能需要一生时间:塞缪尔·约翰逊 (1709-1784) 说过“任何领域的卓越都需要用一生的努力才能实现,别想廉价得到。” 乔叟 (1340-1400) 也抱怨过 “the lyf so short, the craft so long to lerne.”。希波克拉底(c. 400BC)也有一句知名格言 “生命短暂,艺术长存“,这句话截取自“Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile“(拉丁语),翻译出来就是”生命短暂,艺术长存,机会稍纵即逝,实验不可靠,判断亦困难。“ 当然,没有一个数字可以作为终极答案:并不是所有的技能(编程、国际象棋、棋盘游戏、音乐)都需要花相同的时间来掌握,也不是所有人都需要花相同的时间才能掌握同一项技能。如 Prof. K. Anders Ericsson 所说,“在绝大部分领域,即使是最具天赋的人也需要花费可观的时间才能让技艺变得炉火纯青。” 1 万小时这个数字只是把 10 年替换为了一周 20 个小时,即使天赋异禀,技艺要想臻至顶尖,依然需要付出时间。

你想成为一名程序员

以下是我的一些诀窍:

  • 建立兴趣,做有意思的事。有趣的事才能让你持续投入十年/10000小时。
  • 编程吧。从实践中学习。通过刻意练习提高最高水准。最有效的学习方式是定义良好的任务、适中的难度、能提供有效反馈、能重复并改进。—— 《Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life》。
  • 和其他程序员交流;阅读其他代码。比读书和练习课程更重要。
  • 如果有意愿,就花 4 年上个大学,或者再读个研究生。因为有些工作需要相关资质,同时能让你对本领域有更深的理解。如果不喜欢学校,自己来也是可以的。“计算机学科教育并不能让你成为一个专家级程序员,就像光会画笔和颜料也不会让你自动成为画家”。
  • 和其他程序员合作开发项目。在一些项目里成为最佳程序员,在另一些里成为最差程序员。在前者时,测试自己领导项目的能力,并用自己的眼界来激励其他人;在后者时,学习项目领导者是怎么做的,以及其他程序员不喜欢做哪些事(因为这些事会划给你做)。
  • 在其他程序员后面研究项目。理解其他程序员写的代码。看看理解它需要什么,当原作者不在附近时试试自己修正它。思考当自己设计时,如何设计得让其他人便于维护。
  • 至少学会半打(6 个)编程语言。一个强调类抽象(如 Java、C++),一个强调函数抽象(如 Lisp、ML、Haskell),一个支持语法抽象(如 Lisp),一个支持声明式规范(如 Prolog、C++ template),一个强调并行(如 Clojure、Go)。
  • 记住“计算机科学”里有个“计算机”。了解计算机执行一条指令、从内存获取一个词(包括缓存命中和不命中的情况)、从磁盘连续读取词、在磁盘上寻址一个新位置等的时间。
  • 参与一项语言标准化工作。可以是 ANSI C++ 委员会,或者能够决定本地编程风格说 2 或者 4 个空格。无论如何,你学到了在一门语言里,其他人喜欢什么,他们喜欢的程度,甚至可能了解一点他们为什么会产生这种倾向。
  • 拥有尽快从语言标准化工作中抽身的灵敏嗅觉

综合以上这些,那么仅仅通过书本学习能走多远就是可疑的了。在第一个孩子出生前,我阅读了所有的 How To 书籍,但还是像个无助的新手。30 个月之后,当第二个孩子出生时,我是否需要再温习一遍这些书籍?并不是,而是依赖个人经验,这证明比专家写的数千页书籍对我更有用和可靠。

Fred Brooks 在他的文章 没有银弹 中给出了一个三步走计划来发现顶尖的设计人员:

  • 尽早以系统化的方式发掘出顶尖设计人员;
  • 派出职业咨询师负责候选人的发展和履历;
  • 为成长中的设计人员提供相互交流和激励的机会。

这是假定某些人具有成为顶尖设计人员的潜质;这项工作就是适当地诱使他们独自前行。Alan Perlis 有一个更简洁的版本:“每个人都可以接受指导,学习如何雕刻,只有米开朗基罗不应该接受指导,顶尖程序员亦如此”。Perlis 的意思是顶尖人才拥有某些超越人为训练的内在特质。但这些特质从何而来?天生的?或者他们通过勤奋发展出了这些特质?如 Auguste Gusteau(Ratatouille 中虚构的厨师)所说:“任何人都可以做料理,只有无畏者才能成为料理大师。” 我更愿意把它理解为一种投入人生一大块时间进行刻意练习的意愿。但也许无畏的形容恰如其分。或者,如 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/1,000,000,000 秒 = 1 纳秒
读取 L1 缓存0.5 纳秒
分支误判5 纳秒
读取 L2 缓存7 纳秒
互斥加锁/解锁25 纳秒
读取主存100 纳秒
在 1Gbps 带宽上发送 2K 字节20,000 纳秒
从内存顺序读取 1MB250,000 纳秒
读取新的磁盘位置8,000,000 纳秒
从磁盘顺序读取 1MB20,000,000 纳秒
从美国发送报文到欧洲并返回150 毫秒 = 150,000,000 纳秒

附录:选择语言

  • 使用朋友们使用的语言。
  • 语言要简单。像 C++ 和 Java,主要供大型团队有经验的程序员使用,关心的是性能和如何处理大型程序带来的复杂性,不适合新手用于学习。
  • 动起来。

基于以上内容,我建议第一门编程语言选择 PythonScheme。Javascript 也是一种选择,不是因为设计良好,而是网上教程多。重要的是动起来。


附录:书籍和其他资源

虽然仅从书本学习是不够的,我还是推荐一些:

分类: CODE