2015-02-20

用十年自學編程

用十年自學編程
Teach Yourself Programming in Ten Years

Peter Norvig

為什麼大家要這麼急?
Why is everyone in such a rush?

走進任何書店,你可以找到像是24小時自學Java以及無數的類似書籍,在數天或是數小時內教你有關C, SQL, Ruby, 演算法, 等等類似的內容。你可以在亞馬遜書店的進階搜尋中搜尋關鍵字title: teach, yourself, hours, since: 2000並且找到512本相關的書籍。其中最前面的10到九本都是編程的書(其他是有關簿記的)。將關鍵字"自學Teach yourself"換成"學習learn"或是將"小時hour"換成"天day",你將會得到類似的結果。

結論是,要不是人們非常急於學習編程,不然就是編程本身比起其他任何東西來說都是超級無敵簡單。 Felleisen 等在他們的著書How to Design Programs中對這種趨勢下了個簡單的注解,他們說「要寫爛程式很簡單,白痴們可以在21天內學會,即是他們是傻瓜」。Abtruse Goose漫畫也對這個下了他們的注解

讓我們對來分析一下像是24小時自學C++(Teach Yourself C++ in 24 Hours之類的書籍標題可能具有的涵義:
  • 自學Teach Yourself: 在24小時之內你將不會有時間寫任何顯而易懂的程式,並且從中學到你的成功與失敗。 你將沒有機會與經驗老道的程式員一起工作並了解用C++開發環境來討生活是什麼樣的狀況。 總之,你沒有太多學習的時間。所以這本書紙會談到一些超級膚淺的內容,而不會有深度的理解。 就像Alexander Pope所說的,只學表面是件非常危險的事。
  • C++: 在24小時內,你也許可以學到C++的一些文法(如果你已經知道其他語言),但是關於如何使用這個語言,你無法學到更多。 總之,或說,如果你是個Basic的程式員,你可以學到如何用C++的文法編寫Basic風格的程式,但是你不會學到有關C++實際上是哪裡好(以及不好)。 所以重點是什麼呢?Alan Perlis說過:「一個不會影響你對編程的想法的語言,不值得去瞭解。」 一個可能的重點是,你必須學C++(或者其他常見的,像是JavaScript或是處理程序Processing)的一點皮毛,因為你需要藉由一個既存工具的介面來完成特定的工作。但是你不是在學習如何編程,你是在學習如何完成任務。
  • 24小時in 24 Hours: 不幸的是,那並不夠,就如同下一小節中所描述的一樣。

十年自學編程
Teach Yourself Programming in Ten Years

研究人員(Bloom (1985), Bryan & Harter (1899), Hayes (1989), Simmon & Chase (1973)) 指出,在任何不同的領域,包括西洋棋,編曲,電報操作,繪畫,鋼琴,游泳,網球,以及神經心理學與拓撲學等等,發展專長大約需要10年的時間。 關鍵在於審議式的(deliberative)練習:不是只有反覆的實作,而是要藉由超過你現有能力的任務來作自我挑戰,嘗試去實作,並在實作後分析你自己的能力,並且修正所有的錯誤。然後不斷的重複。似乎沒有真正的捷徑:即使是4歲時被稱作音樂神童的莫札特,在他開始作出世界頂尖的音樂之前也花了超過13年的歲月。在其他世代中,披頭四似乎在1964年Ed Sullivan的表演中突然嶄露頭角。但是他們早從1957年開始就在Livepool與Hamburg的小型俱樂部中表演,而他們真正大量出現並發行第一張超級成功的專輯Sgt. Peppers是在1967年。 Malcolm Gladwell的說法是,比起10年,他用10,000小時來堆砌他的成功。

也許10,000個小時才是魔法數字,而不是10年。或者它只是另一個不同的基準; Henri Cartier-Bresson (1908-2004) 說:「你的前10,000張相片會是你最爛的相片。」 真正的專長也許需要花上一生: Samuel Johnson (1709-1784)說:「任何部門的精英只能藉由終身勞動來達成;那無法用低廉的價錢購買。」 且Chaucer (1340-1400)抱怨說「人生太短,學習之路卻太長」。 Hippocrates (c. 400BC)有名的筆記裡寫到:「ars longa, vita brevis」, 而那是長篇短文「Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile」的一部分,譯為「人生太短,工藝之路太長,機會稍縱即逝,體驗苦澀,判斷困難。」 當然,最終的答案不會是只是個單純的數字:似乎沒有合理的假設,編程,下西洋棋,完跳棋,演奏音樂,他們都需要相當長的時間去成為大師,而且不是每個人所需要的時間都會一樣。

那你想要成為一個程式員
So You Want to be a Programmer

要在編程中成功,以下是我的菜單:
  • 對編程感興趣,且真正因為有趣而去做。確保它有足夠的樂趣,那麼你會願意在那上面花上你的10年/10,000小時。
  • 程式Program. 最佳的學習方法是從作中學(learning by doing)。更技術性的說法,「個體在某個給定的特定領域中的最高效能不會像經驗成長的一部分自動獲得,但是在經驗豐富的個體上效能水平可藉由刻意努力的結果而獲得均衡的提升。」(p. 366)還有「最有效率的學習,需要為個體提供良好定義的任務,伴隨著適合的難度等級,訊息回饋,以及複習與錯誤改正的機會。」(p20-21) Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life這本書提供了有關這個觀點的有趣的資料。
  • 與其他程式員交流; 閱讀別人的程式碼。這比起任何書或是訓練課程來的重要。
  • 如果你願意的話,進大學(或是更上一層的研究所)去學習。這將給你參與某些需要學歷的工作的機會,並對這個領域有更深層的理解。但是如果你不喜歡學校,(透過某些方法)你可以靠自己或是在工作中獲得類似的經驗。無論如何,光靠書本的知識是不夠的。 「計算機科學教育不會讓任何人成為頂尖程式員,就像學習筆刷跟顏料不會讓任何人成為頂尖的畫家一樣。」The New Hacker's Dictionary的作者Eric Raymond說到。 我曾經雇用的最好的程式員之一,他只有高中學歷;他創造了很多偉大軟體,擁有他自己的新聞群組,並且賺取了夠多的股票去買他自己的夜店
  • 與其他程式員一同作專案。在一些專案裡當最佳程式員;並在其他某些專案中當最爛的。當你是最佳程式員的時候,你必須測試你領導專案的能力,並且用你的眼光激勵其他人。 當你是最爛的程式員的時候,你學習主人的做法,並學習他們不喜歡作的部分(因為他們會讓你幫他們做那部份)。
  • 跟隨其他程式員作專案。 理解其他人所寫的程式。看看當原始作者不在的時候如何理解並修復它。想想要如何設計你的程式讓其他人在你之後易於維護。
  • 學習至少六種程式語言。 那其中包括一種強調類抽象class abstractions的語言(像是Java或C++), 一種強調函數抽象functional abstraction的語言(像是Lisp, ML, Haskell), 一種支援語法抽象syntactic abstraction的語言(像是Lisp), 一種支援聲明規格declarative specifiaction的語言(像是Prolog或C++模板), 以及一種強調並行處理parallelism的語言(像是Clojure或是Go)。
  • 請記得在「計算機科學」之中有「計算機」這個字眼。 理解你的電腦處理指令的時間,從記憶體獲取資料的時間(伴隨以及不伴隨快取失誤),從磁碟連續讀取資料的時間,以及在磁碟上搜尋新位址所需的時間。(答案在此)
  • 涉足一項語言標準化作業。它可以是ANSI C++委員會,也可以是決定在你的團隊中的編碼風格將有2個或是4個空白來進行縮排。不管是哪一種,你學到其他人在語言中喜歡的做法,還有他們的感受有多深,甚至有可能稍微瞭解為什麼他們覺得那樣之類的。
  • 要明確果斷,盡快脫離語言標準化作業

瞭解了上述的觀點,只藉由書本學習你能夠走多遠是十分可疑的。在我第一個孩子出生前,我讀過很多要如何做 How To的書,但是還是感覺自己是個手足無措的新手。30個月後當我第二個孩子出生時,我有重新把那些書拿來讀嗎?不。相反的,我遵照我個人的經驗,那更加有用,且比起專家寫的上千頁的書更讓我放心。
Fred Brooks在他的著作No Silver Bullet中提到了一個尋找優秀軟體設計師的三部曲計畫:
  1. 有系統的尋找頂尖設計師,越早越好。
  2. 指定一個職業導師負責前景發展,並仔細地規劃職業生涯。
  3. 為設計師提供成長的機會,讓他們彼此互動與刺激。
前提是有些人已經有成為優秀設計師的素質;而工作只是引導他們正確的前進。 Alan Perlis用說得更簡潔:「任何人都可以被教導如何去雕刻:米開朗基羅也被教導過什麼是不該做的。優秀的程式員也沒有不同。」 Perlis說,優秀的人們擁有內在的素質,那超越了他們的訓練。但是那素質是從哪來的?那是與生俱來的嗎?或是他們藉由努力而開發的呢?Auguste Gusteau(Ratatouille中虛構的大廚)下了這樣的注解:「任何人都可以下廚,但只有無畏者才會偉大。」 我覺得那有一大部分是源自一個人是否願意奉獻其生命中極大部分去做審議實踐。但是無畏也許是個總結的方法。 又或者,就像Gusteau的評論家Anton Ego說的:「不是任何人都可以成為優秀的藝術家,但是優秀的藝術家可以從任何地方而來。」

所以,儘管去買那些Java/Ruby/JavaScript/PHP的書;你將也許從中知道一些用法。但是你將不會改變你的生活,或是你的作為程式員的整體專業知識在24小時或是21天內。但是如果你持續努力改善超過24個月後呢?好吧,該是你從某處開始努力的時候了...

資源 References

Bloom, Benjamin (ed.) Developing Talent in Young People, Ballantine, 1985.
Brooks, Fred, No Silver Bullets, IEEE Computer, vol. 20, no. 4, 1987, p. 10-19.
Bryan, W.L. & Harter, N. "Studies on the telegraphic language: The acquisition of a hierarchy of habits. Psychology Review, 1899, 8, 345-375
Hayes, John R., Complete Problem Solver Lawrence Erlbaum, 1989.
Chase, William G. & Simon, Herbert A. "Perception in Chess" Cognitive Psychology, 1973, 4, 55-81.
Lave, Jean, Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life, Cambridge University Press, 1988.

答案Answers



典型個人電腦上各種操作的大約時間:
典型指令之執行
execute typical instruction
1/1,000,000,000 sec = 1 nanosec
從L1快取獲取資料
fetch from L1 cache memory
0.5 nanosec
分歧預測失誤
branch misprediction
5 nanosec
從L2快取獲取資料
fetch from L2 cache memory
7 nanosec
互斥鎖定/解鎖
Mutex lock/unlock
25 nanosec
從主記憶體獲取資料
fetch from main memory
100 nanosec
從1Gbps頻寬的網路傳送2K bytes資料
send 2K bytes over 1Gbps network
20,000 nanosec
從記憶體循序讀取1MB資料
read 1MB sequentially from memory
250,000 nanosec
取得新磁碟位址(搜尋)
fetch from new disk location (seek)
8,000,000 nanosec
從磁碟循序讀取1MB資料
read 1MB sequentially from disk
20,000,000 nanosec
將封包從美國送到歐洲再傳回
send packet US to Europe and back
150 milliseconds = 150,000,000 nanosec


附錄:言語選擇
Appendix: Language Choice

有些人會問,他們應該從哪個程式語言開始學習。這並沒有固定答案,但是可以考慮以下幾個標準:

  • 利用你的朋友Use your friends。 當被問到「我該用哪個作業系統呢? Windows, Unix, 還是Mac?」,我的回答通常是「用你朋友用的那個」。 向你朋友學習的好處將會在不同OS或是不同程式語言間的固有問題上被抵銷掉。 同時,考慮那些你未來會結交的朋友:程式員社群,如果你持續下去的話,你將會是他們的一部分。 你所選擇的語言是否擁有一個大型成長中的社群,還是他擁有的是一個小型且逐漸萎縮的社群?是否有書籍,網站,以及線上討論區可以得到答案? 你是否喜歡那些討論區中的人們?
  • 維持簡單Keep it simple。 像C++與Java之類的程式語言,設計給那些經驗老道的程式員所組成的大型團隊作專業開發,那些人關心他們的程式碼的執行時期效率。 結論上來說,這些語言會擁有一些為了達成這些目標而設計的複雜部分。你應該關心在學習程式上。你不需要那些複雜的部分。你需要一個語言設計便於單一新手程式員學習與記憶。
  • 玩 Play. 一樣是學彈鋼琴,你會比較喜歡哪種方法?一般,互動的方法,那這種方法之中你可以聽到每個音符,就當你壓下琴鍵之後馬上;或是"批量"模式,在那種方法中你只能在完成整首歌之後才能聽到音符。很明顯的,互動模式會讓鋼琴易於學習,而寫程式也是一樣。堅持使用一個擁有互動模式的語言。

鑑於這些標準,我建議第一個程式語言可以用Python或是Scheme。 其他的選擇是JavaScript,不是因為它是完全為初心者精心設計,而是因為它有大量的線上教學,像是可汗學院的教學 Khan Academy's tutorial。 但是你的情況可能會有所不同,而且還有其他不錯的選擇。 如果你的年紀還只有一位數,你可能會比較喜歡愛麗絲Alice 或是Squeak 或是Blockly(有點年紀的學習者也可能會喜歡他們)。重點是你已經選好了一個,並著手開始。


附錄:書籍與其他資源
Appendix: Books and Other Resources

有些人要求我建議一些學習用的書與網頁。我會重複我的論調「只看書是不夠的」,但是我可以建議以下的資源:




筆記 Notes

  1. T. Capey指出亞馬遜書店上的完全問題解決者 Complete Problem Solver一頁現在有"21天自學孟加拉Teach Yourself Bengali in 21 days"與"自學文法與風格Teach Yourself Grammar and Style"在「購買此商品的人同時也買了這些商品」的欄位中。我猜有一大部分的人是從這個網頁找到那本書的。
  2. 感謝Ross Cohen幫忙有關Hippocrates的部分。



原始內容是由Peter Norvig前輩的網站上轉譯而來
原始網址於此:(blog)http://www.yamdas.org/column/technique/21-daysj.html

原本的網站上有各國翻譯的連結。但很不巧的,中文的連結失效了。
於是我參照了日文翻譯與原文重製了我自己的翻譯版本。
希望對有需要或是想參考的各位有所幫助。
Updated: 2015/02/20

GoogleCode-Prettify

SyntaxHighlighter

人気の投稿