電腦科學自學指南

pumpkin0227發表於2018-12-22

如果你是一名自學工程師或者是一名軟體集訓課程畢業的學生,有些電腦科學基礎課程是你必須要補齊的。幸好,你通過網際網路就能獲得世界頂級的CS(電腦科學)課程。

其實網上有很多學習資源但它們良莠不齊,你需要不是什麼“200+免費線上課程”列表而是如下問題的答案:

你應該學習哪門課程?為什麼?

每門課程最好的書籍或者視訊,講座是什麼?

我寫這篇文章的目的就是嘗試對於這些問題給出的明確答案:

使用建議的書籍或者視訊講座來學習以下的九門科目,最好是書籍和講座都仔細的研究一下,可以不嚴格按照列出的順序來。每一門科目都需要花上100-200小時來研讀,然後在你的職業生涯中對於最熱愛的方向進行反覆重溫。

主題 為什麼學習它 推薦書籍 推薦視訊
程式設計 別做那些連“遞迴”是什麼都搞不懂的程式設計師 Programs Brian Harvey’s Berkeley CS 61A
計算機體系結構 如果你基礎薄弱,不知道計算機是如何執行的,那些你學會的所謂“高層”技能不過是空中樓閣 計算機組成與設計硬體/軟體介面 Berkeley CS 61C
演算法和資料結構 如果你不能很好的使用隨處可見的資料結構(例如棧、佇列、樹和圖),你是無法解決複雜問題的 Steven Skiena’s lectures
計算機數學 電腦科學實際上是應用數學的一個分支,學好數學讓你更具競爭力 《Mathematics for Computer Science》 Tom Leighton’s MIT 6.042J
作業系統 你編寫的大部分程式碼是通過作業系統執行的,所以你需要知道它們是如何互動的 Operating Systems: Three Easy Pieces Berkeley CS 162
計算機網路 網際網路是個了不起的發明,只有理解它的原理,才能發揮它的威力
計算機網路(第4版)
Stanford CS 144
資料庫 對於很多程式來說,資料是其核心,但是很少有人真正理解資料庫系統是如何執行的 Readings in Database Systems Joe Hellerstein’s Berkeley CS 186
程式語言和編譯器 如果你理解語言和編譯器是如何執行的,你就能編寫更好的程式碼並輕鬆學會新的語言 編譯原理 技術與工具 Alex Aiken’s course on Lagunita
分散式系統 近年來,大部分系統已經發展成為分散式系統 Distributed Systems

為什麼要學習電腦科學

有兩種軟體工程師:一種人對於電腦科學有很好的理解從而去從事挑戰性的、富有創造力的工作。另外一種人僅僅熟悉一些高階工具,對其原理持得過且過的態度。

兩者都叫做軟體工程師,而且兩者在早期的職業生涯中可能領著同樣的薪水。但是第一種工程師,不管他從事的是商業工作,還是突破性的開源工程,都會由於他的技術領導力或者傑出的個人貢獻一點一點成長成一名對於程式設計更加痴迷而且待遇更高的工程師。

第一種工程師可以通過常規手段或者在職業生涯中不斷學習來加深對於電腦科學的理解深度。第二種工程師通常停留在表面,學習具體的工具或者技巧而不是其中的基礎,當前流行什麼技術,他們就僅僅撿起新的技能學習一下。

近些年來,越來越多的人進入軟體領域工作,但是本質上電腦科學的畢業生數量是沒有改變的。第二種工程師的供應過量開始導致他們的就業機會變少而且導致他們離企業中令人感覺充實的工作更遠。不管你是努力要成為第一種工程師或者僅僅是保險起見地想找到更多的工作,學習電腦科學是唯一一種可靠的途徑。

課程指南

程式設計

大多數大學的計算機程式設計課程通常以“入門類”計算機的課程開始。這些課程最好是不僅僅針對於初學者,而且對於第一次學習程式設計,基本概念和程式設計模型不是很熟悉的人也有所啟發的。

對於這種介紹的內容的我們給出的標準建議是經典的計算機程式的結構與解釋,在網路上能找到很多這樣的資料,它們可能是電子書或者是MIT的一系列講座視訊。這些講座都很不錯,但是我們的視訊推薦的實際上是伯克利的一門課程:Brian Harvey 的 SICP 講座 ,這個系列的課程比起MIT的講座更精煉而且對於入門者更具有針對性。

我們推薦觀看完至少前三章節的SICP(《計算機程式的構造和解釋 》)並且做完相應訓練。額外地,可以在 exercism 進行一些程式設計訓練。

image

如果你覺得SICP太難,我們推薦《程式設計方法(中文版)| How to Design Programs》這本書。如果你覺得它太簡單,我們推薦《Concepts, Techniques, and Models of Computer Programming 這本書。

計算機體系結構

硬體是平臺 – Mike Acton(Insomniac Games的工程總監) (收看他在 CPP 大會上的演講)

計算機結構–有的時候被稱為“計算機系統”或者“計算機組織”–是瞭解程式外表下計算機執行的第一步。根據我們的經驗,這是自學軟體工程師最容易忽略的地方。

《計算機系統要素》The Elements of Computing Systems,也被稱為“從與非門到俄羅斯方塊”。這是一本讓你對於計算機中的每一個零件是怎麼工作的有一個整體的理解的雄心勃勃的書。每個章節涉及到建立整體系統中一個小的部分,從寫基本的邏輯閘到HDL,到CPU和組合語言,一直到完成一個俄羅斯方塊應用程式。

elements-computing-systems

我們推薦閱讀書的前六章節並且完成相關的工程。這會提高你對於計算機結構和執行的軟體之間關係的理解。

這本書的前半部分(和它的全部工程)在 Nand2Tetris 網站上可以免費獲得。在 Coursera 課程網站上你也可以找到它們。

為了保證課程簡單並吸引人,Nand2Tetris 捨棄了深度。特別是現代計算機結構中兩個很重要的概念:流水線(pipelining)和記憶體層級(memory hierarchy),在書中都沒有提及。

當你覺得看Nand2Tetris已經很簡單了,我們下一個建議是Patterson和Hennessy合著的《計算機組成與設計硬體/軟體介面》Computer Organization and Design——一本傑出的現代經典書籍。不是書中所有的部分都很重要;我們建議跟隨Berkeley的CS61C 課程——(Great Ideas in Computer Architecture),作為特殊讀物。講座的筆記和實驗環境都是線上的,而且可以在在這個歸檔連結回看講座。

演算法和資料結構

只有一個方法是我一直以來廣泛推薦的—編碼前首先要思考 — Richard Hamming

我們根據幾十年的通識來看,熟悉通用的演算法和資料結構是電腦科學教育中最重要的方面之一。這是一個訓練一個人解決問題的通用能力的方式,而且這種能力還可以遷移到其他領域的學習。

這個領域有很多優秀的書籍,但是我們最喜歡的是Steven Skiena的《演算法設計手冊》The Algorithm Design Manual 。他顯然喜歡這東西而且也迫不及待地想幫助你學習資料結構和演算法。這是令人耳目一新的變化,我們認為這本書相對於被更多人所推薦的Cormen, Leiserson, Rivest & Stein 或者 Sedgewick 的書來說更好。後兩本書有些太過於引經據典,對於想通過閱讀來解決問題的人來說並不是一個好的選擇。

skiena

對於那些更喜歡講座視訊的人來說,我們推薦Skiena的講座. 我們也喜歡Tim Roughgarden的課程,在史丹佛的MOOC平臺或者Coursera上面可以獲得。你喜歡 Skiena 還是 Roughgarden 的講課風格就是你的個人喜好問題了。

說到練習,我們傾向於讓學生在Leetcode上面解決問題。LeetCode上面的問題都比較有趣而且有答案和討論。這上面還可以通過解決各大軟體公司廣泛應用的技術問題來幫助你測試你的進步。我們建議解決你學習的時候解決大約隨機100道LeetCode上面的問題。

最後,我們強烈推薦《怎樣解題》這本書,它針對如何解題進行了精彩絕倫和獨特的講解,既適用於數學也適用於電腦科學。

polya

電腦科學領域的數學

如果人們不認為數學是簡單的,那麼他們一定沒有體會過人生的艱難 — John von Neumann

在某些方面,電腦科學是應用數學的一個擴充套件。雖然許多軟體工程師忽略了這一點,我們建議你去學習它。好好學習數學會給你比那些不學習它們的人巨大的競爭優勢。

和CS最相關的數學領域是“離散數學”,離散是連續對立面。是微積分之外的一系列的有趣的應用數學的主題。從大體上說,嘗試學會全部範圍的“離散數學”是沒有意義的。更現實一點的做法是對於邏輯學,組合學和概率學,集合論,圖論和一些數論告知密碼學有一個瞭解。對於計算機影像學和機器學習來說,線性代數也是一門值得學習的課程。

我們建議從László Lovász的講座學起. 這一系列開始學習離散數學。Lovász 教授讓學習的內容變得直觀生動,比起拘謹的文字,這更利於你學習。

接下來,我們推薦《Mathematics for Computer Science》, 它是MIT同名課程的講義。講座課程的視訊也是免費的,而且是我們推薦的離散數學的視訊課程。

線性代數,我們建議從 Essence of linear algebra 系列開始學習,接著是Gilbert Strang的書籍視訊

作業系統

《作業系統概念》Operating System Concepts)(恐龍書)和《現代作業系統》Modern Operating Systems )是經典的作業系統的書籍。這兩本書的寫作方式都飽受爭議,而且為了鼓勵你去購買新版,這些長達1000頁的書每幾年就會新增一些內容。

Operating Systems: Three Easy Pieces》這本書是一本比較好的可供選擇的線上免費讀物。我們特別喜歡書的結構和它經典的練習題。

ostep

讀完這本書,我們推薦你去探索一種特定的作業系統的設計方式,比如那些書名中有系統名字的書籍,比如 《Lion‘s commentary on Unix》、《The Design and Implementation of the FreeBSD Operating System》,還有 Mac OS X Internals.

鞏固你對於作業系統的理解很好的方式是去讀一個小的核心並且新增功能。xv6 是一個不錯的選擇,它是 Unix V6 和 ANSI C 和 X86 的介面,MIT專門有一門課程就是講這個的。OSTEP(之前提到的)這本書有一個 XV6 的實驗附錄,裡面都是充滿潛力專案的好點子。

計算機網路

你不能夠通過凝視水晶球來預見未來。因特網未來會變成什麼樣,取決於如今人類如何去塑造它 — Bob Kahn

考慮到很多軟體專案都是基於web伺服器和客戶端的,計算機網路變成電腦科學中一門有實用價值的學科。系統學習過該課程的自學學生發現他們終於理解了圍繞了伴隨它們很多年的術語,概念,協議等等。

關於這個主題我們最推薦的書是:《計算機網路》Computer Networking: A Top-Down Approach)。書中的小工程和實驗都很好,值得一做。我們非常喜歡它們提供的 Wireshark labs

對於那些喜歡視訊課程的人,我們推薦史丹佛MOOC平臺上的《Introduction to Computer Networking course》。

學習網路的好處不僅僅在於做小的實驗而且對於工程來說也有很大的好處。可能涉及到的有:一個HTTP的伺服器,一個UDP協議的聊天軟體,一個迷你的 TCP 協議棧,一個代理或者負載平衡器,還有分散式的雜湊表等等。

資料庫

對於自學者來說,學習資料庫系統會比學習其他花費更多的時間。這是一個相對較新的(即1970年代後期)的研究領域。比起寫書,許多潛在的傑出教科書作者更願意去加入或者創辦一家公司。

在這種情況下,我們建議自學者放棄教科書而去學習伯克利的Joe Hellerstein的資料庫課程,看完課程再去閱讀論文。

對於初學者有一篇論文比較推薦的是:《Architecture of a Database System》,它高屋建瓴地講解了關聯式資料庫管理系統是如果工作的這一問題。它會為你未來的學習提供一個有用的綱要。

Readings in Database Systems這本書,又被稱為資料庫紅皮書、是一本Peter Bailis、Joe Hellerstein和Michael Stonebraker編輯地論文集。對於那些理解了CS 186內容的人來說,紅皮書是你的不二之選。

如果你堅持要使用一本引導性的教科書,我們推薦Ramakrishnan 和Gehrke的《資料庫管理系統》Database Management Systems,對於更優秀的學生,Jim Gray的傳統課程《Transaction Processing: Concepts and Techniques值得一看,但是我們不建議把它當成入門書。

不編大量的程式碼是不能很好的鞏固資料庫的理論的,CS 186的學生往Spark中新增功能,這是一個很有意義的工程。但是我們建議僅僅是從頭寫一個簡單的關聯式資料庫管理系統。功能可能不是很豐富,但是即使每一個部分都涉及到一些基本功能也很有啟發性。

最後,資料模型是一個資料庫使用中被忽略和沒有被重點學習的方面。我們對於這個課題建議的書籍是:《Data and Reality: A Timeless Perspective on Perceiving and Managing Information in Our Imprecise World

語言和編譯器

Don’t be a boilerplate programmer. Instead, build tools for users and other programmers. Take historical note of textile and steel industries: do you want to build machines and tools, or do you want to operate those machines? — Ras Bodik at the start of his compilers course

大部分程式設計師學習如何使用一門程式語言,然而大部分的電腦科學家則學習這門語言本身。這給了電腦科學家比起程式設計師很明顯的優勢。他們的知識能夠更好的泛化,他們能比簡簡單單地掌握一門語言的更加深入和快速的理解一門新語言的操作。

經典的教科書《編譯原理 技術與工具》( Compilers: Principles, Techniques & Tools)通常又被稱為“龍書”。不幸的是,這本書並不適合自學者,它比較適合教師從中選出1-2個章節並在課堂上講授。這本書是有必要看的,你可以挑選裡面的主題,最好再有個師傅指導你。

如果你選擇在自學中使用龍書,我們推薦你一系列門視訊講座,然後再沉浸在對於龍書的研究中。我們推薦的線上課程是:Alex Aiken 的講座,你可以在史丹佛大學的幕課平臺上觀看。

也有可以替代龍書的教材:Terence Parr寫的《程式語言實現模式》Language Implementation Patterns,它更適合那些工作中使用類似特定領域語言的小眾語言的有經驗的程式設計者,它顯得更加實用。當然,為了達到這個目的它也刪去了一些有價值的理論。

對於工程實踐,我們推薦你寫一個編譯器,你可以選擇像COOL這種簡單的教學語言或者你感興趣的一門語言。如果你覺得太難,你可以參考Make a Lisp,你可以參考它作為開始。

分散式系統

計算機的數量增長了,它們的分佈也更廣了。企業之前會購買越來越大型的主機,但是現在大家更傾向於在很多機器上分散式的執行多個小型的應用程式。分散式系統研究的就是這樣的技術,這一技術變得越來越重要了。

我們建議的自學教科書是 Maarten van Steen 和 Andrew Tanenbaum 的《Distributed Systems, 3rd Edition》。 針對於之前的版本做了很大的改進,而且作者慷慨地把書放在了網上共享。由於分散式計算是一門變化很快的領域,所以沒有教科書可以很好的涵蓋所有的內容。但是Maarten van Steen的書是我們讀過的所有書中最好的書。

研究生線上課程 MIT’s 6.824 也是一個不錯的選擇,但可惜視訊中的音質不太好,而且不清楚這些視訊是不是都被授權過。

儘管有參考書或者其它的資源,但學習分散式系統是絕對要讀論文的。連結中有一個很好的清單,而且我們十分推薦你從Papers We Love 上面下載論文到本地學習。

 

譯註:本文提到的大部分書籍,中英文版已歸檔至該豆列

相關文章