# 如何使用这本书

随着贡献者的不断增多，本书的内容也不断扩展，想把书中所有的课程全部学完是不切实际也没有必要的，甚至会起到事倍功半的反效果，吃力而不讨好。为了更好地贴合读者，让这本书真正为你所用，我将读者按照需求大致分为了如下三类，大家可以结合切身实际，精准地规划属于自己的自学方案。

## 初入校园

如果你刚刚进入大学校园或者还在低年级，并且就读的是计算机方向或者想要转到计算机方向，那么你很幸运，因为学习是你的本业，你可以有充足的时间和自由来学习自己感兴趣的东西，不会有工作的压力和生活的琐碎，不必过于纠结“学了有没有用”，“能不能找到工作”这类功利的想法。那么该如何安排自己的学业呢？我觉得首要的一点就是要打破在高中形成的“按部就班”式的被动学习。作为一个小镇做题家，我深知国内大部分高中会把大家一天当中的每一分钟都安排得满满当当，你只需要被动地跟着课表按部就班地完成一个个既定的任务。只要足够认真，结果都不会太差。但步入大学的校门，自由度一下子变大了许多。首先所有的课外时间基本都由你自由支配，没有人为你整理知识点，总结提纲，考试也不像高中那般模式化。如果你还抱着高中那种“乖学生”的心态，老老实实按部就班，结果未必如你所愿。因为专业培养方案未必就是合理，老师的教学未必就会负责，认真出席课堂未必就能听懂，甚至考试内容未必就和讲的有关系。说句玩笑话，你或许会觉得全世界都与你为敌，而你只能指望自己。

那么现状就是这么个现状，你想改变，也得先活过去，并且拥有足够的能力去质疑它。而在低年级，打好基础很重要。这里的基础是全方面的，课内的知识固然重要，但计算机很大程度上还是强调实践，因此有很多课本外的能力需要培养，而这恰恰是国内的计算机本科教育很欠缺的一点。我根据个人的体验总结出了下面几点建议，供大家参考。

其一就是了解如何写“优雅”的代码。国内的很多大一编程入门课都会讲成极其无聊的语法课，其效果还不如直接让学生看官方文档。事实上，在刚开始接触编程的时候，让学生试着去了解什么样的代码是优雅的，什么样的代码 "have bad taste" 是大有裨益的。一般来说，编程入门课会先介绍过程式编程（例如 C 语言）。但即便是面向过程编程，**模块化** 和 **封装** 的思想也极其重要。如果你只想着代码能在 OpenJudge 上通过，写的时候图省事，用大段的复制粘贴和臃肿的 main 函数，长此以往，你的代码质量将一直如此。一旦接触稍微大一点的项目，无尽的 debug 和沟通维护成本将把你吞没。因此，写代码时不断问自己，是否有大量重复的代码？当前函数是否过于复杂（Linux 提倡每个函数只需要做好一件事）？这段代码能抽象成一个函数吗？一开始你可能觉得很不习惯，甚至觉得这么简单的题需要如此大费周章吗？但记住好的习惯是无价的，C 语言初中生都能学会，凭什么公司要招你去当程序员呢？

学过面向过程编程后，大一下学期一般会讲面向对象编程（例如 C++ 或 Java）。这里非常推荐大家看 [MIT 6.031: Software Construction](./软件工程/6031.md) 这门课的 Notes，会以 Java 语言（22年改用了 TypeScript 语言）为例非常详细地讲解如何写出“优雅”的代码。例如 Test-Driven 的开发、函数 Specification 的设计、异常的处理等等等等。除此之外，既然接触了面向对象，那么了解一些常见的设计模式也是很有必要的。因为国内的面向对象课程同样很容易变成极其无聊的语法课，让学生纠结于各种继承的语法，甚至出一些无聊的脑筋急转弯一样的题目，殊不知这些东西在地球人的开发中基本不会用到。面向对象的精髓是让学生学会自己将实际的问题抽象成若干类和它们之间的关系，而设计模式则是前人总结出来的一些精髓的抽象方法。这里推荐[大话设计模式](https://book.douban.com/subject/2334288/) 这本书，写得非常浅显易懂。

其二就是尝试学习一些能提高生产力的工具和技能，例如 Git、Shell、Vim。这里强烈推荐学习 [MIT missing semester](./编程入门/MIT-Missing-Semester.md) 这门课，也许一开始接触这些工具用起来会很不习惯，但强迫自己用，熟练之后开发效率会直线提高。此外，还有很多应用也能极大提高的你生产力。一条定律是：一切需要让手离开键盘的操作，都应该想办法去除。例如切换应用、打开文件、浏览网页这些都有相关插件可以实现快捷操作（例如 Mac 上的 [Alfred](https://www.alfredapp.com/)）。如果你发现某个操作每天都会用到，并且用时超过1秒，那就应该想办法把它缩减到0.1秒。毕竟以后数十年你都要和电脑打交道，形成一套顺滑的工作流是事半功倍的。最后，学会盲打！如果你还需要看着键盘打字，那么赶紧上网找个教程学会盲打，这将极大提高你的开发效率。

其三就是平衡好课内和自学。我们质疑现状，但也得遵守规则，毕竟绩点在保研中还是相当重要的。因此在大一，我还是建议大家尽量按照自己的课表学习，但辅以一些优质的课外资源。例如微积分线代可以参考 [MIT 18.01/18.02](./数学基础/MITmaths.md) 和 [MIT 18.06](./数学基础/MITLA.md) 的课程 Notes。假期可以通过 [UCB CS61A](./编程入门/Python/CS61A.md) 来学习 Python。同时做到上面第一、第二点说的，注重好的编程习惯和实践能力的培养。就个人经验，大一的数学课学分占比相当大，而且数学考试的内容方差是很大的，不同学校不同老师风格迥异，自学也许能让你领悟数学的本质，但未必能给你一个好成绩。因此考前最好有针对性地刷往年题，充分应试。

在升入大二之后，计算机方向的专业课将居多，此时大家可以彻底放飞自我，进入自学的殿堂了。具体可以参考 [一份仅供参考的CS学习规划](./CS学习规划.md)，这是我根据自己三年自学经历总结提炼出来的全套指南，每门课的特点以及为什么要上这门课我都做了简单的介绍。对于你课表上的每个课程，这份规划里应该都会有相应的国外课程，而且在质量上我相信基本是全方位的碾压。由于计算机方向的专业知识基本是一样的，而且高质量的课程会让你从原理上理解知识点，对于国内大多照本宣科式的教学来说基本是降维打击。一般来说只要考前将老师“辛苦”念了一学期的 PPT 拿来突击复习两天，取得一个不错的卷面分数并不困难。如果有课程大作业，则可以尽量将国外课程的 Lab 或者 Project 修改一番以应付课内的需要。我当时上操作系统课，发现老师还用着早已被国外学校淘汰的课程实验，便邮件老师换成了自己正在学习的 [MIT 6.S081](./操作系统/MIT6.S081.md) 的 xv6 Project，方便自学的同时还无意间推动了课程改革。总之，灵活变通是第一要义，你的目标是用最方便、效率最高的方式掌握知识，所有与你这一目标违背的所谓规定都可以想方设法地去“糊弄”。凭着这份糊弄劲儿，我大三之后基本没有去过线下课堂（大二疫情在家呆了大半年），对绩点也完全没有影响。

最后，希望大家少点浮躁和功利，多一些耐心和追求。很多人发邮件问我自学需不需要很强的自制力，我觉得得关键得看你自己想要什么。如果你依然抱着会一门编程语言便能月薪过万的幻想，想分一杯互联网的红利，那么我说再多也是废话。其实我最初的自学并没有太多功利的想法，只是单纯的好奇和本能的求知欲。自学的过程也没有所谓的“头悬梁，锥刺股”，该吃吃，该玩玩，不知不觉才发现竟然攒下了这么多资料。现如今中美的对抗已然成为趋势，而我们还在“卑微”地“师夷长技”，感叹国外高质量课程的同时也时常会有一种危机感。这一切靠谁来改变呢？靠的是刚刚入行的你们。所以，加油吧，少年！

## 删繁就简

如果你已经本科毕业开始读研或者走上了工作岗位，亦或是从事着其他领域的工作想要利用业余时间转码，那么你也许并没有充足的业余时间来系统地学完 [一份仅供参考的CS学习规划](./CS学习规划.md) 里的内容，但又想弥补本科时期欠下的基础。考虑到这部分读者通常有一定的编程经验，入门课程没有必要再重复学习。而且从实用角度来说，由于工作的大体方向已经确定，确实没有太大必要对于每个计算机分支都有特别深入的研究，更应该侧重一些通用性的原则和技能。因此我结合自身经历，选取了个人感觉最重要也是质量最高的几门核心专业课，希望能更好地加深读者对计算机的理解。学完这些课程，无论你具体从事的是什么工作，我相信你将不可能沦为一个普通的调包侠，而是对计算机的底层运行逻辑有更深入的了解。

|课程方向      |课程名                                            |
|-------------|-------------------------------------------------|
|离散数学和概率论|[UCB CS70 : discrete Math and probability theory](./数学进阶/CS70.md)|
|数据结构与算法 |[Coursera: Algorithms I & II](数据结构与算法/Algo.md)|
|软件工程      |[MIT 6.031: Software Construction](软件工程/6031.md)|
|全栈开发      |[MIT web development course](Web开发/mitweb.md)|
|计算机系统导论 |[CMU CS15213: CSAPP](./体系结构/CSAPP.md)|
|体系结构入门   |[Coursera: Nand2Tetris](./体系结构/N2T.md)       |
|体系结构进阶   |[CS61C: Great Ideas in Computer Architecture](./体系结构/CS61C.md)|
|数据库原理     |[CMU 15-445: Introduction to Database System](数据库系统/15445.md)|
|计算机网络     |[Computer Networking: A Top-Down Approach](./计算机网络/topdown.md)|
|人工智能      |[Harvard CS50: Introduction to AI with Python](人工智能/CS50.md)|
|深度学习      |[Coursera: Deep Learning](深度学习/CS230.md)|

## 心有所属

如果你对于计算机领域的核心专业课都掌握得相当扎实，而且已经确定了自己的工作或研究方向，那么书中还有很多未在 [一份仅供参考的CS学习规划](./CS学习规划.md) 提到的课程供你探索。

随着贡献者的不断增多，左侧的目录中将不断增加新的分支，例如 **机器学习进阶** 和 **机器学习系统**。并且同一个分支下都有若干同类型课程，它们来自不同的学校，有着不同的侧重点和课程实验，例如 **操作系统** 分支下就包含了麻省理工、伯克利、南京大学还有哈工大四所学校的课程。如果你想深耕一个领域，那么学习这些同类的课程会给你不同的视角来看待类似的知识。同时，本书作者还计划联系一些相关领域的科研工作者来分享某个细分领域的科研学习路径，让 CS自学指南 在追求广度的同时，实现深度上的提高。

如果你想贡献这方面的内容，欢迎和作者邮件联系 [zhongyinmin@pku.edu.cn](mailto:zhongyinmin@pku.edu.cn)