你的程式語言能這樣做嗎?

發表於2011-05-31

(注:此文是Joel Spolsky寫於2006年8月)

一日,你檢視你的程式程式碼,你有兩大塊程式碼看起來幾乎完全的一樣。事實上它們就是完全一樣,除了一個程式碼裡說的是“Spaghetti(義大利麵條)”,另一個程式碼裡說的是“Chocolate Moose(巧克力慕絲)”。

這個例子恰好是用Javascript寫的,但即使是你不懂Javascript,你也應該能看懂我說的。

當然,重複的程式碼看起來不太好。所以你決定寫一個函式:

沒錯,這個例子很簡單,但你可以想出一些更有實際價值的例子。這樣做是更好一些,有很多理由,這些理由估計你都聽說過一萬遍了。可維護性,可讀性,抽象 = 好!

現在,你又發現兩塊程式碼幾乎完全一樣,除了一塊是不停的呼叫一個叫BoomBoom的函式,而一塊是不停的呼叫一個叫PutInPot的函式。除此之外,這兩塊程式碼完全一樣。

現在,你需要一個途徑,把一個引數傳遞到一個函式裡,而這個引數本身是個函式。這是一個很重要的功能,它是一個好的方法,能讓你發現函式中存在的重複的程式碼,減少這樣的重複。

看見了沒!我們把一個函式當做了引數。

你的語言能這樣做嗎?

且慢…如果你還沒有寫出PutInPot 或 BoomBoom 函式呢。如果你能把他們寫成行內函數,而不是要在其它地方先宣告,這樣是不是更好?

老天,這太方便了。注意到了沒有,我即時建立了一個方法,甚至都不用麻煩給它起名,只需掂著它的耳朵把它丟進函式裡。

當你開始思考把匿名函式當作引數時,你也許會注意到有一種程式碼到處都是,就是,遍歷陣列裡的所有元素進行操作。

對陣列裡的每個元素進行操作是一種很常見的動作,你可以寫出一個函式,讓它為你做這些:

現在,你可以把上面的程式碼重寫成這樣:

另一個常見的跟陣列相關的操作是,通過某種方式把陣列裡的所有值組合到一起。

sumjoin看起來非常的相似,你也許會想把它們的通用之處提取出來做成一個能把陣列裡的元素合併成一個值的通用函式:

很多老式的語言根本沒有方法做出這種事情。另外一些語言允許你做這些,但不容易(例如,C語言裡有函式指標,但你必須進行宣告,並要在什麼地方定義它)。物件導向的語言並沒有被證實可以允許你對函式做所有的操作。

如果你想在Java裡把函式作為一個一等(First Class)物件,你需要建一個只包含一個用來呼叫功能點的方法的整個物件。把這種現象跟實際情況聯絡起來,很多的面嚮物件語言都會要求你為每個 class建立一個完整的檔案,非常的沒效率。如果你的程式語言裡要求你去這樣的呼叫功能點,那你根本沒有享受到現代語言環境給你帶來的所有好處。看看能 否退貨吧,挽回一點損失。

寫這樣的小函式,只是做一些遍歷陣列,處理其中的每個元素的操作,這樣做究竟能得到多少好處?

那好,我們來回頭看一看map這個函式。當你需要對陣列裡的每個元素依次做一些操作時,實際情況是,你並不在乎處理這些元素的順序。你可以向前或向後遍歷整個陣列,得到的結果是一樣的,不是嗎?事實上,如果你的機器是2cpu的,你可以寫出一些程式讓每個cpu個處理一半的元素,你的map一下子就變快了2倍。

或者,只是個假設,在你遍佈全球的數個資料中心裡,你有成千上萬的伺服器,你有一個非常非常大的陣列,我說過,只是假設,它們裝載著整個網際網路的內容資訊。那現在,你就可以在你的成千上萬的計算機上執行map函式,每個機器都能分攤掉計算中的一小部分任務。

所以,如今,舉個例子,要想寫出一個十分高效的能搜尋整個網際網路內容資訊的程式碼,你只需要簡單的用基本搜尋字串當作引數來呼叫map函式就行了。

這裡,我想請你們要真正注意的有趣的事情是,你會發現像mapreduce這樣的函式每個人都可以使用,當人們使用它時,你只需要找到一個程式設計能手寫出最困難的呼叫mapreduce函式的程式碼,讓它們能夠執行在全球大量的並行執行的計算機上,而以前舊的執行的很好的程式碼只需要呼叫這個迴圈操作,唯一不同的是,它們獲得了比以前千萬倍快的速度,這意味著你能做瞬間處理完巨大的計算工作。

讓我再複述一遍。通過把通用的迴圈操作提取出來,你可以實現你想要的任何迴圈操作,包括實現出一種能隨硬體裝置的增加而效能升級的效果。

我想現在你就該明白為什麼我在前段時間寫的一篇文章裡抱怨學校只教授電腦科學專業的學生Java知識而忽略其它:[INDENT] 缺乏對函數語言程式設計的理解,你不可能發明出MapReduce—— 這個能夠讓Google實現大規模按需擴充套件和升級的演算法。Map和Reduce這兩個詞來自於Lisp語言和函數語言程式設計。回首看來,MapReduce對 於任何還存有記憶的人來說都意味著一種純函式式的程式設計,沒有副作用,易於平行計算。事實恰巧是Google發明了MapReduce,而微軟沒有,這就說 明瞭為什麼微軟仍然努力做那些基本的搜尋功能研究的原因了,而Google已經開始了它的下一個目標:開發它的Skynet^H^H^H^H^H^H—— 這世界上最大規模的並行超級計算機。我並不覺得微軟已經認識到在如今的潮流中它已經落後的多遠。
[/INDENT]  那麼,我希望現在你已經能理解了以函式為一等(First class)特徵程式語言能使你更容易的對程式碼進行提煉抽象,這意味著你的程式碼更短小,緊湊,可複用性強,更容易擴充套件升級。大量的Google應用程式都 使用了MapReduce,在他們優化程式或修改Bug時,都能從中得到益處。

現在我要說一點怨言牢騷,最高效的語言開發環境應該是一種能讓你在不同層次上進行抽象歸納的語言環境。笨拙陳舊的FORTRAN語言甚至不允許你寫函式。C語言裡有函式指標,但實現的很醜陋,不能匿名,使用之前必須先進行宣告實現。Java允許你使用功能點呼叫(functor),但更加醜陋。就像Steve Yegge指出的,Java就是一個名詞的王國

原文:joelonsoftware    譯文:外刊IT評論

 

相關文章