为何每个人都如此匆忙?
走进任意一家书店, 你会看到 如何在 24 小时内自学 Java , 以及在几天或几小时内教授 C,SQL,Ruby, 算法等无穷无尽的书籍变种. 亚马逊高级搜索以下关键词[title: teach, yourself, hours, since: 2000 http://www.amazon.com/gp/search/ref=sr_adv_b/?search-alias=stripbooks&unfiltered=1&field-keywords=&field-author=&field-title=teach+yourself+hours&field-isbn=&field-publisher=&node=&field-p_n_condition-type=&field-feature_browse-bin=&field-subject=&field-language=&field-dateop=After&field-datemod=&field-dateyear=2000&sort=relevanceexprank&Adv-Srch-Books-Submit.x=16&Adv-Srch-Books-Submit.y=5 , 会发现有 512 本这样的书. 在前十名中, 有九本是编程书籍(另一本是关于记账的). 类似的结果来自于将 "teach yourself" 替换为 "learn" 或将 "hours" 替换为 "days".
结论是, 要么人们都急于学习编程, 要么编程在某种程度上比其他任何东西都更容易学习. Felleisen 等人在他们的 "How to Design Programs http://www.ccs.neu.edu/home/matthias/HtDP2e/index.html" 一书中对此趋势表示赞同,"糟糕的编程很容易. 即使是傻瓜, 人们也可以在 21 天内学会它."Abtruse Goose 漫画对此也有他们的 理解 http://abstrusegoose.com/249 .
我们来分析一下诸如 24 小时自学 C++ http://www.amazon.com/Sams-Teach-Yourself-Hours-5th/dp/0672333317/ref=sr_1_6?s=books&ie=UTF8&qid=1412708443&sr=1-6&keywords=learn+c%2B%2B+days 这样的标题意味着什么:
自学: 24 小时不足以写一些有意义的程序, 更不用说从中汲取经验或者教训. 这个时间也不足以跟有经验的程序员一起工作并理解处于 C++ 的环境是一种怎样的感受. 简单地说, 就是因为时间不足, 学不到多少东西. 因此, 这种书只会谈及肤浅的表面, 不会带来深刻的理解. 正如 Alexander Pope 所说, 学点皮毛是件很危险的事情.
C++:24 小时内你可能会学到一些 C++ 语法(如果你已经会其它语言的话), 但是不能学到如何应用这门语言. 简而言之, 如果你是一名 Basic 程序员, 你可以学会用 C++ 语法以 Basic 风格编写程序, 但你不会了解 C++ 为什么好(或坏). 所以这有什么意义呢? Alan Perlis http://www-pu.informatik.uni-tuebingen.de/users/klaeren/epigrams.html 曾说:"如果一门语言不能引发你对编程的思考, 就不值得去学." 一个可能的观点是, 你必须学一点 C++(或者更可能是像 JavaScript 或 Processing 的语言), 因为你可能需要与现有工具进行交互以完成某项特定的任务. 但是这样一来, 你学的不是如何编程, 而是如何完成任务.
24 小时: 很不幸, 这是远远不够的, 下面我们将详述.
十年内自学编程
研究员 ( Bloom (1985) http://www.amazon.com/exec/obidos/ASIN/034531509X/ , Bryan & Harter (1899) http://norvig.com/21-days.html#bh , Hayes (1989) http://www.amazon.com/exec/obidos/ASIN/0805803092 , Simmon & Chase (1973) http://norvig.com/21-days.html#sc ) 已经证实, 在包括国际象棋, 音乐制作, 电报操作, 绘画, 钢琴表演, 游泳, 羽毛球, 神经心理学以及拓扑研究在内的各种领域中构建专业知识体系需要大约十年的时间. 关键是审慎的实践: 不仅仅是一次又一次地重复, 而是用一项超出你现有能力的任务来挑战自己, 尝试它, 分析你在执行它时的表现, 并纠正任何错误. 然后重复一遍再重复一遍. 似乎没有真正的捷径: 即使莫扎特 4 岁时是一位音乐神童, 他在开始制作世界级音乐之前还花了 13 年时间. 在另一时代中, 甲壳虫乐队似乎在一系列 #1 热门歌曲和 1964 年的 Ed Sullivan 现场秀中亮相. 但自 1957 年以来他们一直在利物浦和 Hamburg 小型俱乐部演唱, 虽然他们有早期粉丝, 但他们的第一次重大成功, Sgt. Peppers , 于 1967 年发布.
马尔科姆. 格拉德维尔推广了这一思想, 尽管他更关注 10,000 个小时而不是 10 年. 亨利. 卡蒂埃 - 布列松则有其他的标准:"最糟糕的是你前 10,000 张照片"(他没想到数码相机的出现致使某些人在一周之内就能达成目标)."真正的专业知识需要你用一生来了解", 塞缪尔. 约翰逊说到,"任何学科的卓越成就依靠毕生劳作, 靠金钱买不来." 乔叟则抱怨道:"生之有崖, 学而无涯." 希波克拉底因这条摘要 "ars longa, vita brevis" 而著名, 这是引文 "Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile" 的一部分, 在英语中则说 "Life is short, [the] craft long, opportunity fleeting, experiment treacherous, judgment difficult."(译者注: 生命短暂, 技艺长远, 机会易逝, 实验诡谲, 判断困难的意思, 希波克拉底用拉丁文写的)当然, 答案不唯一: 假设所有技能 (例如: 编程, 下象棋, 玩跳棋还有演奏音乐) 都需要完全相同的时间掌握那是不合理的, 并非所有人都花费相同时间. 像安德斯. 爱立信教授所言,"在大多数领域中, 才华横溢者也需时间成就不朽伟业. 10,000 这个数给我们每周仅工作 10 至 20 个小时, 有些人辩称大天才还需要达到最高水准."
所以你想成为一名程序员
这是我在编程方面获得成功的秘诀:
对编程 感兴趣 , 因为它很有趣而完成一些编程工作. 确保它能对你保持足够的兴趣, 以便你愿意在未来投入十年 / 10,000 小时.
编码. 最好的学习方式是 边学边做 http://www.engines4ed.org/hyperbook/nodes/NODE-120-pg.html . 更具技术性地描述下,"特定领域中个人的最高绩效水平并不是作为增加经验的功能而自动实现的, 但即使是经验丰富的个体因刻意努力改进是可以提高绩效水平的."( p. 366 http://www2.umassd.edu/swpi/DesignInCS/expertise.html )和 "最有效的学习需要一个定义明确的任务, 对特定的个体有适当的难度级别, 信息反馈, 以及重复和纠正错误的机会." (第 20-21 页) "实践中的认知: 日常生活中的思想, 数学和文化" ( Cognition in Practice http://www.amazon.com/exec/obidos/ASIN/0521357349 )一书中是对这一观点的一个有趣的引用.
跟其他程序员 交谈 , 或阅读其他人的程序. 这比其他任何书籍或课程都管用.
如果对学校有兴趣, 你可以读 4 年 大学 (或再读几年研究生). 这样你就可以找那些有学历门槛的工作, 而且学校可以让你对这个领域有更深的认识. 当然, 如果你不喜欢学校, 那么也可以通过自学或工作来达到相同的效果. 无论如何, 单单看书肯定是不够的."单凭计算机课无法让一个人变成一个编程专家, 就像单纯研究刷子和颜料无法造就一个画家一样."新黑客字典的作者 Eric Raymond 这样说. 我曾经有个员工, 虽然只有高中学历, 但非常厉害, 写了很多很棒的软件, 还有自己的 新闻组 http://groups.google.com/groups?q=alt.fan.jwz&meta=site%3Dgroups , 甚至还靠股票期权买下了自己的 夜总会 http://en.wikipedia.org/wiki/DNA_Lounge .
跟其他程序员 一起做项目 . 在一些项目里, 你可能是最牛的; 在另一些项目里, 你可能是最弱的. 在那些你最牛的项目里, 你可以训练你的领导能力, 用你的眼界来激发大家. 在那些你最弱的项目里, 你可以学学那些大牛是怎么做的, 也可以学学那些大牛不想做的东西(因为大牛让你替他们做)
接手其他程序员的项目. 理解其他人写的程序. 看看理解和修复其他人的程序会有多难. 这样你就可以想想怎么优化自己的设计, 可以让别人接手时简单一些, 再简单一些.
至少要学那么六七门 编程语言 . 其中至少要有一门是强调类抽象的(比如 Java 和 C++), 一门是强调函数抽象的(比如 Lisp,ML 或 Haskell), 一门是支持语法抽象的(比如 Lisp), 一门是支持声明式规范的(比如 Prolog 和 C++ 模板), 一门是强调并行性的(比如 Clojure 和 Go).
记住,"计算机科学" 中是有一个 "计算机" 的. 你得知道你的计算机执行一条指令需要多久, 从内存取一个词需要多久(缓存命中要多久, 不命中要多久), 从磁盘读连续的字要多久, 磁盘寻道要多久.
加入到语言的 标准化 过程中. 大到加入 ANSI C++ 委员会, 小到确定你们公司里是用 2 个空格缩进还是 4 个空格缩进. 通过这些过程, 你可以了解其他人对语言里某些东西的喜好, 这种喜好到底有多深刻, 甚至为什么有这种喜好.
还要有尽快从语言标准化工作中 抽身而出 的决断力.
考虑到所有这些问题, 你可以通过书本学习到多少. 在我的第一个孩子出生之前, 我读了所有的 How To 书籍, 仍然感觉像一个无知的新手. 30 个月后, 当我的第二个孩子到来时, 我是否还要回到书本上进行复习? 不. 相反, 我依靠我的个人经验, 结果证明, 与专家撰写的数千页相比, 这对我来说更有用, 更让人放心.
弗雷德布鲁克斯在他的文章 No Silver Bullet http://en.wikipedia.org/wiki/No_Silver_Bullet 中确定了一个由三部分组成的计划来寻找优秀的软件设计师:
尽早系统地识别顶级设计师.
指派一名职业导师负责潜在客户的发展并谨慎地保留工作档案.
为成长中的设计师提供互动和互相激励的机会.
这里假设有些人已经拥有成为优秀设计师所需的品质; 任务就是要循循善诱之. Alan Perlis http://www-pu.informatik.uni-tuebingen.de/users/klaeren/epigrams.html 的表达更简洁:"每个人都可以被教导雕琢: 米开朗基罗必须被教导如何不被雕琢. 伟大的程序员也是如此".Perlis 说过, 伟人的内在品质超越了他们的训练. 但其品质来自哪里? 它是天生的吗? 或者他们是通过勤奋来形成的? 正如 Auguste Gusteau( Ratatouille 中虚构的厨师)所说,"任何人都可以烹饪, 但只有无所畏惧者才能做得很好." 我更多地想到将一个人的大部分时间投入到审慎的实践中的意愿. 但也许无畏是对其总结的一种方式. 或者, 正如 Gusteau 的评论家 Anton Ego 所说:"并非每个人都能成为伟大的艺术家, 但伟大的艺术家可以来自任何地方."
所以不妨继续购买 Java/Ruby/Javascript/PHP 类书籍; 你可能会用到其中一些. 但你不会在 24 小时或 21 天内改变你的生活或习得作为程序员所需的真正整体的专业知识. 努力不断改进超过 24 个月如何? 好吧, 现在你开始触摸到某个地方了......
Bloom, Benjamin (ed.) Developing Talent in Young People http://www.amazon.com/exec/obidos/ASIN/034531509X , Ballantine, 1985. (开发年轻人的天赋)
Brooks, Fred, No Silver Bullets http://citeseer.nj.nec.com/context/7718/0 , IEEE Computer, vol. 20, no. 4, 1987, p. 10-19. (银弹并不存在)
Bryan, W.L. & Harter, N. " 关于电报语言的研究: 习惯等级的养成. 心理学评论 , 1899, 8, 345-375
Hayes, John R., Complete Problem Solver http://www.amazon.com/exec/obidos/ASIN/0805803092 Lawrence Erlbaum, 1989.
Chase, William G. & Simon, Herbert A. "Perception in Chess" http://books.google.com/books?id=dYPSHAAACAAJ&dq=%22perception+in+chess%22+simon&ei=z4PyR5iIAZnmtQPbyLyuDQ (国际象棋中的洞察力) 认知心理学 , 1973, 4, 55-81.
Lave, Jean, 实践中的认知学: 日常生活中的心灵, 数学以及文化 http://www.amazon.com/exec/obidos/ASIN/0521357349 , 剑桥大学出版社, 1988.
答案
典型 PC 上不同操作的大致耗时:
执行典型的指令 | 1/1,000,000,000 sec = 1 nanosec |
读取 L1 缓存 | 0.5 nanosec |
分支误预测 | 5 nanosec |
读取 L2 缓存 | 7 nanosec |
Mutex 加锁 / 解锁 | 25 nanosec |
读取内存 | 100 nanosec |
通过 1Gbps 网络发送 2KB | 20,000 nanosec |
从内存中顺序读取 1MB | 250,000 nanosec |
从新的磁盘位置读取数据 (seek) | 8,000,000 nanosec |
从磁盘中顺序读取 1MB | 20,000,000 nanosec |
将数据包从美国发往欧洲,并返回 | 150 milliseconds = 150,000,000 nanosec |
来源: http://www.tuicool.com/articles/QvUFJ32