# 自学计算机科学
现在的技术书籍很多,怎么才能找到其中的精华,从而让我花在书籍上的时间"劳有所获",哪些书籍值得花时间多读几遍?
下面要介绍的内容就是为了解决以下两个问题:
- 你应该学习哪些科目,为什么要学?
- 这些科目对应的最好的学习资料(书籍、视频)是什么?
接下来,你将得到答案。
# 概览
按照列出的顺序,借助建议的书籍和视频课程,学习下面的9门科目。如果你是一个自学成才的工程师,或者从编程培训班毕业,那么你很有必要学习计算机科学。
科目 | 为何要学? | 最佳书籍 | 最佳视频 |
---|---|---|---|
编程 | 不要做一个"永远没彻底搞懂"诸如递归等概念的程序员。 | 《计算机程序的构造和解释》 | Brian Harvey's Berkeley CS 61A |
计算机架构 | 如果你对于计算机如何工作没有具体的概念,那么你所做出的所有高级抽象都是空中楼阁。 | 《计算机组成与设计》 | Berkeley CS 61C |
算法与数据结构 | 如果你不懂得如何使用栈、队列、树、图等常见数据结构,遇到有难度的问题时,你将束手无策。 | 《算法设计手册》 | Steven skiena's lectures |
数学知识 | 计算机科学基本上是应用数学的一个"失控的"分支,因此学习数学将会给你带来竞争优势。 | 《计算机科学中的数学》 | Tom Leighton's MIT 6.042J |
操作系统 | 你所写的代码,基本上都由操作系统来运行,因此你应当了解其运作的原理。 | 《操作系统导论》 | Berkeley CS 162 |
计算机网络 | 互联网已然势不可挡:理解工作原理才能解锁全部潜力。 | 《计算机网络:自顶向下方法》 | Stanford CS 144 |
数据库 | 对于多数重要程序,数据是其核心,然而很少人理解数据库系统的工作原理。 | 《Readings in Database System》 | Joe Hellerstein's Berkeley CS 186 |
编程语言与编译器 | 若你懂得编程语言和编译器如何工作,你就能写出更好的代码,更轻松地学习新的编程语言。 | 《编译原理》 | Alex Aiken's course on Lagunita |
分布式系统 | 如今,多数系统都是分布式的。 | 《分布式系统原理与范型》 |
# 为什么要学习计算机科学
软件工程师分为两种:
- 一种充分理解了计算机科学,从而有能力应对充满挑战的创造性工作
- 另一种仅仅凭着对一些高级工具的熟悉而勉强应付(直白有力,直击心灵)
这两种人都自称软件工程师,都能在职业生涯早期挣不到差不多的工资。然而,随着时间流逝,第一种工程师不断成长,所做的事情将会越来越有意义且更为高薪,不论是有价值的商业工作、突破性的开源项目、技术上的领导力或者高质量的个人贡献。
全球短信系统每日收发约200亿条信息,而仅仅靠57名工程师,现在的WhatsApp每日收发420亿条。
——Benedict Evans(@BenedictEvans)
第一种工程师总是寻求深入学习计算机科学的方法,或是通过传统的方法学习,或是在职业生涯中永无止息地学习。
第二种工程师通常浮于表面,只学习某些特定的工具和技术,而不研究其底层的基本原理,仅仅在技术潮流的风向改变时学习新的技能。
如今,涌入计算机行业的人数激增,然而计算机专业的毕业生数量上基本上未曾改变。第二种工程师的拱过于求正在开始减少他们的工作机会,使他们无法涉足行业内更加有意义的工作。对你而言,不论正在努力成为第一种工程师,还是只想让自己的职业生涯更加安全,学习计算机科学是唯一的途径。
(成为不可或缺的人才,而不是可以随意被替代的熟练工。)
# 分科目指引
# 编程
大多数计算机本科教学以程序设计"导论"作为开始。这类课程的最佳版本不仅能满足初学者的需要,还适用于那些在初学编程阶段遗漏了某些有益的概念和程序设计模式的人。
对于这部分内容,我们的标准推荐是这部经典著作:《计算机程序的构造和解释》。在网络上,这本书既可供免费阅读(英文版)。
我们建议至少学完SICP的前三章,并完成配套的习题。如果需要额外的练习,可以去解决一些小的程序设计问题,比如exercism。
# 计算机架构
计算机架构——有时候又被称为"计算机系统"或者"计算机组成"——是了解软件底层的重要视角。根据我们的经验,这是自学的软件工程师最容易忽视的领域。
《计算机系统要素》,又名"从与非门到俄罗斯方块"("Nand2 Tetris")。这本书规模宏大,让读者对计算机内的所有组成部分如何协同工作有完全的认识。这本书的每一章节对应如何构建计算机整体系统中的一小部分,从用HDL(硬件描述语言)写基本的逻辑门电路出发,途径CPU和汇编,最终抵达诸如俄罗斯方块这般规模的应用程序。
我们推荐把此书的前六章读完,并完成对应的项目练习。这么做,你将更加深入地理解,计算机架构和运行其上的软件之间的关系。
这本书的前半部分(包括所有对应的项目)均可从Nand2Tetris的网站上免费获得。
硬件是平台。
—— Mike Acton, Engine Director at Insomniac Games
(不明白游戏平台的规则,很难成为超级玩家)
# 算法与数据结构
正如几十年来的共识,我们认为计算机科学教育所赋予人们的最大能量在于对常见算法和数据结构的熟悉。此外,这也可以训练一个人对于各种问题的解决能力,有助于其它领域的学习。
关于算法与数据结构,有成百上千的书可供使用,但是我们的最爱是Steven Skiena编写的《算法设计手册》。显而易见,他对此充满热爱,迫不及待地想要帮助其他人理解。在我们看来,这本书给人一种焕然一新的体验,完全不同于那些更加经常被推荐的书。
至于练习,我们推荐学生在Leetcode上解决问题。Leetcode上的问题往往有趣且带有良好的解法和讨论。此外,在竞争日益激烈的软件行业,这些问题可以帮助你评估自己应对技术面试中常见问题的能力。我们建议解决大约100道随机的Leetcode问题,作为学习的一部分。
最后,我们强烈推荐《怎样解题》。这本书极为优秀且独特,指导人们解决广义上的问题,因而一如其适用于数学,它适用于计算机科学。
我可以广泛推荐的方法只有一个:写之前先思考。
—— Richard Hamming
# 数学知识
从某个角度说,计算机科学是应用数学的一个"发育过度"的分支。尽管许多软件工程师视图——并且在不同程度上成功做到——忽视这一点,我们鼓励你用学习来拥抱数学。如若成功,比起那些没有掌握数学的人,你将获得巨大的竞争优势。
对于计算机科学,数学中最相关的领域是"离散数学",其中的"离散"和"连续"相对立,大致上指的是应用数学中那些有趣的主题,而不是微积分之类的。由于定义比较含糊,试图掌握离散数学的全部内容是没有意义的。较为现实的学习目标是,了解逻辑、排列组合、概率论、集合论、图论以及密码学相关的一些数论知识。考虑到线性代数在计算机图形学和机器学习中的重要性,该领域同样值得学习。
学习离散数学,我们建议从László Lovász 的课程笔记开始。Lovász教授成功地让这些内容浅显易懂且符合直觉,因此,比起正式的教材,这更适合初学者。
对于更加高阶的学习,我们推荐《计算机科学中的数学》,MIT同名课程的课程笔记,篇幅与书籍相当(事实上,现已出版)。
对于线性代数,我们建议从Essence of linear algebra系列视频开始,然后再去学习Gilbert Strang的《线性代数导论》。
如果人们不相信数学是简单的,那么只能是因为他们没有意识到生活有多么复杂。
—— John von Neumann
# 操作系统
《操作系统概念》(恐龙书)和《现代操作系统》是操作系统领域的经典书籍。二者都因为写作风格,长达1000页的篇幅以及每隔几年就增加内容来鼓励人们购买"最新版本"招致了一些批评。
《操作系统导论》(Operating System: Three Easy Pieces)是一个不错的替代品,并且可在网上免费获得(英文版)。我们格外喜欢这本书的结构,并且认为这本书的习题很值得一做。
在读完《操作系统导论》后,我们鼓励你探索特定操作系统的设计。可以借助"{OS name} Internals"风格的书籍。
为了巩固对操作系统的理解,阅读小型系统内核的代码并且为其增加特性是一个很不错的方法。
# 计算机网络
鉴于有那么多关于网络服务端和客户端的软件工程,计算机网络是计算机科学中价值最为"立竿见影"的领域之一。我们的学生,系统性地学习了计算机网络,最终能理解那些曾困扰他们多年的术语、概念和协议。
在这一主题上,我们最爱的书籍是《计算机网络:自顶向下方法》。书中的小项目和习题相当值得练习,尤其是其中的"Wireshark labs"(这部分在网上可以获得)。
对于计算机网络的学习,做项目比完成小的习题更有益。一些可能的项目有:HTTP服务器,基于UDP的聊天APP、迷你TCP栈、代理、负载均衡器或者分布式哈希表。
你无法盯着水晶球预见未来,未来的互联网何去何从取决于社会。
—— Bob Kahn
# 数据库
比起其它主题,自学数据库系统需要更多的付出。这是一个相对年轻的研究领域,并且出于很强的商业动机,研究者把想法藏在紧闭的门后。此外,许多原本有潜力写出优秀教材的作者反而选择了加入或创立公司。
鉴于如上情况,我们鼓励自学者大体上抛弃教材,而是从2015年春季学期的CS186课程(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添加特性,倒是不错的项目,不过我们仅仅建议从零实现一个简单的关系型数据库管理系统。自然,它将不会有太多的特性,但是即便只实现典型的关系型数据库管理系统每个方面最基础的功能,也是相当有启发的。
# 编程语言与编译器
多数程序员学习编程语言的知识,而多数计算机科学家学习编程语言相关的知识。这使得计算机科学家比起程序员拥有显著的优势,即便在编程领域!因为他们的知识可以推而广之:相较于只学习过特定编程语言的人,他们可以更深入更快速地理解新的编程语言。
权威的导论书籍是《编译原理》,通常称为"龙书"。不幸的是,这本书不是为自学者而设计的,而是拱教师从中挑选一些主题用于1-2学期的教学。因此十分重要的是,你需要从中甄选主题,而且最好是在导师的帮助下。
对于项目练习,我们建议为诸如COOL的简单教学语言或者你所感兴趣的某个语言的一个子集写一个编译器。如果感觉这样的项目让人生畏,可以先从Make a Lisp开始,在一步步的指导下完成项目。
不要做一个只写样板代码的程序员。相反,给用户和其他程序员创造工具。从纺织工业和钢铁工业中学习历史教训:你想制造机器和工具,还是操作这些机器?
—— Ras Bodik 在他的编译器课程伊始
# 分布式系统
随着计算机在数量上的增加,计算机同样开始分散。尽管商业公司过去愿意购买越来越大的大型机,现在的典型情况是,甚至很小的应用程序都同时在多台机器上运行。思考这样做的利弊权衡,即是分布式系统的研究所在,也是越来越重要的一项技能。
对于自学者,我们推荐的教材是 Maarten van Steen 和 Andrew Tanenbaum 所著的《分布式系统原理与范型》(中文第二版,英文第三版)。相较之前的版本,第三版有巨大的改进,并且多亏了其作者的慷慨,这本书在网上可以免费获得。考虑到分布式系统是一个迅速变化的领域,没有教材可以完全作为路标指引,不过就我们所见,这本书是基础扎实的最佳总览。
不管选择怎样的教材或者其他辅助资料,学习分布式系统必然要求阅读论文。这里有一个不错的论文清单.
← 2019与我的自由启蒙 轮子哥的编程之路 →