真·程序员必修书单
https://m.toutiao.com/is/Ju1Fsy1/
本文作者:削微寒
迫近年关,很多人都写了 19 年的总结和 20 年的展望。我在回想 2019 年的时候,想到自己只读完了几本'杂’书,真正技术的书籍一本也没有读完。焦虑就悄然涌上心头,有种不学习就退步的烦躁。然后我回想起了之前看到的一个网站:
- Teach Yourself Computer Science:https://teachyourselfcs.com/
- GitHub 上的中文翻译:https://github.com/keithnull/TeachYourselfCS-CN
现在的技术书籍很多,怎么才能找到其中的精华,从而让我花在书籍上的时间'劳有所获’,哪些书籍值得花时间多读几遍?
下面要介绍的内容就是为了解决以下两个问题:
- 你应该学习哪些科目,为什么要学?
- 这些科目对应的最好的学习资料(书籍、视频)是什么?
接下来,你将得到答案。(我寻找的书单要来啦!)
一、概览
按照列出的顺序,借助建议的书籍和视频课程,学习下面的 9 门科目。如果你是一个自学成才的工程师,或者从编程培训班毕业,那么你很有必要学习计算机科学。
(我本科喂了 Dota,编程算是自学的。工作了后我深刻的体会到,这些科目的重要性。)
二、为什么要学习计算机科学
软件工程师分为两种:
- 一种充分理解了计算机科学,从而有能力应对充满挑战的创造性工作;
- 另一种仅仅凭着对一些高级工具的熟悉而勉强应付。(直白有力,直击心灵)
这两种人都自称软件工程师,都能在职业生涯早期挣到差不多的工资。然而,随着时间流逝,第一种工程师不断成长,所做的事情将会越来越有意义且更为高薪,不论是有价值的商业工作、突破性的开源项目、技术上的领导力或者高质量的个人贡献。
全球短信系统每日收发约 200 亿条信息,而仅仅靠 57 名工程师,现在的 WhatsApp 每日收发 420 亿条。
— Benedict Evans (@BenedictEvans)
第一种工程师总是寻求深入学习计算机科学的方法,或是通过传统的方法学习,或是在职业生涯中永无止息地学习;
第二种工程师通常浮于表面,只学习某些特定的工具和技术,而不研究其底层的基本原理,仅仅在技术潮流的风向改变时学习新的技能。
如今,涌入计算机行业的人数激增,然而计算机专业的毕业生数量基本上未曾改变。第二种工程师的供过于求正在开始减少他们的工作机会,使他们无法涉足行业内更加有意义的工作。对你而言,不论正在努力成为第一种工程师,还是只想让自己的职业生涯更加安全,学习计算机科学是唯一可靠的途径。
(成为不可或缺的人才,而不是可以随意被替代的熟练工。我的热血沸腾起来了,我要知道如何成为真·程序员!)
三、分科目指引
注意:因为篇幅问题,我删除了视频部分的推荐。有需求的小伙伴,可点击阅读原文。
3.1 编程
大多数计算机专业本科教学以程序设计“导论”作为开始。这类课程的最佳版本不仅能满足初学者的需要,还适用于那些在初学编程阶段遗漏了某些有益的概念和程序设计模式的人。
对于这部分内容,我们的标准推荐是这部经典著作:《计算机程序的构造和解释》。在网络上,这本书既可供免费阅读(英文版)
我们建议至少学完 SICP 的前三章,并完成配套的习题。如果需要额外的练习,可以去解决一些小的程序设计问题,比如exercism。
(这本书我读完序章就睡着了,我要擦干口水,扶我起来)
3.2 计算机架构
计算机架构——有时候又被称为“计算机系统”或者“计算机组成”——是了解软件底层的的重要视角。根据我们的经验,这是自学的软件工程师最容易忽视的领域。
《计算机系统要素》,又名“从与非门到俄罗斯方块”(“Nand2Tetris”)。这本书规模宏大,让读者对计算机内的所有部分如何协同工作有完全的认识。这本书的每一章节对应如何构建计算机整体系统中的一小部分,从用 HDL(硬件描述语言)写基本的逻辑门电路出发,途经 CPU 和汇编,最终抵达诸如俄罗斯方块这般规模的应用程序。
我们推荐把此书的前六章读完,并完成对应的项目练习。这么做,你将更加深入地理解,计算机架构和运行其上的软件之间的关系。
这本书的前半部分(包括所有对应的项目)均可从Nand2Tetris 的网站上免费获得。
硬件是平台。
— Mike Acton, Engine Director at Insomniac Games
(不明白游戏平台的规则,很难成为超级玩家)
3.3 算法与数据结构
正如几十年来的共识,我们认为计算机科学教育所赋予人们的最大能量在于对常见算法和数据结构的熟悉。此外,这也可以训练一个人对于各种问题的解决能力,有助于其他领域的学习。
关于算法与数据结构,有成百上千的书可供使用,但是我们的最爱是 Steven Skiena 编写的 《算法设计手册》。显而易见,他对此充满热爱,迫不及待地想要帮助其他人理解。在我们看来,这本书给人一种焕然一新的体验,完全不同于那些更加经常被推荐的书。
至于练习,我们推荐学生在Leetcode上解决问题。Leetcode 上的问题往往有趣且带有良好的解法和讨论。此外,在竞争日益激烈的软件行业,这些问题可以帮助你评估自己应对技术面试中常见问题的能力。我们建议解决大约 100 道随机挑选的 Leetcode 问题,作为学习的一部分。
最后,我们强烈推荐 《怎样解题》。这本书极为优秀且独特,指导人们解决广义上的问题,因而一如其适用于数学,它适用于计算机科学。
我可以广泛推荐的方法只有一个:写之前先思考。
— Richard Hamming
(我这个算法渣默默的捧起了《我的第一本算法书》,上面的推荐的书明年再战!)
3.4 数学知识
从某个角度说,计算机科学是应用数学的一个“发育过度”的分支。尽管许多软件工程师试图——并且在不同程度上成功做到——忽视这一点,我们鼓励你用学习来拥抱数学。如若成功,比起那些没有掌握数学的人,你将获得巨大的竞争优势。
对于计算机科学,数学中最相关的领域是“离散数学”,其中的“离散”与“连续”相对立,大致上指的是应用数学中那些有趣的主题,而不是微积分之类的。由于定义比较含糊,试图掌握离散数学的全部内容是没有意义的。较为现实的学习目标是,了解逻辑、排列组合、概率论、集合论、图论以及密码学相关的一些数论知识。考虑到线性代数在计算机图形学和机器学习中的重要性,该领域同样值得学习。
学习离散数学,我们建议从 László Lovász 的课程笔记开始。Lovász 教授成功地让这些内容浅显易懂且符合直觉,因此,比起正式的教材,这更适合初学者。
对于更加高阶的学习,我们推荐 《计算机科学中的数学》,MIT 同名课程的课程笔记,篇幅与书籍相当(事实上,现已出版)。
对于线性代数,我们建议从 Essence of linear algebra 系列视频开始,然后再去学习 Gilbert Strang 的《线性代数导论》
如果人们不相信数学是简单的,那么只能是因为他们没有意识到生活有多么复杂。
— John von Neumann
(放我一条活路)
3.5 操作系统
《操作系统概念》(“恐龙书”)和 《现代操作系统》是操作系统领域的经典书籍。二者都因为写作风格,长达 1000 页的篇幅以及每隔几年就增加内容来鼓励人们购买“最新版本”招致了一些批评。
《操作系统导论》(Operating Systems: Three Easy Pieces)是一个不错的替代品,并且可在网上免费获得(英文版)。我们格外喜欢这本书的结构,并且认为这本书的习题很值得一做。
在读完《操作系统导论》后,我们鼓励你探索特定操作系统的设计。可以借助“{OS name} Internals”风格的书籍。
为了巩固对操作系统的理解,阅读小型系统内核的代码并且为其增加特性是一个很不错的方法。
(写一个小型系统内核很酷)
3.6 计算机网络
鉴于有那么多关于网络服务端和客户端的软件工程,计算机网络是计算机科学中价值最为“立竿见影”的领域之一。我们的学生,系统性地学习了计算机网络,最终能够理解那些曾困扰他们多年的术语、概念和协议。
在这一主题上,我们最爱的书籍是 《计算机网络:自顶向下方法》。书中的小项目和习题相当值得练习,尤其是其中的“Wireshark labs”(这部分在网上可以获得)。
对于计算机网络的学习,做项目比完成小的习题更有益。一些可能的项目有:HTTP 服务器,基于 UDP 的聊天 APP、迷你TCP栈、代理、负载均衡器或者分布式哈希表。
你无法盯着水晶球预见未来,未来的互联网何去何从取决于社会。
— Bob Kahn
(之前有人给我推荐过,我没买来看。然而现在正在读:真香~)
3.7 数据库
比起其他主题,自学数据库系统需要更多的付出。这是一个相对年轻的研究领域,并且出于很强的商业动机,研究者把想法藏在紧闭的门后。此外,许多原本有潜力写出优秀教材的作者反而选择了加入或创立公司。
鉴于如上情况,我们鼓励自学者大体上抛弃教材,而是从2015 年春季学期的 CS 186 课程(Joe Hellerstein 在 Berkeley 的数据库课程)开始,然后前往阅读论文。
对于初学者,有一篇格外值得提及的论文:“Architecture of a Database System”。这篇论文提供了独特的对关系型数据库管理系统(RDBMS)如何工作的高层次观点,是后续学习的实用梗概。
《Readings in Database Systems》,或者以数据库“红书”更为人知,是由 Peter Bailis,Joe Hellerstein 和 Michael Stonebraker 编纂的论文合集。对于那些想要在 CS 186 课程的水平更进一步的学习者,“红书”应当是下一步。
如果你坚持一定要一本导论教材,那我们推荐 Ramakrishnan 和 Gehrke 所著的 《数据库管理系统:原理与设计》。
如果没有编写足够数量的代码,很难巩固数据库理论。CS 186 课程的学生给 Spark 添加特性,倒是不错的项目,不过我们仅仅建议从零实现一个简单的关系型数据库管理系统。自然,它将不会有太多的特性,但是即便只实现典型的关系型数据库管理系统每个方面最基础的功能,也是相当有启发的。
(国内做数据库的公司越来越多了,但这块我还啃不下先放放)
3.8 编程语言与编译器
多数程序员学习编程语言的知识,而多数计算机科学家学习编程语言 相关 的知识。这使得计算机科学家比起程序员拥有显著的优势,即便在编程领域!因为他们的知识可以推而广之:相较只学习过特定编程语言的人,他们可以更深入更快速地理解新的编程语言。
权威的导论书籍是《编译原理》,通常称为“龙书”。不幸的是,这本书不是为自学者而设计的,而是供教师从中挑选一些主题用于 1-2 学期的教学。因此十分重要的是,你需要从中甄选主题,而且最好是在导师的帮助下。
对于项目练习,我们建议为诸如 COOL 的简单教学语言或者你所感兴趣的某个语言的一个子集写一个编译器。如果感觉这样的项目让人生畏,可以先从 Make a Lisp开始,在一步步的指引下完成项目。
不要做一个只写样板代码的程序员。相反,给用户和其他程序员创造工具。从纺织工业和钢铁工业中学习历史教训:你想制造机器和工具,还是操作这些机器?
— Ras Bodik 在他的编译器课程伊始
(我说为什么大神学习一门语言那么快!)
3.9 分布式系统
随着计算机在数量上的增加,计算机同样开始**分散((。尽管商业公司过去愿意购买越来越大的大型机,现在的典型情况是,甚至很小的应用程序都同时在多台机器上运行。思考这样做的利弊权衡,即是分布式系统的研究所在,也是越来越重要的一项技能。
对于自学者,我们推荐的教材是 Maarten van Steen 和 Andrew Tanenbaum 所著的《分布式系统原理与范型》(中文第二版,英文第三版)。相较之前的版本,第三版有巨大的改进,并且多亏了其作者的慷慨,这本书在网上可以免费获得。考虑到分布式系统是一个迅速变化的领域,没有教材可以完全作为路标指引,不过就我们所见,这本书是基础扎实的最佳总览。
不管选择怎样的教材或者其他辅助资料,学习分布式系统必然要求阅读论文。这里有一个不错的论文清单.
(工作中会遇到,安排上)
四、常见问题解答
4.1 人工智能/计算机图形学/XX主题怎么样?
我们试图把计算机科学主题清单限制到那些我们认为每一个软件工程师都应该了解的内容,不限于专业或行业。拥有了这些基础,你将能更加轻松地挑选教材或论文,然而无需指引地学习核心概念。在这里,我们给出一些其他常见主题的自学起点:
- 人工智能:通过观看视频并完成Pacman项目来学习 Berkeley 的 AI 课程。至于教材,使用 Russell 和 Norvig 编写的 《人工智能:一种现代方法》。
- 机器学习:学习吴恩达在 Coursera 上的课程。耐心学习,先确保理解了基础概念再奔向类如深度学习的诱人新主题。
- 计算机图形学:学习 Berkeley CS 184 课程的材料,使用《计算机图形学:原理及实践》作为教材。
4.2 一定要严格遵守推荐的学习次序吗?
事实上,所有主题之间都有一定程度的重叠,彼此循环引用。以离散数学和算法的关系为例:先学习数学可以帮助你更深入地分析和理解算法,然而先学习算法可以为学习离散数学提供更大的动力和应用背景。理想情况下,你将在你的职业生涯多次重温二者。
因此,我们所推荐的次序主要是为了帮助你起步……如果你出于某种强烈的原因而倾向以不同的顺序学习,那也没有关系,勇敢开始吧!不过在我们看来,最重要的“先决条件”是:先学计算机架构再学操作系统或数据库,先学计算机网络和操作系统再学分布式系统。
4.3 这份指引的目标受众是?
我们面向自学的软件工程师、培训班学生、“早熟的”高中生或者想要通过自学补充正式教育的大学生。关于何时开启这段自学旅程,完全取决于个人,不过多数人在有一定的职业经历后深入学习计算机科学理论会获益匪浅。比如:我们注意到,如果学生在工作中曾经使用过数据库,他们会喜爱学习数据库系统课程;如果学生从事过一两个 Web 项目,他们会喜爱学习计算机网络。
4.4 XX 编程语言怎么样?
学习一门特定的编程语言和学习计算机科学的一个领域完全不在一个维度——相比之下,学习语言容易且缺乏价值。如果你已经了解了一些语言,我们强烈建议遵照我们的指引,然后在学习的空当中习得语言,或者暂且不管以后再说。如果你已经把编程学得不错了(比如学完了《计算机程序的构造和解释》),尤其是如果你学习过编译器,那么面对一门新的语言,你只需要花一个周末稍多的时间即可基本掌握。
4.5 XX 流行技术怎么样?
没有任何一种技术的重要程度可以达到学习其使用足以成为计算机科学教学的核心部分。不过,你对学习那门技术充满热情,这很不错。诀窍是先从特定的技术回退到基本的领域或概念,判断这门流行技术在技术的宏观大局中位于何处,然后才深入学习这门技术。