Clojure 之美
最近,我在博客上有點安靜。部分原因是正在學習程序設計語言 Clojure,這是很讓人激動的事。
討厭 Lisp 的人
Clojure 在 2007 左右就被推出了。因此,我是花了一段時間在興奮中去探索它的。事實上,我在 2013就買了本《The Joy of Clojure1》。是什么讓我花了這么長的時間去閱讀它呢?
我承認,自從我在大學第一次接觸它們的時候我就很討厭 Lisp 。當我說“討厭”的時候,我不是在夸大其詞。我非常討厭 Lisps。我就不理解了,為什么還有人想要使用 Lisp 寫程序,還給出了替代品。我從未從括號和前綴表達符事情中解脫出來。
然而,Clojure 開發者聲稱 Clojure 是好的不能再好的東西,是這個星球上最有效的程序設計語言,這些才讓我走出了以前的陰影(過渡括號的恐懼)。
極其恐怖的括號
如果你看看周圍各種 Clojure 文章你將發現他們正在淡化 Lisp 括號和前綴符號在可讀性方面的影響。就我個人而言,我想那是無知的。至少對于這個語言的新特性來說。
我們絕大多數的人都是伴隨著從左到右閱讀的語言和用中綴表示法表示數學和邏輯操作的一般表示方法的語言。這已經根深蒂固的植入我們得血液里。s-expressions2 的使用和 他們作為結果的前綴符合在很多方面是 Clojure 的秘密調料。然而,它要求你從右到左,從里到外的閱讀。這對我們大多數人來說有點擰巴,是煎熬。這是進入 Lisp 世界的一個很大的障礙。
例如,這是一些用 Clojure 實現的一些簡單的代碼。它僅僅只是獲取一組數據,再把它們都加上 2,然后再計算這些結果的和。
Failed loading gist https://gist.github.com/effab10ef3e67f2b3cfa.json: timeout
這段代碼簡單的跟 1 一樣。但是對于那些不了解 Lisp 代碼閱讀的人來說就不容易消化理解了。相比于同等功能的 Scala 代碼很簡單了。但得讓你自己下定決心。
Failed loading gist https://gist.github.com/318453e354df70c656fb.json: timeout
具有諷刺意味的是,一旦你跨過了最初的困難, s-expressions 設置了讓 Clojure 成為最簡單的和與現代程序設計語言保持一致的基礎去使用。但是它確實需要一些努力。不可避免,但是你不得不跨過去。
放開靜態類型
下一件事情會打擊到有 Java 背景的你,是缺少靜態類型檢查(或者函數程序設計(FP)范式,如果你不熟悉 FP,我建議你學習 Clojure 之前先熟悉一下 FP,這是我的一點心得)
在某些方面這是解放。畢竟,誰愿意從數據庫取數據的時候還要安排數據到一個完全成熟的對象里,然后再轉換成 JSON? 使用 Clojure 你就可以對這些說再見了。數據僅僅是一個 Map,也就是 JSON。嘣~,再見,沒有活力的域模型。
另一方面,這有點像“哇噻! 我僅僅收到一個 map 作為參數傳到我的方法!這到底是怎么做到的?”額~,你的猜測跟我差不多。
但是如果你能沒有 java 的類型還能活的話,那么 Clojure 是高效的選擇。
Clojure 之美
很快,你將得到更多的驚喜,而愛上 Clojure。 s-expression 基本語法的簡潔,語言的連貫性,力量:這才是美。
這時你就發現你自己想站起來向 Lisp 的創造者,John McCarthy 的天才致敬,并且感謝 Rich Hickey為 JVM 創造了真正的實用主義者的 Lisp 語法。
Clojure,像 Scala,是一個實用主義者的語言,而不是純粹主義者。它的存在是建立偉大的軟件,而不是定義完美的語言。
Clojure 不做框架
一旦你著手開始使用 Clojure 構建應用,也許你會受到打擊。Clojure 沒有框架。它們根本不存在什么框架,一切由庫組成。
在 Clojure 的世界里,方法是語言的一等公民。因此,Coljure 達到了一個徹底地超越了Java 的可組合性的新水準。這個可組合的觀念部分自始至終的體現在 Clojure 的生態系統,這里框架被視作緊密耦合的絆腳石。
這在剛開始可能覺得有點令人怯步,但這絕對是一個來自的 Java 的范式轉換。最初,它也需要一些跑腿的工作,就像你必須定義一些庫組合到你的應用里。但是最終得到一個由最小部件組成的緊湊的應用。
另外跑腿的工作往往是值得的,你將發現有許多庫都是優雅而有力的。就那 compojure-api 做個例子。這個庫能夠幫助你很容易就生成一個 REST API,包括支持 Swagger。
Clojure vs Scala
當年試過按范式轉換的要求閱讀基于 s-expressions 的語言之后,你就會覺得 Clojure 是簡單的,真他媽簡單。它只是列表,在列表中,在列表中 ,... ...
相比較之下,Scala 就不簡單了。為什么它難呢?Clojure 是函數式程序語言(FP),像 Lisp 那樣。而 Scala 是面向對象的,FP,靜態類型的,等等。如果僅僅就這些原因,Scala 復雜度立馬就超過 Clojure 的三倍。毫無疑問地,這是在你接觸之前,還不算其他的。
不要誤解我的意思,我真的喜歡 Scala。它有類型。我可以用我的 IDE 重構大量的代碼庫。試著用 Clojure 這樣做一下,我只能祝你好運了。但是 Scala 比較復雜。由于同時具有 OO 和 FP 的模式和可變和不可變的方法,Scala 給你下了很多套。
從這點來看,Clojure 更純凈,更固執,更簡單。Clojure 是簡潔的。
Clojure 腳本——無名的英雄
如果你遨游在 Clojure 的世界里,遲早你將遇到 Clojure 腳本,它是 非死book React 封裝。如果你以前做過可以轉譯成Javascript的語言和框架的Web應用開發(比如GoogleWeb Toolkit),很快,你會驚訝的連下巴都掉地上了。
在組合工具中,比如 figwheel,你可以獲得實時的開發經驗,figwheel 可以你使用的瀏覽器上最大程度的保持代碼/CSS的更新。是的,你沒看錯,看一下這個視頻 是個不錯的例子。
即使你之前沒有留意到,此刻,Clojure 的參數開始變得極其的引人入勝。(Scala 也有Scala.js和它自己的等同于 figwheel 的 workbench。但是,目前它在代碼更新上不支持狀態保留這樣的水準——可能由于可能是由于靜態類型的限制。)
Clojure 可以開發企業級應用嗎?
如果我今天打算開發一個 Clojure 項目,我知道我應該把 Clojure/Clojurescript 組合起來開發。但是我可以用 Clojure 開發一個企業級應用嗎? 我不知道。
問題是企業級軟件開發被一個缺乏技術性強的領導者掌控著,導致在項目中充滿了反模式和離岸開發,從而引起更嚴重的問題。如果當公司使用一個相當簡單的、靜態類型的語言(比如 Java)會發生什么,哪一個相對容易的保證質量?他們用固有的權力在一個動態的,宏啟用的語言(比如 Clojure)里來做什么?
對于我來說,暫時還無法提供企業級應用。是的,我還不能通過 Clojure(script) 超越以前的開發速度。毫無疑問的是,如果我用 Clojure 來開發企業級應用,我會大吃一驚。這就是我不確定的長尾理論吧。
當 Clojure 涉及到類型,Typed Clojure 就如虎添翼。一方面,它似乎存在動態類型不擴展的說明,這正是 Clojure 正在失去的一些東西。與此同時,它又提供了快速建立原型的可能性和后來增加的 Clojure 認為需要的可選類型。
我只是不能確認,以靜態類型語言作為開始會不會更好,或者是否 Typed Clojure 才是是最好的中間地帶。(有強烈建議的人,歡迎來說服我)。
你的 FN 就是大家的 FN
Clojure 讓我靜下心來,并將我從 Lisp 的厭惡中解放出來。深深地印在我的腦海里。Clojure ,我向你致敬。
當然,問題是很難讓每個人都用 Clojure.<o (>﹏<)>。快速瀏覽一下工作網站,你會發現 Scala 的工作需求量是 Clojure 的五倍。你又會發現 Java 的工作需求量是 Scala 的十倍。如果沒有企業級軟件社區買入 Clojure,任何事情都不會好轉。這兒仍然希望有較多的實踐能發掘出 Clojure 潛在的企業級應用軟件開發。
如果你是 Clojure 新手,并有興趣深入學習,并且工作前景還過的去,那么我建議你從 Light Table的 instaREPL 和一些東西像 Clojure for the Brave and True 開始。
(我在闊別 15 年后再次使用上了 Emacs ,但是這完全是另一個故事)