編程學習指南

我我的十分喜歡的編程學習指南,也將做爲本身的編程學習和技能提高的重要參考。javascript

本文做者是@蕭井陌,基於我的收藏的緣故,在格式上略有改動。php

前言

現在編程成爲了一個愈來愈重要的技能:做爲設計師,懂一些編程可能會幫你更好地理解本身工做內容;做爲創業者,技術創始人的身份則會讓你的不少工做顯得更容易。而做爲剛想入門的新手,面對眼前海量的信息,或許根本不知道從哪裏開始;入門輕鬆度過初級材料的學習後,發現學習愈來愈困難,陡峭的學習曲線又讓你望而卻步;你知道如何在頁面上打印輸出一些文本行,可是你不知道什麼時候該進行一個真正的有用的項目;你不清楚本身還有哪些不知道的東西,你甚至搞不清下一步該學什麼。html

這篇文章的內容對此不只會有一些方向性的建議,還會包含一個核心向的編程入門導引。固然,Step by Step 的路線是不現實的,而且每一個人都會有本身的特色,因此給出的這個編程入門導引更多的是爲了引起讀者的思考,最終幫助你造成適用於本身的學習路線。java

但要注意:這篇文章是寫給那些真心想學編程的人看的——那些憋着一股狠勁兒,必定要作出個什麼真東西,不學好不罷休的人;而不是那些「據說編程好玩」的人,在我看來,這種人永遠都入不了編程的門,更別提整出個像樣的東西來了。python

心態調整

肯定目標

You can code. They cannot. That is pretty damn cool.c++

– Learn Python The Hard Waygit

在你學習編程以前思考一下你的目標,當你有最終目標時道路會更加的清晰。那麼,你想要寫什麼?網站?遊戲?iOS或者Android應用?或是你是想自動化完成一些乏味的任務讓你有更多的時間看窗外的風景?也許你只是想更具備就業競爭力找個好工做。全部的這些都是有價值的目標,這些目標都是你編程學習推進力的一部分,沒有推進力的人,是沒法在略顯枯燥的漫長學習之旅中走遠的。程序員

這段視頻也許能給你啓發:What Most Schools Don't Teachgithub

不要浮躁

Bad programming is easy. Even Dummies can learn it in 21 days. Good programming requires thought, but everyone can do it and everyone can experience the extreme satisfaction that comes with it.web

無論是在線下仍是線上的書店,滿目都是《21天學通Java》這種速成書目,它們都承諾在很短一段時間內就讓你可以學會相關技術。Matthias Felleisen在他的著做 How to Design Program 一書中明確指出了這種「速成」的趨勢並予以了以上的諷刺。

所謂的「捷徑」或者說「銀彈」是不存在的,智者說過,精通某個東西須要10年或10000個小時,也就是漢語中的「十年磨一劍」,因此不用着急,功不唐捐。

培養興趣

Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program.

– Linus Torvalds

沉醉於編程,編程更是爲了興趣。興趣是推進力的不竭源泉,保持這種充滿興趣的感受,以便於你能將其投入到你的10年/10000小時的編程時間中。編程頗有趣,那是探索的喜悅。那是創造的喜悅。看到本身親手完成的做品顯示在屏幕上頗有趣。有人爲你的代碼而驚歎頗有趣。有人在公共場合稱讚你的產品、鄰居使用你的產品、以及在媒體上討論你的產品頗有趣。編程應該十分有趣,若並不是如此,就找出致使編程無趣的問題,而後解決之。

開始學習

使人警醒的故事

剛上初中時我便開始了編程學習,很不幸,我讀完了好幾本當時廣泛存在的諸如《21天精通C++》這類的垃圾書,當時讀完也無大礙,甚至還能寫點小程序。可是軟件出故障了我不知道爲何,稍顯龐大的編程問題無從下手,碰到現有的庫作不到的事也只能兩手一攤。雖然我天天不停地編碼,但我發現本身的編程能力倒是提升的如此緩慢,對於「迭代」與「遞歸」的概念只有極其有限的瞭解,能夠說只是把計算機當成了計算器來使用。

進入大學後,我主修了物理學,最初的一段時間裏我一直在記憶背誦那些物理公式,卻不理解她們是如何得出的,她們之間有什麼聯繫,亦或是她們的意義。我不停地學習如何計算解答一些常見的物理問題,卻對在這些Hows背後的Whys一無所知。

而在我嘗試作一些基於物理行爲的電腦遊戲時我再次遇到了以前的的困難:面對新問題時無從下手,面對新問題時的恐懼不斷累積滋生,我開始主動逃避,不去真正地理解,而是幻想能經過Google搜索複製粘貼代碼解決問題。幸運的是,大二時的一堂課徹底改變了個人學習方法。那是第一次我有了「開天眼」的感受,我痛苦地意識到,我對一些學科只有少的可憐的真正的理解,包括我主修的物理與輔修的計算機科學。

關於那堂課:那時咱們剛剛學習完電學和狹義相對論的內容,教授在黑板上寫下了這兩個主題,並畫了一根線將他們連了起來。「假設咱們有一個電子沿導線以相對論級別的速度移動…」,一開始教授只是寫下了那些咱們所熟悉的電學與狹義相對論的常見公式,但在數個黑板的代數推導後,磁場的公式神奇的出現了。雖然幾年前我早已知道這個公式,但那時我根本不知道這些現象間的有着這樣潛在的聯繫。磁與電之間的差異只是「觀察角度」的問題,我猛然醒悟,此後我再也不僅僅追求怎麼作(How),我開始問爲何(why),開始回過頭來,**拾起那些最基礎的部分**,學習那些我以前我本該好好學的知識。這個回頭的過程是痛苦的,但願大家能就此警醒,永遠不要作這種傻事。

警醒後的反思

這幅圖取自 Douglas Hofstadter 的著做 Gödel, Escher, Bach 。圖中的每個字母都由其餘更小的字母組成。在最高層級,咱們看的是"MU",M這個字母由三個HOLISM(總體論)構成,U則是由一個REDUCTIONISM(還原論)構成,前者的每個字母都包含後者的後者整個詞,反之亦然。而在最低層級,你會發現最小的字母又是由重複的"MU"組成的。 每一層次的抽象都蘊含着信息,若是你只是幼稚地單一運用總體論在最高層級觀察,或運用還原論觀察最低層級,你所獲得的只有"MU"(在一些地區的方言中mu意味着什麼都沒有)。問題來了,怎樣才能儘量多的獲取每一個層級的信息?或者換句話說,該怎樣學習複雜領域(諸如編程)包含的衆多知識?

教育與學習過程當中廣泛存在一個關鍵問題:初學者們的目標常常過於傾向總體論而忽略了基礎,舉個常見的例子,學生們很是想作一個機器人,卻對背後的

理解物理模型→理解電子工程基礎→理解伺服系統與傳感器→讓機器人動起來

這一過程徹底提不起興趣。

在這裏對於初學者有兩個大坑。 1. 若是初學者們只與預先構建好的「發動機和組件」接觸(沒有理解和思考它們構造的原理),這會嚴重限制他們在未來構建這些東西的能力,而且在診斷解決問題時無從下手。 2. 第二個坑沒有第一個那麼明顯:幼稚的「總體論」方法有些時候會顯得頗有效,這有必定的隱蔽性與誤導性,可是一兩年事後(也許沒那麼長),當你在學習路上走遠時,再想回過頭來「補足基礎」會有巨大的心理障礙,你得拋棄以前本身狹隘的觀念,耐心地緩步前進,這比你初學時學習基礎知識困可貴多。

但也不能矯枉過正,陷入還原論的大坑,初學時便一心試圖作宏大的理論,這樣不只有一切流於理論的危險,枯燥和乏味還會讓你失去推進力。這種狀況常常發生在計算機科班生身上。

爲了更好理解,能夠將學習編程類比爲學習廚藝:你爲了燒得一手好菜買了一些關於菜譜的書,若是你只是想爲家人作菜,這會是一個不錯的主意,你重複菜譜上的步驟也能作出不賴的菜餚,可是若是你有更大的野心,真的想在朋友面前露一手,作一些獨一無二的美味佳餚,甚至成爲「大廚」,你必須理解這些菜譜背後大師的想法,理解其中的理論,而不只僅是一味地實踐。可是若是你天天惟一的工做就是閱讀那些厚重的理論書籍,由於缺少實踐,你只會成爲一個糟糕的廚子,甚至永遠成爲不了廚子,由於看了幾天書後你就由於枯燥放棄了廚藝的學習。

總之,編程是鏈接理論與實踐的紐帶,是計算機科學與計算機應用技術相交融的領域。正確的編程學習方法應該是:經過自頂而下的探索與項目實踐,得到編程直覺與推進力;從自底向上的打基礎過程當中,得到最重要的通用方法並鞏固編程思想的理解。

做爲初學者,應以**後者爲主,前者爲輔**。

啓蒙

「學編程應該學哪門語言?」這常常是初學者問的第一個問題,但這是一個錯誤的問題,你最早考慮的問題應該是「**哪些工具**將構成編程學習的基礎」?

編程知識的金字塔底部有三個關鍵的部分:

  • 算法思想:例如怎樣得出一組數中最大的那個數?首先你得有一個maxSoFar變量,以後對於每一個數…
  • 語法:我怎樣用某種編程語言表達這些算法,讓計算機可以理解?
  • 系統基礎:爲何 while(1) 時線程永遠沒法結束?爲何
    int *foo() 
    { 
        int x = 0; 
        return &x; 
    }

    是不可行的?

啓蒙階段的初學者若選擇C語言做爲第一門語言會很困難而且枯燥,這是由於他們被迫要同時學習這三個部分,在能作出東西前要花費不少時間。

所以,爲了儘可能最小化「語法」與「系統基礎」這兩部分,建議使用 Python 做爲學習的第一門語言,雖然Python對初學者很友好,但這並不意味着它只是一個「玩具」,在大型項目中你也能見到它強大而靈活的身影。熟悉Python後,學習C語言是即是一個不錯的選擇了:學習C語言會幫助你以靠近底層的視角思考問題,而且在後期幫助你理解操做系統層級的一些原理,若是你只想成爲一個普通(平庸)的開發者你能夠不學習它。

下面給出了一個可供參考的啓蒙階段導引,完成後你會在頭腦中構建起一個計算機科學的總體框架,幫助你進行自頂向下的探索。

  1. 完成 Codecademy 的Python部分。這只是熱身部分,**儘快完成它**,由於你永遠只是在瀏覽器裏,你不會學到如何搭建開發環境。在Codecademy這類的編程學習網站學到的那點兒東西,哪怕你只想作一個小的不能再小的項目,你都不知道該從哪兒開始。
  2. 完成 MIT計算機導論課(若是你英語不過關:麻省理工學院公開課:計算機科學及編程導論)。MOOC 是學習編程的一個有效途徑。雖然該課程的教學語言爲Python,但做爲一門優秀的導論課,它強調學習計算機科學領域裏的重要概念和範式,而不只僅是教你特定的語言。若是你不是科班生,這能讓你在自學時開闊眼界;課程內容:計算概念,python編程語言,一些簡單的數據結構與算法,測試與調試。支線任務:
    1. 完成 Python核心編程
  3. 完成 Harvard CS50 (若是你英語不過關:哈佛大學公開課:計算機科學CS50)。一樣是導論課,但與MIT的導論課互補。教學語言涉及 C, PHP, JavaScript + SQL, HTML + CSS,內容的廣度與深度十分合理,還可以瞭解到最新的一些科技成果,能夠很好激發學習計算機的興趣。支線任務:
    1. 閱讀《編碼的奧祕》
    2. 完成《C語言編程》
    3. [可選] 若是你的目標是成爲一名 Hacker:閱讀 Hacker's Delight

PS:若是教育對象仍是一個孩子,如下的資源會頗有幫助(標註年齡供參考):

入門

結束啓蒙階段後,初學者積累了必定的代碼量,對編程也有了必定的瞭解。這時你可能想去學一門具體的技術,諸如Web開發,Android開發,iOS開發什麼的,你能夠去嘗試作一些儘量簡單的東西,給本身一些正反饋,補充本身的推進力。**但記住別深刻**,這些技術有無數的細節,未來會有時間去學習;一樣的,這時候也別過於深刻特定的框架和語言,如今是學習計算機**科學**通用基礎知識的時候,不要試圖去抄近路直接學你如今想學的東西,這是註定會失敗的。

那麼入門階段具體該作些什麼呢?這時候你須要作的是反思本身曾經寫過的程序,去思考程序爲何(Why)要這樣設計?,思考怎樣(How)寫出更好的程序?試圖去探尋理解編程的本質:利用計算機**解決問題**。 設想 : X = 用於思考解決問題的辦法的時間,即「解決問題「部分 Y = 用於實現代碼的時間,即「利用計算機」這一部分」 編程能力 = F(X,Y) (X>Y)

要想提升編程能力,就得提高改進 X,Y 與函數 F(X,Y),不多有書的內容能同時着重集中在這三點上,但有一本書作到了—— Structure and Interpretation of Computer Programs(SICP)《計算機程序的構造和解釋》,它爲你指明瞭提高這三個變量的方向。在閱讀SICP以前,你也許能經過調用幾個函數解決一個簡單問題。但閱讀完SICP以後,你會學會如何將問題抽象而且分解,從而處理更復雜更龐大的問題,這是編程能力巨大的飛躍,這會在本質上改變你思考問題以及用代碼解決問題的方式。此外,SICP的教學語言爲Scheme,可讓你初步瞭解函數式編程。更重要的是,他的語法十分簡單,你能夠很快學會它,從而把更多的時間用於學習書中的編程思想以及複雜問題的解決之道上。

Peter Norvig曾經寫過一篇很是精彩的SICP書評 ,其中有這樣一段:

To use an analogy, if SICP were about automobiles, it would be for the person who wants to know how cars work, how they are built, and how one might design fuel-efficient, safe, reliable vehicles for the 21st century. The people who hate SICP are the ones who just want to know how to drive their car on the highway, just like everyone else.

若是你是文中的前者,**閱讀SICP必將成爲你銜接啓蒙與入門階段的關鍵點**

雖然SICP是一本「入門書」,但對於初學者仍是有必定的難度,如下是一些十分有用的輔助資源:

完成了這部分學習後,你會逐步創建起一個本身的程序設計模型,你的腦子裏再也不是一團亂麻,你會意識到記住庫和語法並不會教你如何解決編程問題,接下來要學些什麼,在你內心也會明朗了不少。**這時候纔是真正開始進行項目實踐,補充推進力的好時機**。關於項目實踐:對於入門階段的初學者,參與開源項目還爲時過早,這時候應該開始一些簡單的項目,諸如搭建一個網站並維護它,或是編寫一個小遊戲再不斷進行擴展,若是你本身的想法不明確,能夠從 Mega Project List 中選取項目。總之,務必在這時拿下你項目實踐的第一滴血。

若是你以爲SICP就是搞不定,也不要強迫本身,先跳過,繼續走常規路線:開始讀 The Elements of Computing Systems 吧,它會教會你從最基本的 Nand 門開始構建計算機,直到俄羅斯方塊在你的計算機上順利運行。 具體內容很少說了,這本書會貫穿你的整個編程入門階段,你入門階段的目標就是堅持完成這本書的全部項目(包括一個**最簡的**編譯器與操做系統)。

爲了徹底搞定這本書,爲了繼續打好根基。爲了未來的厚積薄發,在下面這幾個方面你還要作足功課(注意:下面的內容沒有絕對意義上的前後順序):

計算機系統基礎

有了以前程序設計的基礎後,想更加深刻地把握計算機科學的脈絡,不妨看看這本書:《深刻理解計算機系統》 ( Computer Systems A Programmer's Perspective 縮寫CSAPP)。這裏點名批評這本書的中譯名,其實根本談不上什麼深刻啦,這本書只是 CMU 的「計算機系統導論」的教材而已。CMU 的計算機科學專業相對較偏軟件,該書就是從一個程序員的視角觀察計算機系統,以「程序在計算機中如何執行」爲主線,全面闡述計算機系統內部實現的諸多細節。

若是你看書以爲有些枯燥的話,能夠跟一門 Coursera上的MOOC: The Hardware/Software Interface ,這門課的內容是 CSAPP 的一個子集,可是最經典的實驗部分都移植過來了。同時,能夠看看 The C Programming Language,回顧一下C語言的知識。

完成這本書後,你會具有堅實的系統基礎,也具備了學習操做系統,編譯器,計算機網絡等內容的先決條件。當學習更高級的系統內容時,翻閱一下此書的相應章節,同時編程實現其中的例子,必定會對書本上的理論具備更加感性的認識,真正作到經手的代碼,從上層設計到底層實現都瞭然於胸,並能在腦中回放數據在網絡->內存->緩存->CPU的流向。

此外,也是時候去接觸 UNIX 哲學了: KISS - Keep it Simple, Stupid. 在實踐中,這意味着你要開始熟悉命令行界面,配置文件。而且在開發中逐漸脫離以前使用的IDE,學會使用Vim或Emacs(或者最好二者都去嘗試)。

數據結構與算法基礎

現在,不少人認爲編程(特別是作web開發)的主要部分就是使用別人的代碼,可以用清晰簡明的方式表達本身的想法比掌握硬核的數學與算法技巧重要的多,數據結構排序函數二分搜索這不都內置了嗎?工做中永遠用不到,學算法有啥用啊?這種扛着實用主義大旗的「碼農」行爲固然不可取,沒有紮實的理論背景,遇到瓶頸是早晚的事。

數據結構和算法是配套的,入門階段你應該掌握的主要內容應該是:這個問題用什麼算法和數據結構能更快解決。這就要求你對常見的數據結構和算法了熟於心,你不必定要敲代碼,用紙手寫流程是更快的方式。對你不懂的數據結構和算法,你要去搜它主要拿來幹嗎的,使用場景是什麼。

供你參考的學習資源:

  • 《算法導論》:有人說別把這本書當入門書,這本書原本就不是入門書嘛,雖然說書名是 Introduction to Algorithms,這只不過是由於做者不想把這本書與其餘書搞重名罷了。固然,也不是沒辦法拿此書入門,讀第一遍的時候跳過習題和證實就好了嘛,若是還以爲心虛先看看這本數據結構與算法分析
  • Coursera Algorithms: Design and Analysis Part 1 & Part 2: Stanford開的算法課,不限定語言,兩個部分跟下來算法基礎基本就有了;英語沒過關的:麻省理工學院公開課:算法導論
  • 入門階段還要注意培養使用常規算法解決小規模問題的能力,結合以前前文的程序設計部分能夠讀讀這幾本書:《編程珠璣》《程序設計實踐》

編程語言基礎

Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut. Additionally, learning many languages is far easier now, thanks to the wealth of freely available software on the Internet

— The Pragmatic Programmer

此外還要知道,學習第n門編程語言的難度是第(n-1)門的一半,因此儘可能去嘗試不一樣的編程語言與編程範式,若你跟尋了前文的指引,你已經接觸了:「乾淨」的腳本語言Python, 傳統的命令式語言C, 以及浪漫的函數式語言Scheme/Racket 三個好朋友。但僅僅是接觸遠遠不夠,你還須要不斷繼續加深與他們的友誼,並嘗試結交新朋友,美而雅的 Ruby 小姑娘,Hindley-Milner 語言家族的掌中寶 Haskell 都是不錯的選擇。但有這麼一位你躲不開的,必須得認識的大夥伴 —— C++,你得作好與他深交的準備:

現實是殘酷的,在軟件工程領域仍舊充斥着一些狂熱者,他們只掌握着一種編程語言,也只想掌握一種語言,他們認爲本身掌握的這門語言是最好的,其餘異端都是傻X。這種人也不是無藥可救,有一種很簡單的治療方法:讓他們寫一個編譯器。要想真正理解編程語言,你必須親自實現一個。如今是入門階段,不要求你去上一門編譯器課程,但要求你能至少實現一個簡單的解釋器。

供你參考的學習資源:

  • 《程序設計語言-實踐之路》:CMU編程語言原理的教材,程序語言入門書,如今就能夠看,會極大擴展你的眼界,拉開你與普通人的差距。
  • Coursera 編程語言MOOC:課堂上你能接觸到極端FP(函數式)的SML,中性偏FP的Racket,以及極端OOP(面向對象)的Ruby,並學會問題的FP分解 vs OOP分解、ML的模式匹配、Lisp宏、不變性與可變性、解釋器的實現原理等,讓你在未來學習新語言時更加輕鬆並寫出更好的程序。
  • Udacity CS262 Programming Language:熱熱身,教你寫一個簡單的瀏覽器——其實就是一個javascript和html的解釋器,完成後的成品仍是頗有趣的;接下來,試着完成一個以前在SICP部分提到過的項目:用Python寫一個 Scheme Interpreter

其餘

編程入門階段比較容易忽視的幾點:

  1. 學好英語:英語是你獲取高質量學習資源的主要工具,但在入門階段,所看的那些翻譯書信息損耗也沒那麼嚴重,以你本身狀況權衡吧。此外英語的重要性更體如今溝通交流上,Linus Torvalds 一個芬蘭人,一口流利的英語一直是他招募開發者爲Linux幹活的的法寶,這是你的榜樣。
  2. 學會提問:學習中確定會遇到問題,首先應該學會搜索引擎的「高級搜索」,當單靠檢索沒法解決問題時,去 Stack Overflow 或知乎提問,提問前讀讀這篇文章:What have you tried?
  3. 不要作一匹獨狼:嘗試搭建一個像這樣簡單的我的網站,不要只是一個孤零零的About頁面,去學習 Markdown 與 LaTeX,試着在Blog上記錄本身的想法,並訂閱本身喜歡的編程類博客。推薦幾個供你參考:Joel on SoftwarePeter NorvigCoding Horror

小結

以上的內容你不該該感到害怕,編程的入門不是幾個星期就能完成的小項目。期間你還會遇到無數的困難,當你碰壁時試着嘗試「費曼」技巧:將難點分而化之,切成小知識塊,再逐個對付,以後經過向別人清楚地解說來檢驗本身是否真的理解。固然,依舊會有你解決不了的問題,這時候不要強迫本身——不少時候當你以後回過頭來再看這個問題時,一切豁然開朗。

此外不要侷限與上文提到的那些材料,還有一些值得在入門階段以及未來的提高階段反覆閱讀的書籍。*The Pragmatic Programmer* 就是這樣一本程序員入門書,終極書。有人稱這本書爲代碼小全:從DRY 到 KISS,從作人到作程序員,這本書教給了你一切,你所需的只是遵循書上的指導。

後記

若是你能設法完成以上的全部任務,恭喜你,你已經真正實現了編程入門。這意味着你在以後更深刻的學習中,不會畏懼那些學習新語言的任務,不會畏懼那些「複雜」的API,更不會畏懼學習具體的技術,甚至感受很容易。固然,爲了掌握這些東西你依舊須要大量的練習,腰仍是會疼,走路仍是會費勁,一口氣也上不了5樓。但我能保證你會在思想上有巨大的轉變,得到極大的自信,看老師同窗和CSDN的眼光會變得很是微妙,雖然只是完成了編程入門,但已經成爲了程序員精神世界的高富帥。不,我說錯了,即便是高富帥也不會有強力精神力,他也會懷疑本身,以爲本身沒錢就什麼都不是了。但總之,你遵循指南好好看書,那就會體驗「會當凌絕頂」的感受。

歡迎實踐過的同窗現身說法。

相關文章
相關標籤/搜索