Peter Norvig:十年學會程式設計

無痕幽雨發表於2018-06-21

出處:http://norvig.com/21-days.html

為啥都想速成?

隨便逛一下書店,你會看到《7天自學Java》等諸如此類的N天甚至N小時學習Visual Basic、Windows、Internet的書。我用亞馬遜網站的搜尋功能,出版年份選1992年以後,書名關鍵詞是:“天”、“自學”、“教你”,查到248個結果,前78個是計算機類圖書,第79個是《30天學孟加拉語》。我用“天”換成“小時”,結果更驚人,有多達253本書,前77本是計算機圖書,第78是《24小時自學語法句式》。在前200名中,96%是計算機的書。

結論就是:要麼人們急於學習電腦,要麼計算機比其他東西學起來要異常簡單。沒有任何書是關於幾天學習貝多芬或量子物理的,甚至連犬類裝扮都沒有。費雷森(Felleisen)等人在其著作《如何設計程式》中同意這個趨勢,其中提到:“壞設計很簡單,笨蛋才用21天學,儘管他們還是真傻。”

讓我們看看《三日學會C++》這個書名意味著什麼:

◇學習:
三天內你可能沒有時間寫出有意義的程式,或者從中積累經驗。你不可能有時間去跟職業程式設計者一起去理解在C++環境下的狀況。簡而言之,你沒有充足的時間學很多。所以這本書只能說膚淺的知識。正如亞歷山大·波普(Alexander Pope)所言:一知半解是很危險的。

◇C++:
三天內你可能學會C++的句法(如果你已經瞭解其他的語言),但你還不會使用它。打個比方,假如你是個Basic程式設計師,你可能寫出Basic風格的C++程式,而無法理解C++的真實好處。那要點是什麼?艾倫·佩里斯(Alan Perlis)曾經說過:“一門不能影響你程式設計觀點的語言不足學的。”有可能你學了一點點C++(或者諸如Javascript、Flex之類),因為你需要和現成的工具介面以完成手頭的任務。這種情況下,你不是在學習如何程式設計,只是在學習如何完成任務。

◇三日:
不幸地是,這遠遠不夠,下一部分會詳細講。

如何用十年掌握程式設計

研究人員(Bloom (1985), Bryan & Harter (1899), Hayes (1989), Simmon & Chase (1973))得出結論:想要在諸多領域達到職業水平需要十年,比如國際象棋,作曲,電報操作,繪畫,彈鋼琴,游泳,網球以及神經心理學和拓撲學的研究。關鍵是精心練習,只是一遍一遍地重複是不夠的,必須挑戰恰好超越你能限的事情,嘗試並思考你的表現,並自我矯正。周而復始。這並無捷徑!4歲的音樂奇才莫扎特用了13年才能創作世界級的音樂。另外,披頭士樂隊似乎在1964年的埃德·蘇利文( Ed Sullivan show)演出中一炮而紅,但是他們自從1957年就在利物浦和漢堡的酒吧演出,在取得廣泛關注後,第一部重量級作品《佩珀軍士》(Sgt. Peppers)是在1967年發行。馬爾科姆·格拉德威爾(Malcolm Gladwell)撰文描述了一項針對柏林音樂學院學生的研究,他們被分為尖子,中等和不足三類,並被問到他們練琴的情況:
所有三組中的人,開始學琴的年齡大概相差無幾,五歲左右。在剛開始的幾年,所有人練習量也差不多,一週兩三個小時。自八歲開始,實質性變化就有了。那些精英學生開始比其他人練習更多:九歲的時候一週六個小時,十二歲的時候一週八個小時,十四歲的時候一週十六個小時,一直到二十歲的時候一週要超過三十小時。截止到二十歲,在他們的生涯裡已經有總計一萬小時練琴。僅僅表現可以的那部分學生加起來是八千小時,那些未來的音樂老師有四千小時。

所以,更確切地說,一萬小時,而非十年,是個神奇之數。薩繆爾·約翰遜(Samuel Johnson, 1709-1784)認為還需更長時間:“卓越乃一生之追求,而非其它”。 喬叟(Chaucer, 1340-1400)抱怨道"the lyf so short, the craft so long to lerne." (生之有限,學也無涯)。希波克拉底(Hippocrates, c. 400BC)因這句話被世人所知:"ars longa, vita brevis"(譯註:拉丁語,意為“藝無盡,生有涯”),更長的版本是 "Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile",翻譯成英文就是 "Life is short, (the) craft long, opportunity fleeting, experiment treacherous, judgment difficult." (生有涯,藝無盡,機遇瞬逝,踐行誤導,決斷不易)。

我的程式設計成功祕笈是:

◇首先要對程式設計感興趣,能從程式設計中得到樂趣。一定要讓它足夠有趣,因為你要保持你的興趣長達十年。

◇與別的程式設計師交流;閱讀別人的程式碼——這比看任何書或參加培訓課都重要。

◇實踐。最好的學習乃實踐。俗話說:“程式設計的至高境界一定要通過充分的實踐才能達到,而個人的能力可通過不懈努力獲得顯著提升。” (p. 366) “最有效率的學習需要明確的目標,適當的難度,知識回饋,並容許重複或修正錯誤。” (p. 20-21) 《實踐認知:每日的思維、數學及文化》(Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life) 在這方面可做參考。

◇如果你願意,花四年學習大學課程(或者再加上讀研)。這將給你贏得某些工作機會,並給予你在該領域的深層見解。但如果你不喜歡學校的學習,你同樣可以在工作中獲得相似的經驗。無論如何,單靠書本是遠遠不夠的。“學習電腦科學不會讓你成為程式設計專家,如同學習繪畫和色彩理論不會讓你成為畫家一樣”。這是埃裡克·雷蒙德(Eric Raymond)說的,他是《新黑客字典》(The New Hacker's Dictionary)的作者。我僱用過的最優秀程式設計師,只有高中文憑。但他開發過許多偉大軟體,有自己的新聞組,通過公司認股賺的錢就讓他買下了自己的夜店。

◇和其他程式設計師一起參與工程專案。在某些專案中擔當最優秀程式設計師,在另一些專案中充當最差勁程式設計師。充當領頭羊的時候,你要測試你領導一項工程的能力,並用你的視野來激發他人;如果在專案組中墊底,就應該學習其它牛人在做些啥,以及他們不喜歡做的(看他們把哪些活讓給你做)。

◇繼續別人的工程專案。去理解先前程式設計師寫的程式。學習如何理解並解決先前程式設計師沒有考慮到的問題。思考你的程式該如何設計以便讓之後的程式設計師更容易維護。

◇至少學6種程式語言。其中包括一種支援類抽象的(Java和C++),一種支援函式抽象的(如Lisp或ML),一種支援語義抽象的(Lisp),一種支援宣告規範的(如Prolog或C++模板),還有一種支援協程的(Icon或Scheme),另外一種支援併發的(Sisal)。

◇記住,在“電腦科學”裡有“計算機”一詞。理解計算機執行你的程式碼的時候花費的時間。比如:從記憶體中取一個字(考慮有無快取未命中情形),連續從磁碟讀字,或者在磁碟中定位。

◇參加語言標準化工作。這可能是有關 ANSI C++ 委員會,也可能是決定你編碼風格是兩格縮排或四格縮排。無論如何,你要知道其他人對語言的喜好程度,有時還要想想他們為什麼喜歡這樣。

◇知道自己應該在何時脫身於語言標準化

所有上述這些,很難通過書本的學習來達到。我頭一個孩子出生時,我讀了所有的“如何做”(How To)系列的書籍,卻依然對育嬰毫無頭緒。30個月後,我第二個孩子出生,我還需要溫習一下那些書嗎?絕對不!相反,我完全可以參照個人經驗,而結果相當有效。這更讓我確信:我的經驗勝過那些專家們寫的上千頁文字。

弗雷德·布魯克斯(Fred Brooks)在《沒有銀彈》(No Silver Bullet)一書給出了尋找頂級設計師的三條建議:
◇儘早系統地識別出頂級設計師。
◇分配一個人作為其職業規劃的導師。
◇給予機遇讓成長中的設計師互相磨礪。

此處假定有部分人已經有成為偉大設計師的潛質,你所需的就是要誘導他們。艾倫·佩里斯(Alan Perlis)一針見血地指出:"假如人人都可以學雕刻,那就得教米開朗基羅如何不去幹雕刻。對於偉大程式設計師,也是如此。”

所以,簡單地買一本Java書,你或許能找到些有用的東西,但絕不會讓你在24小時內甚至24天抑或24月內,成為行家裡手。


Teach Yourself Programming in Ten Years

Peter Norvig

Why is everyone in such a rush?

Walk into any bookstore, and you'll see how to Teach Yourself Java in 24 Hours alongside endless variations offering to teach C, SQL, Ruby, Algorithms, and so on in a few days or hours. The Amazon advanced search for [title: teach, yourself, hours, since: 2000 and found 512 such books. Of the top ten, nine are programming books (the other is about bookkeeping). Similar results come from replacing "teach yourself" with "learn" or "hours" with "days."

The conclusion is that either people are in a big rush to learn about programming, or that programming is somehow fabulously easier to learn than anything else. Felleisen et al. give a nod to this trend in their book How to Design Programs, when they say "Bad programming is easy. Idiots can learn it in 21 days, even if they are dummies." The Abtruse Goose comic also had their take.

Let's analyze what a title like Teach Yourself C++ in 24 Hours could mean:

  • Teach Yourself: In 24 hours you won't have time to write several significant programs, and learn from your successes and failures with them. You won't have time to work with an experienced programmer and understand what it is like to live in a C++ environment. In short, you won't have time to learn much. So the book can only be talking about a superficial familiarity, not a deep understanding. As Alexander Pope said, a little learning is a dangerous thing.

  • C++: In 24 hours you might be able to learn some of the syntax of C++ (if you already know another language), but you couldn't learn much about how to use the language. In short, if you were, say, a Basic programmer, you could learn to write programs in the style of Basic using C++ syntax, but you couldn't learn what C++ is actually good (and bad) for. So what's the point? Alan Perlis once said: "A language that doesn't affect the way you think about programming, is not worth knowing". One possible point is that you have to learn a tiny bit of C++ (or more likely, something like JavaScript or Processing) because you need to interface with an existing tool to accomplish a specific task. But then you're not learning how to program; you're learning to accomplish that task.

  • in 24 Hours: Unfortunately, this is not enough, as the next section shows.

Teach Yourself Programming in Ten Years

Researchers (Bloom (1985)Bryan & Harter (1899)Hayes (1989)Simmon & Chase (1973)) have shown it takes about ten years to develop expertise in any of a wide variety of areas, including chess playing, music composition, telegraph operation, painting, piano playing, swimming, tennis, and research in neuropsychology and topology. The key is deliberative practice: not just doing it again and again, but challenging yourself with a task that is just beyond your current ability, trying it, analyzing your performance while and after doing it, and correcting any mistakes. Then repeat. And repeat again. There appear to be no real shortcuts: even Mozart, who was a musical prodigy at age 4, took 13 more years before he began to produce world-class music. In another genre, the Beatles seemed to burst onto the scene with a string of #1 hits and an appearance on the Ed Sullivan show in 1964. But they had been playing small clubs in Liverpool and Hamburg since 1957, and while they had mass appeal early on, their first great critical success, Sgt. Peppers, was released in 1967.

Malcolm Gladwell has popularized the idea, although he concentrates on 10,000 hours, not 10 years. Henri Cartier-Bresson (1908-2004) had another metric: "Your first 10,000 photographs are your worst." (He didn't anticipate that with digital cameras, some people can reach that mark in a week.) True expertise may take a lifetime: Samuel Johnson (1709-1784) said "Excellence in any department can be attained only by the labor of a lifetime; it is not to be purchased at a lesser price." And Chaucer (1340-1400) complained "the lyf so short, the craft so long to lerne." Hippocrates (c. 400BC) is known for the excerpt "ars longa, vita brevis", which is part of the longer quotation "Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile", which in English renders as "Life is short, [the] craft long, opportunity fleeting, experiment treacherous, judgment difficult." Of course, no single number can be the final answer: it doesn't seem reasonable to assume that all skills (e.g., programming, chess playing, checkers playing, and music playing) could all require exactly the same amount of time to master, nor that all people will take exactly the same amount of time. As Prof. K. Anders Ericssonputs it, "In most domains it's remarkable how much time even the most talented individuals need in order to reach the highest levels of performance. The 10,000 hour number just gives you a sense that we're talking years of 10 to 20 hours a week which those who some people would argue are the most innately talented individuals still need to get to the highest level."

So You Want to be a Programmer

Here's my recipe for programming success:

  • Get interested in programming, and do some because it is fun. Make sure that it keeps being enough fun so that you will be willing to put in your ten years/10,000 hours.

  • Program. The best kind of learning is learning by doing. To put it more technically, "the maximal level of performance for individuals in a given domain is not attained automatically as a function of extended experience, but the level of performance can be increased even by highly experienced individuals as a result of deliberate efforts to improve." (p. 366) and "the most effective learning requires a well-defined task with an appropriate difficulty level for the particular individual, informative feedback, and opportunities for repetition and corrections of errors." (p. 20-21) The book Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life is an interesting reference for this viewpoint.

  • Talk with other programmers; read other programs. This is more important than any book or training course.

  • If you want, put in four years at a college (or more at a graduate school). This will give you access to some jobs that require credentials, and it will give you a deeper understanding of the field, but if you don't enjoy school, you can (with some dedication) get similar experience on your own or on the job. In any case, book learning alone won't be enough. "Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter" says Eric Raymond, author of The New Hacker's Dictionary. One of the best programmers I ever hired had only a High School degree; he's produced a lot of great software, has his own news group, and made enough in stock options to buy his own nightclub.

  • Work on projects with other programmers. Be the best programmer on some projects; be the worst on some others. When you're the best, you get to test your abilities to lead a project, and to inspire others with your vision. When you're the worst, you learn what the masters do, and you learn what they don't like to do (because they make you do it for them).

  • Work on projects after other programmers. Understand a program written by someone else. See what it takes to understand and fix it when the original programmers are not around. Think about how to design your programs to make it easier for those who will maintain them after you.

  • Learn at least a half dozen programming languages. Include one language that emphasizes class abstractions (like Java or C++), one that emphasizes functional abstraction (like Lisp or ML or Haskell), one that supports syntactic abstraction (like Lisp), one that supports declarative specifications (like Prolog or C++ templates), and one that emphasizes parallelism (like Clojure or Go).

  • Remember that there is a "computer" in "computer science". Know how long it takes your computer to execute an instruction, fetch a word from memory (with and without a cache miss), read consecutive words from disk, and seek to a new location on disk. (Answers here.)

  • Get involved in a language standardization effort. It could be the ANSI C++ committee, or it could be deciding if your local coding style will have 2 or 4 space indentation levels. Either way, you learn about what other people like in a language, how deeply they feel so, and perhaps even a little about why they feel so.

  • Have the good sense to get off the language standardization effort as quickly as possible.
With all that in mind, its questionable how far you can get just by book learning. Before my first child was born, I read all the How To books, and still felt like a clueless novice. 30 Months later, when my second child was due, did I go back to the books for a refresher? No. Instead, I relied on my personal experience, which turned out to be far more useful and reassuring to me than the thousands of pages written by experts.

Fred Brooks, in his essay No Silver Bullet identified a three-part plan for finding great software designers:

  1. Systematically identify top designers as early as possible.

  2. Assign a career mentor to be responsible for the development of the prospect and carefully keep a career file.

  3. Provide opportunities for growing designers to interact and stimulate each other.

This assumes that some people already have the qualities necessary for being a great designer; the job is to properly coax them along. Alan Perlis put it more succinctly: "Everyone can be taught to sculpt: Michelangelo would have had to be taught how not to. So it is with the great programmers". Perlis is saying that the greats have some internal quality that transcends their training. But where does the quality come from? Is it innate? Or do they develop it through diligence? As Auguste Gusteau (the fictional chef inRatatouille) puts it, "anyone can cook, but only the fearless can be great." I think of it more as willingness to devote a large portion of one's life to deliberative practice. But maybe fearless is a way to summarize that. Or, as Gusteau's critic, Anton Ego, says: "Not everyone can become a great artist, but a great artist can come from anywhere."

So go ahead and buy that Java/Ruby/Javascript/PHP book; you'll probably get some use out of it. But you won't change your life, or your real overall expertise as a programmer in 24 hours or 21 days. How about working hard to continually improve over 24 months? Well, now you're starting to get somewhere...


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

Approximate timing for various operations on a typical PC:
execute typical instruction1/1,000,000,000 sec = 1 nanosec
fetch from L1 cache memory0.5 nanosec
branch misprediction5 nanosec
fetch from L2 cache memory7 nanosec
Mutex lock/unlock25 nanosec
fetch from main memory100 nanosec
send 2K bytes over 1Gbps network20,000 nanosec
read 1MB sequentially from memory250,000 nanosec
fetch from new disk location (seek)8,000,000 nanosec
read 1MB sequentially from disk20,000,000 nanosec
send packet US to Europe and back150 milliseconds = 150,000,000 nanosec

Appendix: Language Choice

Several people have asked what programming language they should learn first. There is no one answer, but consider these points:

  • Use your friends. When asked "what operating system should I use, Windows, Unix, or Mac?", my answer is usually: "use whatever your friends use." The advantage you get from learning from your friends will offset any intrinsic difference between OS, or between programming languages. Also consider your future friends: the community of programmers that you will be a part of if you continue. Does your chosen language have a large growing community or a small dying one? Are there books, web sites, and online forums to get answers from? Do you like the people in those forums?
  • Keep it simple. Programming languages such as C++ and Java are designed for professional development by large teams of experienced programmers who are concerned about the run-time efficiency of their code. As a result, these languages have complicated parts designed for these circumstances. You're concerned with learning to program. You don't need that complication. You want a language that was designed to be easy to learn and remember by a single new programmer.
  • Play. Which way would you rather learn to play the piano: the normal, interactive way, in which you hear each note as soon as you hit a key, or "batch" mode, in which you only hear the notes after you finish a whole song? Clearly, interactive mode makes learning easier for the piano, and also for programming. Insist on a language with an interactive mode and use it.
Given these criteria, my recommendations for a first programming language would be Python or Scheme. Another choice is Javascript, not because it is perfectly well-designed for beginners, but because there are so many online tutorials for it, such as Khan Academy's tutorial. But your circumstances may vary, and there are other good choices. If your age is a single-digit, you might prefer Alice or Squeak or Blockly (older learners might also enjoy these). The important thing is that you choose and get started.

Appendix: Books and Other Resources

Several people have asked what books and web pages they should learn from. I repeat that "book learning alone won't be enough" but I can recommend the following:


Notes

T. Capey points out that the Complete Problem Solver page on Amazon now has the "Teach Yourself Bengali in 21 days" and "Teach Yourself Grammar and Style" books under the "Customers who shopped for this item also shopped for these items" section. I guess that a large portion of the people who look at that book are coming from this page. Thanks to Ross Cohen for help with Hippocrates.

相關文章