~.~Joel Spolsky
如今的孩子變懶了。
多吃一點苦,又會怎么樣呢?
我一定是變老了,才會這樣喋喋不休地這樣抱怨和感嘆“如今地孩子”,不理解為什么他們不再同意,或者說不再能夠做艱苦地工作。
當我還是孩子地時候,學習編程需要用到穿孔卡片(punched card)。那時可沒有任何類似“退格”鍵(Backspace key)這樣地現(xiàn)代化功能,如果你出錯了,就沒有辦法更正,只好扔掉錯地卡片,從頭再來。
回想1991年我開始面試程序員地時候。我一般會出一些編程題,允許用任何編程語言解題。在99%地情況下,面試者選者C語言。
如今,面試者一般會選者Java語言。
說到這里,不要誤會我的意思。作為開發(fā)工具,Java語言本身并沒有什么錯。
等一等,我要做個更正。我只是在本書特定地環(huán)境中不會提到作為一種開發(fā)工具Java語言有什么不好地地方。事實上,它有許許多多不好地地方,不過這些只有另找時間來談了。
我在這里真正想要說的是,總體來看,Java不是一種非常難的編程語言,無法用來區(qū)分優(yōu)秀程序員和普通程序員。它可能很適合用來完成工作,但是這個不是我今天的主題。我甚至想說,Java語言不夠難其實是它的特色,不能算缺點。但是不管怎樣,它就是有這個問題。
如果我聽上去像妄下論斷,那么我想說一點兒我自己微不足道的經(jīng)歷。大學計算機系的課程歷有兩個傳統(tǒng)的知識點,但許多人從來都沒有真正搞懂過,那就是指針(pointer)和遞歸(recursion)。
你進大學后,一開始總要上一門“數(shù)據(jù)結(jié)構(gòu)”課,然后會有鏈表 散列表以及其他諸如此類的課程。這些課會大量使用“指針”,并且經(jīng)常起到一種優(yōu)勝劣汰的作用。因為這些課程非常難,學不會就表明學生的能力不足以達到計算機科學學士學位的要求,這些學生只能選擇放棄這個專業(yè)。這是一件好事,因為如果你連指針都覺得很難,那么等學到后面要你證明不動點定理(fixed point theory)的時候,你該怎么辦呢?
有些孩子讀高中的時候就能用Basic語言在Apple II型個人電腦上寫漂亮的乓(Pong)游戲。等他們進了大學都會去選修計算機科學101課程,那門課講的就是數(shù)據(jù)結(jié)構(gòu)。當他們接觸到指針那些玩意以后,就一下子完全傻眼了,后面的事情你都可以想象:他們就去改學政治學,因為看上去法學院是一個更好的出路。關(guān)于計算機系的淘汰率,我見過各式各樣的數(shù)字,通常在40%到70%之間。校方一般會覺得學生拿不到學位很可惜,我則視其為必要的篩選,淘汰那些沒有興趣編程或者沒有能力編程的人。
對于許多計算機系的青年學生來說,另一門有難度的課程是有關(guān)函數(shù)式編程(functional programming)的,其中就包括遞歸程序設(shè)計(recursive programming)。麻省理工學院將這些課程的標準提得很高,還專門設(shè)立了一門必修課(6.001),它的教材(Stucture and Interpretation of Computer Programs,作者為Harold Abelson等,中文版書名為《計算機程序的構(gòu)造和解釋》)被幾百所高校的計算機系采用,充當事實上的計算機科學導論課程。(你能在網(wǎng)上找到這門課程的視頻,應(yīng)該看一下){http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/}。
這些課程難得驚人。在第一堂課,你就要學完Scheme語言的幾乎所有內(nèi)容,(Scheme語言是Lisp語言的一個變種,業(yè)內(nèi)人士都稱為Lisp的方言。于1975年誕生于麻省理工學院,以其對函數(shù)式編程的支持而聞名。)你還會遇到一個不動點函數(shù),它的參數(shù)本身就是另一個函數(shù)。我讀的這門導論課式賓夕法尼亞大學的CSE121課程,真是讀得苦不堪言。我注意到很多學生(也許式大部分的學生)都無法完成這門課。課程的內(nèi)容實在太難了。我給教授寫了一封長長的聲淚俱下的Email,控訴這門課不是給人學的。賓夕法尼亞大學里一定有人聽到了我的呼聲(或者聽到了其他抱怨者的呼聲)。因為如今這門課講授的計算機語言是Java。
我現(xiàn)在覺得,他們還不如沒有聽見呢!
這就是爭議所在。許多年來,像當年的我一樣懶惰的計算機系本科生不停地抱怨,再加上計算機業(yè)界也在抱怨畢業(yè)生不夠用,這一切終于造成了重大惡果。過去十年中,大量本來堪稱完美地學校,都百分百轉(zhuǎn)向了Java語言地懷抱。這真是好的沒話說了,那些用grep命令(UNIX/Linux環(huán)境中用于搜索或者過濾內(nèi)容地命令。)過濾簡歷地企業(yè)招聘主管,大概會很喜歡這樣。最妙不可言的是,Java語言中沒有什么太難的地方,不會真地淘汰什么人,你搞不懂指針或者遞歸頁沒關(guān)系。所以,計算機系地淘汰率就降低了,學生人數(shù)上升了,經(jīng)費預算變大了,可謂皆大歡喜。
學習Java語言餓孩子是幸運地,因為當他們用到以指針為基礎(chǔ)的散列表時,他們永遠也不會遇到古怪的“段錯誤”(segfault是segmentation fault的縮寫){指的是軟件中的一類特定錯誤,通常發(fā)生在程序試圖讀取不允許讀取的內(nèi)存地址或者以非法方式讀取內(nèi)存的時候。}他們永遠不會因為無法將數(shù)據(jù)塞進有限的內(nèi)存空間而急得發(fā)瘋,他們也永遠不用苦苦思索,為什么在一個純函數(shù)的程序中,一個變量的值一會兒保持不變,一會兒又變個不停!多么自相矛盾??!
他們不需要怎么動腦筋就可以在專業(yè)課上得到4.0的成績。
我是不是有點太苛刻了?就像電視里的“四個約克郡男人”{《四個約克郡男人》(Four Yorkshiremen)是英國電視系列喜劇At last the 1948 Show中的一部,于20世紀70年代播出。內(nèi)容是四個約克郡男人競相吹噓各自的童年是多么困苦。由于內(nèi)容太夸張,所以顯得非??尚?。}那樣,成了老古板?就知道在這里吹噓我是多么刻苦,完成了所有那些高難度的課程?
我再告訴你一件事。1900年的時候,拉丁語和希臘語都是大學里必修課,原因不是因為它們有什么特別作用,而是因為它們有點被看成是受過高等教育的人士的標志。在某種程度上,我的觀點同拉丁語支持者的觀點沒有不同(下面的四點理由都是如此):“(拉丁語)訓練你的思維,鍛煉你的記憶。分析拉丁語的句法結(jié)構(gòu)是思維能力的最佳練習,是真正對智力的挑戰(zhàn),能夠很好地培養(yǎng)邏輯能力?!币陨铣鲎許cott Barker之口(http://www.promotelatin.org/whylatin.htm)。但是,今天我找不到一所大學還把拉丁語作為必修課。指針和遞歸不正像計算機科學中地拉丁語和希臘語嗎?
說到這里,我坦率地承認,當今地軟件代碼中90%都不需要使用指針。事實上,如果在正是產(chǎn)品中使用指針。這將是非常危險地。好的,這一點沒有異議。與此同時,函數(shù)式編程在實際開發(fā)中用到地也不多。這一點我也同意。
但是,對于某些最激動人心地編程任務(wù)來說,指針仍然是非常重要地。比如說,如果不用指針,你根本沒辦法開發(fā)Linux地內(nèi)核。如果你不是真正地理解了指針,你連一行Linux的代碼頁看不懂,說實話,任何操作系統(tǒng)的代碼你都看不懂。
如果你不懂函數(shù)式編程,你就無法創(chuàng)造出MapReduce(是一種由Goolge引入使用的軟件框架,用于支持計算機集群環(huán)境下海量數(shù)據(jù)PB級別的并行計算。),正是這種算法使得Google的可擴展性(scalable)達到如此巨大的規(guī)模。術(shù)語“Map”(映射)和“Reduce”(化簡)分別來自Lisp語言和函數(shù)式編程?;叵肫饋?,在類似6.001這樣的編程課程中,都提到純粹的函數(shù)式編程沒有副作用,因此可以直接用于并行計算。任何人只要還記得這些內(nèi)容,那么MapReduce對他來說就是顯而易見的。發(fā)明MapReduce的公司是谷歌,而不是微軟,這個簡單的事實說出了原因,為什么微軟至今還在追趕,還在試圖提供最基本的搜索服務(wù),而谷歌已經(jīng)轉(zhuǎn)向了下一階段,開發(fā)Skynet,我的意思是,開發(fā)世界上最大的并行式超級計算機。我覺得,微軟并沒有完全明白在這波競爭中它落后了多遠。
除了上面那些直接就能看到的重要性,指針和遞歸的真正價值在于那種你在學習它們的過程中所得到的思維深度,以及你因為害怕在這些課程中被淘汰所產(chǎn)生的心理抗壓能力,它們都是在建造大型系統(tǒng)的過程中必不可少的。指針和遞歸要求一定水平的推理能力 抽象思考能力,以及最重要的,在若干個不同的抽象層次上同時審視同一個問題的能力。因此,是否真正理解指針和遞歸與是否是一個優(yōu)秀程序員直接相關(guān)。
如果計算機系的課程都與Java語言有關(guān),那么對于那些在智力上無法應(yīng)付復雜概念的學生而言,就沒有東西可以真地淘汰他們。作為一個雇主,我發(fā)現(xiàn)那些100%Java教學的計算機系已經(jīng)培養(yǎng)出了相當一大批畢業(yè)生,這些學生只能勉強完成難度日益降低的課程作業(yè),只會用Java語言編寫簡單的記帳程序,如果你讓他們編寫一個更難的東西,他們就束手無策了。他們的智力不足以成為程序員。這些學生永遠頁通不過麻省理工學院的6.001課程,或者耶魯大學的CS 323課程。坦率地說,為什么在一個雇主的心目中,麻省理工學院或者耶魯大學計算機系的學位的份量要重于杜克大學的,這就是原因之一。因為杜克大學最近已經(jīng)全部轉(zhuǎn)為用Java語言教學。賓夕法尼亞大學的情況也很類似,當初CSE 121課程中的Scheme語言和ML語言幾乎將我和我的同學折磨致死,如今已經(jīng)全部被Java語言代替。我的意思不是說我不想雇用來自杜克大學或者賓夕法尼亞大學的聰明學生,我真地愿意雇用他們,只是對于我來說,確定他們是否真地聰明如今變得難多了。以前,我能夠分辨出誰是聰明學生,因為他們可以在一分鐘內(nèi)看懂一個遞歸算法,或者可以迅速在計算機上實現(xiàn)一個線性鏈表操作函數(shù),所用的時間同在黑板上寫一遍這個函數(shù)差不多。但是對于在學校只學Java語言的畢業(yè)生,看著他們面對上述問題苦苦思索卻做不出來的樣子,我分辨不出這到底是因為學校里沒教,還是因為他們不具備編寫優(yōu)秀軟件的素質(zhì)。Paul Graham(Steve Soong(宋易峰)強烈建議讀一讀他的一本叫《黑客和畫家》的書,很不錯喲?。⑦@一類程序員稱為“Blub程序員”{Blub程序員(Blub programmers)指的是那些企圖用一種語言解決所有問題的程序員。Blub是Paul Graham假設(shè)的一種高級編程語言}[www.pualgraham.com/avg.htm]
大學里只教Java語言,無法淘汰那些永遠也成不了優(yōu)秀程序員的學生,這已經(jīng)是很糟糕的事情了。但是,學??梢詿o可厚非地辯解,這不是校方地錯。整個軟件行業(yè),或者說至少是其中那些用grep命令過濾簡歷地招聘經(jīng)理,確實是在一直叫嚷,要求學校使用Java語言教學。
但是,即使如此,學校地教學也還是失敗地,因為學校沒有成功訓練好學生地頭腦,沒有使他們變得足夠熟練 敏捷 靈活,能夠做出高質(zhì)量地軟件設(shè)計。(我不是指面向?qū)ο笫降摹霸O(shè)計”,那種編程只不過式要求你花上無數(shù)個小時重寫你的代碼,使它們能夠滿足面向?qū)ο缶幊痰牡燃壷评^承式結(jié)構(gòu),或者說要求你思考到對象之間的式“has-a”從屬關(guān)系,還是“is-a”繼承關(guān)系,這種“偽命題”將你搞得煩躁不安。)你需要的式那種能夠在多個抽象層次上同時思考問題的訓練。這種思維能力正是設(shè)計出優(yōu)秀軟件架構(gòu)所必需的。
你也許想知道,在教學中OOP(Obiect-Oriented Programming,面向?qū)ο缶幊蹋┦欠袷侵羔樅瓦f歸的優(yōu)質(zhì)替代品,是不是也能起到淘汰作用。簡單回答是“不”。我在這里不討論OOP的優(yōu)點,我只指出OOP不夠難,無法淘汰平庸的程序員。大多數(shù)時候,OOP教學的主要內(nèi)容就是記住一堆專有名詞,比如“封裝”(encapsulation)和“繼承”(inheritance),然后在做一堆多選題小測驗,考你是不是明白“多態(tài)”(polymorphism)和“重載”(overloading)的區(qū)別。這同歷史課上要求你記住重要的日期和人名的難度差不多。OOP不構(gòu)成堆智力的太大挑戰(zhàn),嚇不跑一年級新生。據(jù)說,如果你沒學好OOP,你的程序依然可以運行,只是維護起來有點難。但是如果你沒學好指針,然后你只好停下來,深呼一口,真正開始努力在兩個不同的抽象層次上同時思考你的程序是如何運行的。
順便說一句,我有充分理由在這里說,那些使用grep命令過濾簡歷的招聘經(jīng)理真是荒謬可笑。我從來沒有見過哪個能用Scheme語言 Haskell語言和C語言中的指針編程的人,竟然不會在兩天里面學會Java語言,并且寫出的Java語言的質(zhì)量竟然不能勝過那些有5年Java編程經(jīng)驗的人士。不過,是無法指望人力資源部里那些平庸的懶漢聽進去這些話的。
再說,計算機系承擔的發(fā)揚光大計算機科學餓使命該怎么辦呢?計算機系畢竟不是職業(yè)學校?。∮柧殞W生如何在這個行業(yè)里工作不應(yīng)該是計算機系的任務(wù),這應(yīng)該是社區(qū)高校和政府就業(yè)培訓計劃的任務(wù),那些地方會教給你工作技能。計算機系給予學生的理應(yīng)是他們?nèi)蘸笊钏枰幕A(chǔ)知識,而不是為學生第一周上班做準備。對不對?
還有,計算機科學是由證明(遞歸)、算法(遞歸)、語言(入演算)、操作系統(tǒng)(指針)、編譯器(入演算)所組成的,所以說那些不教C語言 、不教Scheme語言 、只教Java語言的學校實際上根本不是在教授計算機科學。雖然對于真實世界來說,有些概念可能毫無用處,比如函數(shù)的科里化(function currying指的是一種多元函數(shù)的消元技巧,將其變?yōu)橐幌盗兄挥幸辉逆準胶瘮?shù)。它最早是由美國數(shù)學家哈斯格爾 科里 Haskell Curry 提出的,因此而得名。)但是這些知識顯然是進入計算機科學研究生院的前提。我不明白,計算機系課程設(shè)置委員會中的教授為什么會同意將課程的難度下降到如此低的地步,以至于他們既無法培養(yǎng)出合格的程序員,甚至無法培養(yǎng)出合格的能夠得到哲學博士學位 進而能夠申請教職 與他們競爭工作崗位餓研究員。噢,且慢,我說錯了。也許我明白原因了。
實際上,如果你回顧和學術(shù)界在“Java大遷移(Great Java Shift)中的爭論,你會注意到,最大的議題是Java語言是否還不夠簡單,不適合作為一種教學語言。
我的老天啊,我心里說,他們還在設(shè)法讓課程變得更簡單。為什么不干脆用匙子把所有東西一勺勺都喂到學生嘴里呢?讓我們再請助教幫他們接管考試,這樣一來就沒有會該學“美國研究”了(是對美國社會的經(jīng)濟 歷史 文化等各個方面進行研究的一門學科。這里指的是,計算機系學生不會因為課程太難被淘汰,所以就不用改學相對容易的“美國研究”)。如果課程被精心設(shè)計,使得所有內(nèi)容都比原有內(nèi)容更容易,那么怎么可能期望任何人從這個地方學到任何東西呢?看上去似乎有一個工作小組(Java task force)正在開展工作,創(chuàng)造出一個簡化的文檔,小心地不讓學生纖弱的思想接觸到任何EJB/J2EE的臟東西。這樣一來,學生的小腦袋就不會因為遇到有點難度的課程而感到煩惱了,除非那門課里只要求做一些空前簡單的計算機習題。
計算機系如此積極地降低課程難度,有一個最善意地解釋,那就是節(jié)省出更多地時間去教授真正屬于計算機科學地概念。但是,前提是不能花費整整兩節(jié)課向?qū)W生講解如Java語言中int和Integer有何區(qū)別。好的,如果真是這樣,課程6.001就是你地完美選擇。你可以先講Scheme語言,這種教學語言簡單到聰明學生大約只用10分鐘就能全部學會地程度。然后,你將這個學期剩下的時間都用來講解不動點。
誒。
說了半天,我還是在說要學1和0.
(你是1?真幸運??!我們那時所有人得到的都是0。)
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。