《程式設計師的吶喊》讀書筆記

程式碼灣發表於2017-12-13

程式設計師的吶喊》是Google一位老程式設計師的經驗總結,文中展現了他對各大語言如Java、C/C++、Lisp、Python、Ruby、Perl等的極端觀點,比如大力吐槽C++,極力推崇C、Lisp、Ruby。他的觀點只是他個人經驗所得,也不一定符合實情,僅供參考,有任何想法都可以說出來一起討論。

>>>>

1、程式設計師和司機一樣,總是自我安慰說等到需要的時候再去學新技能也來得及。但是在內心深處他們都明白,其實當需求出現的時候就已經太晚了。因此現實情況是這樣的,旱鴨子會和水保持距離,司機會繞開泥濘的路段,而程式設計師會躲在舒適區裡,搭建圍欄把自己保護起來,然後祈禱世界和平。

me:其實喜歡躲在舒適區裡是每個人都或多或少存在的性格弱點,誰能克服它誰就能學到新技能,誰就能站的比別人高。對於偶爾努力經常懶惰的我來說,技術也是學的廣而不精,對新技術都有興趣但學不到精深處,希望剛工作的我可以改善這個弱點。

2、當時04年亞馬遜正飽受其龐大程式碼庫的困擾,我曾經一度認為它的程式碼庫失控是因為語言問題,後來才意識到企業文化是主因。首當其衝的是,亞馬遜的主流語言裡有兩門非常哆嗦的語言C++中和Java,外加一門精練的語言Perl。但是Perl正受到排擠,漸漸退出主流。我覺得這是因為Perl程式設計師能用更少的人力完成和Java/C++程式設計師同樣的工作量,所以要是比人多的話,他們註定是贏不了的。根據我們的估算,亞馬遜的程式碼量比它的功能數量膨脹得更快。第二個因素是,亞馬遜的很多技術問題完全可以用自定義領域語言(DSL的方式來解決),比如大規模的查詢、分散式計算、產品配置等,他們寫了太多不必要的程式碼了。我後來跳到Google,發現他們為這些完全一樣的問題專門編寫了強大的自定義DSL。這證實了我心中的疑慮,亞馬遜的工程師在這些問題上和無頭蒼蠅沒什麼兩樣。我敢說這句話誤傷的概率極低。最後一點就是,和絕大多數公司一樣,亞馬遜非常抗拒用新語言來解決問題。他們會避免使用表達能力更強的通用語言,比如Ruby或Erlang。他們也幾乎從來不會想到自己去寫DSL。

me:龐大程式碼庫是很多公司都有的弊病吧,可又有多少能想到用DSL來解決呢。害怕變動、拒絕新技術的公司註定是失敗的。

3、為什麼C是必修課?
一個原因是現在的電腦都是馮諾·伊曼結構的,而C以精悍的語法展現了馮·諾伊曼機的能力,其他型別的機器也是存在的,比如Lisp機。還有一個原因就是,Unix是用C寫的,不僅如此,包括Windows等在內的幾乎所有的作業系統都是用C寫成的,因為它們全部屬於馮諾伊曼機作業系統。你覺得自己還有其他選擇嗎?至少在作業系統領域裡,任何與C迥異的語言都發揮不出硬體的實際能力,至少這句話放在近一百年裡都是對的這些系統都誕生於這段時期內。

4、計算機程式語言裡沒有所謂的“親近生侮謾“,只有在掌握更優秀的語言前提下,才會懂得怎麼批判自己最熟悉的那門語言。因此,要是你不喜歡我批評C++,我建議你去了解一下更優秀的語言是什麼樣子的,然後你才有資格否定我的話。不過到那時你就不會來否定我了,我忽悠成功了。那時你不會再喜歡C++,可能會有點生我的氣,忽悠你討厭自己之前最愛的語言。所以你還是別管我說什麼了。C++很出色,非常優秀。別在意我的話。它是門很棒的語言。

me:作者是有多麼討厭C++啊!“親近生侮謾“的意思是當你對一個人或事物越親近越熟悉,你就會越討厭越忽視TA。而作者認為計算機語言裡不會發生這種事情,除非你知道了其它更優秀的語言。我贊同這個觀點。

5、亞馬遜的偉大元老們只用兩種語言:C和Lisp。顯然,他們都是Emacs的擁躉。

me:的確很多程式設計界的大佬都愛這兩門語言,比如《黑客與畫家》的作者。

6、傑米·扎溫斯基曾經寫過一篇非常有名的文章來批判Java有多糟糕,但他還是這樣寫道:“先說好的地方:Java沒有free(),我必須承認這一點,其他錦上添花而已。光這一點就足以讓我忽視其他缺點了,不管它們有多糟糕。有鑑於此,本文接下來的內容都可以說無足輕重。”傑米的這篇文章寫於1997年,那時的Java還在襁褓之中,如今Java早已今非昔比,他當時抱怨的有些東西現在都已經修復了。但也不是全都改好了。就語言層面,Java仍然算不上優秀。但正如傑米所言,它“依然是今天最好的語言,遠遠比我們在實際工作中用的那些徹頭徹尾的垃圾語言要好得多”。不過Java也缺了一些C++的優點,比如(在棧上)傳引用、typedef,巨集,還有過載操作符。這些東西並非必不可少,但是需要的時候就很方便。對了還有多重繼承,說得我都開始懷念從前了。假如你要用我自己的“固執己見的精靈”來反對多型,那麼我還可以舉出更多為什麼多重繼承是必需的例子。有時間我們可以討論一下“火焰劍”或者“盜賊披風”的問題,你就會明白介面是多糟糕的東西了。幾年前,高斯林自己也承認,要是有機會重來的話,絕對不會考慮介面。而這正是Java的問題所在。

me:Java好在垃圾自動回收,壞在臃腫不堪,語言本身設計的不好。

7、總之,Ruby對Perl充分實行了拿來主義。Ruby的作者Matz(我沒記錯的話,他的本名是松本行弘,不過通常都自稱“Matz”)甚至可能有點借鑑過頭了,連些不好的東西也拿了過來。好在不多,只有一點點而已。基本上Ruby照搬了Perl的字串處理和Unⅸ整合,語法完全一樣,只此一點,Perl的精華就全都有了。這可以說是開了個去蕪存菁的好頭。接著Matz從Lisp那裡吸收了列表處理的精華,從Smalltalk那裡拿來了OO,迭代器則是取自CLU,基本上各個語言裡的優點都吸收進來了。所有的這些東西被完美地糅合在一起,你壓根注意不到斧鑿的痕跡。

me:Ruby本質上就是各種語言精華的大雜燴,去蕪存菁,作者精通這麼多語言的精華非常值得敬佩。現在的框架也是的,都是互相之間借鑑精華,按需索取,無可厚非。

8、Python本來是有機會一統江湖的,但是它有兩個致命的缺陷:一個是空白符,另一個是死腦筋。所謂空白符的問題就是Python的巢狀是通過縮排來完成的。它強迫你用特定的方式來縮排,這樣大家的程式碼看起來就是一樣的了。可惜,很多程式設計師都討厭這個規定,感覺好像被剝奪了自由一樣;他們覺得胡亂排版和和編寫那種精簡到一行沒人看得懂的小程式是自己的權利,而Python卻侵犯了這一點。Python之父吉多·範羅蘇姆之前也出過幾次昏招,雖然不如拉里那麼驚世駭俗,但也真的是夠小兒科的了。比如,Python原本是沒有詞法作用域的。可問題是它連動態作用域也沒有,雖然說動態作用域也有自身的問題,但至少還勉強可以用。Python最早只有全域性和區域性(函式)作用域,所以雖然它擁有一個“真正的OO系統,可是—個類卻連自己的例項變數都沒法訪問。你只能給每個例項方法帶上一個self引數,然後通過self來訪問自己的例項資料。所以你在Python裡看到一堆self ,哪怕你忍了空白符,這些self也能把你給逼瘋了。

me:用空格縮排的確讓人不爽,不過提升了規範性。

9、Java 其中特點之一就是凸顯了“架構”。Java國王授予了架構尊崇的地位,因為架構完全是由名片語成的。我們都知道,名詞就是事物,而在Java裡,事物的地位遠勝一切動作。建築是由看得見摸得著的事物構成的,譬如高聳入雲的龐然大物,又如用棍子敲打時發出低沉悅耳聲音的東西。Java國王特別喜歡這種沉悶的聲音,每次換新馬車的時候,他都特別喜歡從踢輪子中獲得快感。不管上述的兒歌有何瑕疵,它就是不想要任何東西。
me:的確,Java最讓人受不了的就是一堆架構,一層層封裝致死,除錯起來也麻煩。

10、福勒告訴我們所謂重構,就是通過迭代,將噁心的程式碼變成優質程式碼的藝術和科學,是能妝點程式碼卻不會在操作過程中產生破壞的演算法,而且正確性都是能證明的。

me:作者認為福勒寫的重構這本書非常不錯,值得一讀。

11、那麼這些程式碼一開始是怎麼變爛的呢?首先當然是由於過早優化造成的,為了避免重複計算而儲存了太多的中間變數。因為害怕方法呼叫會造成虛幻的負擔,而刻意迴避編寫短小的函式。我們還弄出一大堆類的繼承關係,僅僅是為了想象中可能存在的複用,為了避免分配器物件而弄出一個巨大的引數列表。濫用null,把它當成成具有語義的符號。放任簡單的布林邏輯表示式變成錯綜複雜、無法閱讀的漿糊。不用訪問方法來封裝資料結構。還有其他很多亂七八糟的問題。正是因為各種各樣的小錯誤別類,加以命名,並歸類成嚴重錯誤。

me:這是福勒重構這本書告訴我們的。

12、那我們的程式碼是怎麼變成那樣的呢?因為寫得爛。這時重構就能救命。再優秀的設計也會出紕漏,但我們仍然可以補救,反正有自動化的奴僕來幫我們修復這些:小問題。它們不知疲倦,我們只要點個按鈕就行了。既然如此,誰能離得開自動化重構工具?還有誰能協調Java那些數以百計的小腿,讓它們像毛毛蟲一樣統一行動呢?讓我來告訴你答案:Ruby是蝴蝶。(意指Ruby是完全不同的物種,Java中自動化重構工具所要解決的問題在Ruby中根本不存在。)

me:作者喜歡Ruby,覺得Java需要重構是因為程式碼寫的爛,要是用Ruby寫的話根本不需要重構,也就沒有自動化重構工具。

13、首先,再垃圾的語言和技術也一樣有機會贏。甚至贏面可能還會大一點,因為改正起來會更快。Java擊敗了smalltalk , C++擊敗了Object-C,Perl擊敗了Python,VHS擊敗了Beta,諸如此類。並不是說一項技術(特別是程式語言)比較優秀,它就一定會勝出。營銷才是關關鍵。追求公平競爭只會導致你的語言無人問可津。

me:原來一門語言的流行起關鍵作用的不是這門語言有多優秀,而是它的營銷做的有多好。嗯,我記得Java就是營銷搞起來的。

14、注意,罵誰也不能罵Python。相反,罵Ruby罵得最凶的人可能就是Matz自己了。他在自己的演講“為什麼Ruby很爛”裡,自陳了Ruby的各種問題,當時看得我汗都下來了。不可否認,任何語言都有缺點。相比之下,我更喜歡Ruby眾的坦誠,Pyhon那種一味指責別人,迴避問題,過分地自我標榜的行為令人感到噁心。

me:作者的意思是Python眾狂妄自大,而Ruby相對比較坦誠,這是作者通過經過逛兩個社群得出的結論,也不一定準確。

15、Ruby談不上有多出色,但它現在手上有殺手級應用。Rails對推動Ruby起到了巨大的作用。在Web框架方面,Python可謂輸得一敗塗地。號稱要和Rails競爭的Python框架至少有五個:Pylons、Django、TurboGears、Zope,還有Subway。其實3個(甚至4個)都嫌多啊。從營銷的角度來講底哪個比較優秀其實根本不重要,重要的是Python社群應該選中其中一個後全力鼓吹;否則每個框架都只只能分到20%,結果誰都沒有實力跟上Rails的步伐。
me:再一次吐槽Python在web框架方面的不足,話說Python有殺手級應用嗎?

16、Java並沒有提出什麼新鮮的東西,它有的SmallTalk早就有了。

me:這種論點好像在哪裡聽過。

17、相反我卻親眼見識了日本服務生為了滿足那些在商務旅行中的醉漢所作出的努力,他們的敬業程度讓我這個美國人都感到羞愧。如果要問世界級的服務水平是什麼樣的,來日本看看就明白了。

me:真的嗎?真的嗎?繼續學日語,好去日本玩……

18、最終讓Java平臺佔領了那些它做夢也沒想到過的領域,一切都虧了這個所謂的“殺手級應用”Applet。

me:不會吧???沒聽說過Applet這麼厲害,一直覺得它是雞肋。

4

程式設計師需要了解的是哪些數學分支?

1、實際生活中,電腦科學家常用的數學和上面那個列表幾乎沒有重疊。其一,小學和中學裡教的絕大部分數學都是連續的,也就是實數上的數學。而對電腦科學家來說,95%有趣的數學都是離散的,也就是整數上的數學。

me:程式設計師所要解決的數學問題一般都是離散數學,其中最有用的課程應該就是組合數學和概率論統計。

2、除了概率論和離散數學,其他數學分支也是有助於程式設計師的。可惜除非你去輔修數學,否則學校是不會教你的。它們包含了:
(1) 統計。我的離散數學書裡講到了一點。但是統計是一門完整的學科,而且是非常重要的學科,重要到根本不需要額外介紹。
(2)代數和線性代數(比如矩陣)。線性代數應該緊跟在代數後面教。它不是很難,而且在很多領域都非常非常有用,比如機器學習。
(3)數理邏輯。
(4)資訊理論和柯氏複雜度。資訊理論(粗略地講)主要是關於資料壓縮的,而柯氏複雜度(同樣粗略地講)則是關於演算法的複雜度(比如最小空間是多少,需要多長時間,程式或者資料結構有多優雅等)的。它們都是好玩,有趣,實用的學科。
當然還有其他的分支,而且有些學科互有重疊。但重點在於:對你有用的數學和學校覺得有用的數學是非常不同的。

3、微積分的本質就是連續一變化的速度,曲線下的面積,固體的體積。很有用,記憶和很多煩瑣的步驟程式設計師通常不需要這些東西。知道大致概但是需要大量的概念和技巧就可以了,細節方面等到需要的時候再查也來得及。

5

編譯器,你懂嗎?

1、我在招人的時候有一個訣竅。就是在尋找優秀的軟體工程師“通才”的時候,通常在簡歷上你可以看到到各種讓你覺得不行的關鍵字和詞,但“編譯器”是我唯一感興趣的詞。

me:作者強烈要求程式設計師學編譯器原理,你還記得嗎?

2、編譯器會接收一串符號流,根據預先定義好的規則,分析出這串符號的結構,然後把它轉換成另一串符號流。是不是很籠統?的確是。一幅圖片能不能被當成是符號流?當然可以。它可以是每一行畫素所組成的流。每個畫素就是一個數字。每個數字就是一個符號。編譯器當然可以轉換圖片。英語可以被當做符號流叫嗎?當然可以。規則或許會很複雜,但是自然語言處理的確可以被看成是某種很炫的編譯。

編譯過程中第一個大階段就是解析,即把輸入的內容變成一棵樹。中間要經過預處理,詞法分析(也叫單詞化)然後是語法分析和中間程式碼生成這幾個步驟。詞法分析通常是由正規表示式來完成的。語法分析則是根據語法完成。你可以採遞迴向下(最常見)或是解析器生成器(在小語言中比較常見)或是更炫的算來實現,只不過相應的執行速度也會慢一點。無論如何,最後的結果通常都是某解析樹。
第二個大階段是型別檢查。這是一群狂熱的學術分子(包括他們的組織以及或者手下的研究生)他們自信可以寫出非常聰明的程式,能分析出你的程式想幹什麼,並且在你出錯的時候幫你指出。不過奇怪的是,他們並不覺得自己是在研究人工智慧畢竟人工智慧界已經(明智地)放棄確定性的方法了。
第三個陣營是程式碼生成,他們通常都被邊緣化了。只要你對遞迴有足夠的瞭解,知道自己的祖先不是亞當和夏娃,那麼程式碼生成還是挺直觀的。這裡要講的其實是優化就是那種生成足夠正確的程式碼,讓絕大多數使用者都意識不到有問題的藝術。等等不好意思,這是亞馬遜化。優化是指根據你那些昂貴的菜鳥程式設計師寫出來的垃圾程式碼生成“正確”程式碼的藝術。

6

保守派和自由派,你屬於哪派?

1、軟體工程有自己的政治軸心,—端是保守派,另—端是自由派。

畢竟“保守的”這個形容詞基本上和謹慎、厭惡風險就是同義詞。金融上的保守主義常常(也是顯而易見的)和年齡以及財富聯絡在一起。公司會隨著時間逐漸變得保守起來,因為它們熬過過了各種法律訴訟、技術失敗、公共危機、金融風暴等危機。連螞蟻和蚱蜢的寓言故事都告訴我們寒冬將至,要儲存食物。
本質上,保守主義就是風險管理。
同樣自由派的觀點常常和年輕、理想主義、天真無邪聯絡在一起。在企業裡,創業公司往往是典型的自由派,一部分原因是他們本來就是為了(在一定程度上)改變世界而存在的(而自由主義原本就意味著變化),另一部分則是他們必須全力以赴完成投資人設定的目標,所以放棄一點軟體安全也就變得合理(不得已)了。

me:保守派,儘量修復所有bug,迴避錯誤,學不會新語法,通過編譯器安全檢查,資料必須遵循事先定義好的格式,公共介面必須嚴格建模,生產系統裡絕不允許存在危險過有風險的後門,安全性有疑慮就不能上線,快比慢好,注重效能。自由派則相反。

2、各大語言的分派:(作者自己使用語言的經驗,僅供參考)
難以言喻的自由:組合語言
極端自由:Perl、Ruby、PHP、指令碼
非常自由:Javascript、VB、Lua
自由:Python、Common Lisp、Smalltalk/Sqeak
溫和自由:C、Object-C、Schema
溫和保守:C++、Java、C#、D、Go
保守:Clojure、Erlang、Pascal
非常保守:Scala、Ada、Ocaml、Eiffel
極端保守:Haskell、SML

3、(1)Facebook是極端自由的。他們主要用的是C++和PHP,他們的資料都放在memcached裡:只有鍵值對,沒有資料庫結構。他們把資料匯出來放到一個後臺Hⅳe資料倉儲裡,然後用Hadoop來進行離線資料分析。每兩個星期左右他們仍然會舉辦通宵黑客馬拉松,反正他們的程式設計師大多都是單身男青年(至少我上次去參觀的時候還是如此),股票的估值也還很高(我上次查價格的時候好像已經沒那麼好了)。作為一家公司,Facebook是非常緊密的,具有很強的執行力,十分注重程式設計師在網站上釋出新功能的單兵能力,沒有什麼官僚主義。這對一家規模這麼大、使用者那麼多多的公司來講是難能可貴的。保守派毫無疑問會厭惡蔑視他們。但是Facebook證明了不管具有什麼世界觀的程式設計師,只要聯合起來,就能解決很多問題。
(2)Amazon是自由的。
(3)Google是保守的。開始是有點自由的 ,然後就變得越來越保守了。只有在剛剛開始的時候才是軟體自由的,那時候的搜尋引擎是用Python寫的。隨著公司不斷壯大,他們很快就轉向了軟體保守主義,而這完全是由工程師自己主導的。他們寫了很多宣言警告太多語言所帶來的危險,而僅有的幾門語言裡,也裡,也有嚴格的風格指南,限制使用那些端保守,險”或者“難以閱讀”的語言特性。
(4)微軟是難以言喻的保守。

相關文章