← 所有文章

工程哲學:Rich Hickey,簡單並不等於容易

Rich Hickey,Clojure程式語言的創造者

重點摘要

  • 簡單不等於容易。 簡單意味著「未交織」——一件事只承擔一個關切——而且是客觀的;容易意味著熟悉、近在手邊,而且是主觀的。我們總是選擇容易,卻把它誤稱為簡單。
  • 交織是複雜的根源。 複雜不在於零件的數量,而在於它們纏繞得多深。把狀態纏到時間上、把身分纏到行為上、把策略纏到機制上——這正是讓一套系統淪為只能祈禱的東西。
  • 不懈地解開交織。 把纏繞的關切抽離成各自獨立的部件,再刻意地加以組合。簡單是「一種選擇」,需要「持續的警覺」——它絕不會因為你伸手去拿那件熟悉的工具就自動降臨。
  • 重視值勝過位置,重視資料勝過物件。 讓不可變性成為預設,讓過往以不可變的事實層層累積,而非就地覆寫狀態——這正是Clojure與Datomic背後共同的紀律。

核心原則

「這個字的字根是『sim』和『plex』,意思是『一摺或一辮』[……]恰好與『complex』相鄰或相對,而complex的意思是『交織在一起』或『摺疊在一起』。」——Rich Hickey,Simple Made Easy1

幾乎每一場關於軟體品質的爭論,其實都是兩場爭論披著同一個字眼在發聲,而Rich Hickey的貢獻就是把它們拆開來。簡單容易並非同義詞。它們甚至不在同一個座標軸上:一個衡量的是事物本身,另一個衡量的是你與它之間的距離。簡單源自拉丁文simplex——一摺、一辮、一轉。它描述的是事物本身:其中交織了多少關切。它是客觀的,其反面是複雜——交織在一起、自我摺疊。相對地,容易衍生自一個意為「躺得近」的字根,與adjacent(相鄰)同源。2容易描述的是你與事物之間的關係:它離手有多近、有多熟悉、你動手起步要花多少力氣。它是主觀的,其反面是困難12

一旦看見這個區分,就再也無法視而不見。那件因為只差一道npm install就唾手可得而你伸手去拿的工具,是容易的。至於它是否簡單——它是否把持久化纏進你的驗證、再纏進你的UI、再纏進你的商業規則——則完全是另一個問題,而答案通常是否定的。我們不斷選擇容易並稱之為簡單,然後在自己招來的複雜裡滅頂。Hickey用來指稱「纏繞」這個動作的字是complect(交織):「把……交錯、纏繞或編成辮子。」3交織是原罪。它正是把一套你本可推理的系統,變成一套你只能祈禱的系統的元兇,因為一旦兩個關切被編成一辮,你就再也無法觸碰其一而不必去理解、不必去冒犯另一個。

於是,紀律就是解開交織(decomplect)——不懈地把纏繞的關切抽離成各自獨立的部件——而Hickey對其代價直言不諱。「簡單是一種選擇,」他說。「如果你沒有一套簡單的系統,那是你的錯。」4它不會因為你伸手去拿熟悉的工具就發生;它源自「持續的警覺」與刻意的用心。4整個原則就濃縮在四個字裡:簡單不等於容易。簡單是那條更艱難、需主動選擇、未經交織的路,而它是唯一會複利累積的一條。同樣的信念也墊在這個論點底下:品質是唯一的變數——你不會靠著每一步都挑那個方便的選項,而倒退著走進一套乾淨的系統;你得逆著坡度,每一次都主動選擇它。

背景脈絡

Rich Hickey是一位獨立程式設計師,在打造出那件讓他聲名遠播的東西之前,他靠著寫C++、Java與C#系統維生,前後約莫二十年。5他懂得如何用這些語言打造大型系統,而他在二十年後得出的結論,並不是它們缺了什麼功能。而是它們本身就是製造交織的機器——它們讓人毫不費力地把關切編成辮子,卻幾乎不提供任何把它們拆開的協助。

於是他獨力打造了那個替代方案。從2005年前後開始,Hickey花了大約兩年半開發Clojure——其中大半時間自掏腰包、不支薪,在Java虛擬機上打造一個Lisp,讓不可變性與簡單成為阻力最小的路徑,而非一樁英雄事蹟。5他在2007年公開發布。背後沒有公司、沒有委員會、沒有補助金。那是一位曾近距離見過這場病的程式設計師,決定用自己數年的存糧去打造解藥。他後來又創造了Datomic,一個不可變的資料庫,5並發表了一系列研討會演講——Simple Made EasyThe Value of ValuesHammock-Driven DevelopmentAre We There Yet?——這些演講合在一起,構成了現代函數式程式設計中最具影響力的一套設計哲學。6

Rich Hickey演講中

作品

Simple Made Easy:簡單對容易,以及交織

Simple Made Easy於2011年9月在Strange Loop發表,是那場重新整頓了一整代程式設計師談論複雜方式的演講。1它全部的力道,都來自拒絕讓簡單容易意指同一件事。簡單關乎構造——它是一摺,還是許多摺編在一起?容易關乎你——它是否近在手邊、熟悉、落在你目前的能力範圍之內?你可以擁有簡單卻陌生的東西(難學,但好相處),也可以擁有容易卻複雜的東西(熟悉、舒適,卻悄悄釀成毀滅)。業界包裝成生產力來販售的,大多是第二種。1

居於核心的那個動詞是complect(交織):編辮、交錯、纏繞。3交織才是一套系統複雜的東西——不是零件的數量,而是它們纏繞得多深。狀態把值與時間交織在一起。物件把狀態、身分與行為交織在一起。繼承、ORM、散落在一個方法各處的條件判斷——每一樣都把本可各自獨立的關切編成辮子。而一道辮子的代價不是只付一次;它在未來的每一次更動上都要再付,因為你再也無法觸碰其中一股而不擾動全部。

解藥是解開交織(decomplect)——把各股分離成獨立的東西,讓你日後得以按自己的條件加以組合。Hickey的主張很有力:解開交織並不是能力的折損。「你可以用大幅簡單的工具,寫出一樣精密的系統,」他說——同樣的程式,只不過是你真正能夠推理、更動且信任的那種。4簡單並不是能力的初學者子集。它是專家拒絕去編辮的那份紀律。

Clojure:給JVM的Lisp,資料勝過物件

Rich Hickey

Clojure就是這個原則化為可執行之物:一種動態、函數式的Lisp方言,執行於JVM之上,由Hickey設計為「一個用於函數式程式設計、與一個為並行而生的成熟平台共生的Lisp」。7有兩個決定把這套哲學編碼進去。其一,不可變性是預設,而非選項——Clojure的核心資料結構是不可變且持久的,於是最自然就能寫出的東西,也正是無法被遠方某處的突變所污染的東西。7其二,資料勝過物件:Clojure不偏好一堆各自帶著私有狀態、又把行為交織進去的訂製類別,而是青睞「定義在少數幾種主要資料結構上的許多函式」——序列、映射、向量、集合。7就用映射。就用資料。

這個切分,是在語言文法的層級上解開交織。物件把狀態、身分與行為交織成單一一個封死的東西;Clojure把它們拆開——用不可變的值表達一件事物是什麼,用單純的函式表達你對它做什麼,用明確的參考型別來管理那隨時間而來的變動。Hickey讓JVM成為平台而非與之對抗,也順帶把語言與執行環境解開了交織:Clojure免費承接了JVM的成熟度、函式庫與效能,而把它全部的創新預算,都花在狀態與時間的模型上。7

The Value of Values:不可變性與Datomic

The Value of Values把不可變性的論證再往上推一層,推到資料庫本身。Hickey瞄準的,是他所稱的位置導向程式設計(place-oriented programming,PLOP):「任何時候只要新資訊取代了舊資訊,你就是在做位置導向程式設計。」8我們就地更新一筆記錄,舊的值就此消失,連同它的歷史一併不見。他主張這是記憶體稀缺那個年代遺留下來的習慣,而它恰恰丟棄了企業推理所需的東西——過往。相對地,一個依定義就是不可變的:一個事實是「發生過的某件事、已知發生過的某件事」,而一個事實無法被更新,只能被一個更新的事實所取代。8一位新總統不會覆寫掉舊的那位;它是附加上去。

Datomic就是那個構想打造成的資料庫。它從根本上就是不可變的:「一個Datomic資料庫是一組稱為datom的不可變原子事實,」而且「Datomic的交易只新增datom,從不更新或移除它們,因此你擁有一份完整的稽核軌跡。」9因為沒有任何東西會被覆寫,這個資料庫便能被當作某個時間點當下的一個值來看待——你可以用查詢現在所用的同一批查詢,「截至」(as-of)過往的任何一刻去查詢它,毫無更動。9資料庫不再是單一一個可變的位置,而成為隨時間而來的一連串值。狀態、身分與時間——在一個生產環境的資料存放區裡,被解開了交織。

Hammock-Driven Development:先思考

與這一切相伴的,是一場關於真正的工作何時發生的演講,而Hickey的答案是:在你碰鍵盤之前。在Hammock-Driven Development裡,他主張「修正臭蟲最省成本的地方,是在你設計軟體的時候」,而大多數嚴重的軟體失敗,都是誤解的失敗——我們在動手解決之前,根本沒搞懂問題。10補救之道,是把問題明確陳述出來、蒐集事實與限制,然後思考——包括把問題交給你的「背景心智」,由它去建立那些你分析性的「清醒心智」無法硬逼出來的連結。10吊床就是那件除了不受打擾地思考之外什麼都不做的字面意義上的傢俱。

吊床驅動開發正是讓簡單得以成立的那項實踐。你無法解開一套你尚未理解的系統的交織,而你也無法在趕著編譯時去理解它。吊床驅動開發是簡單不等於容易那不起眼的前半段:在那未經交織的設計得以浮現之前,必須先發生的那種刻意、緩慢、警覺的思考。

方法

這套方法只有一個區分——簡單不等於容易——以不尋常的頑固,橫跨一門語言、一個資料庫與一種工作方式去貫徹。

在每一個決定之前,把「簡單」與「容易」分開來。 對任何工具或設計都要問:這是未經交織(簡單),還是僅僅熟悉而近在手邊(容易)?它們是不同的座標軸,而把它們混為一談,正是複雜偽裝成生產力潛入的方式。12

獵捕交織,並把它解開。 複雜不在於零件的數目;而在於它們纏繞得多深。找出狀態被纏到時間上、身分被纏到行為上、策略被纏到機制上之處——再把各股拆開成獨立的部件,刻意地加以組合。3

重視值與資料,勝過位置與物件。 讓不可變性成為預設。把資訊表達為單純的資料——映射、向量——並以函式對它進行操作,而非把狀態與行為一起封死在物件裡。78

把過往當作一個值,而非被覆寫的狀態。 新資訊應當附加,而非摧毀。一套隨時間累積不可變事實的系統,可被推理、可被稽核,並可「截至」任何一刻去查詢——這是一個就地被覆寫的位置永遠做不到的。89

動手打字之前先思考。 修正缺陷最便宜的地方在設計。把問題陳述出來、餵給你的背景心智,先理解了問題,再去把那簡單的設計掙來。10

接受簡單是艱難的、是選來的。 它不會因為你伸手去拿那件容易的東西就降臨。「簡單是一種選擇,」而它需要「持續的警覺」。那條方便的路與那條簡單的路,鮮少是同一條路。4

影響鏈

是誰形塑了他

Lisp與John McCarthy。 用Hickey自己的話來框,Clojure是「一個不受向後相容性所束縛的Lisp」——那程式碼即資料的同像性(homoiconicity)以及巨集的威力,都直接承自McCarthy的血脈,只是延伸到了映射與向量,而不只是串列。7(直接影響)

John Backus與函數式程式設計傳統。 Backus 1977年的圖靈獎演講Can Programming Be Liberated from the von Neumann Style?,是反對賦值驅動、位置導向運算的那篇典範論證。Hickey對位置導向程式設計與可變狀態的征戰,正是那篇論證被帶進了生產環境。(奠基影響)

Java虛擬機。 Hickey並未把執行環境當作一個要抽象掉的敵人,反而讓JVM成為平台,並在其上打造語言——這是一次刻意把「語言」與「執行環境」解開交織的動作,讓Clojure從第一天起就擁有成熟度與觸及範圍。(直接影響)

關聯式與值導向的思考。 Datomic把資料看作隨時間累積、可「截至」任何一點查詢的不可變事實,這個觀點承襲自關聯式傳統把事實與其儲存分離的做法——亦即,資訊擁有一種獨立於當前持有它的那個位置的存在。89(奠基影響)

他形塑了誰

函數式程式設計的復興。 Clojure,連同JVM上的Scala等語言,協助把函數式程式設計從學術好奇心推向主流生產環境,而Hickey的演講成了共通的詞彙——「simple」、「easy」、「complect」——如今的在職程式設計師就用這些字眼來爭論設計。

不可變性,被推向主流。 「不可變即預設的資料才是理智的預設,而非一項奇特的限制」這個觀念,遠遠傳播到了Clojure之外。它如今在整個業界的語言與函式庫設計裡,都已是基本門檻。

React、Redux與前端世界。 那套值導向的模型——不可變的狀態、對資料的純粹轉換、身分與狀態被拆開——正是React、尤其是Redux的概念骨幹。一整代前端工程師吸收了Hickey的值思維,卻未必知道那是誰的。

貫穿的主線

John Carmack把一個算繪器剝到那快速、簡單的核心,並拒絕任何會把緩慢編進內層迴圈的功能;Hickey則把一套系統剝到它那些未經交織的關切,並拒絕任何會把它們交織起來的抽象。兩人都把簡單當作那艱難、選來的東西,而非預設。而當Linus Torvalds推崇那種讓特例消失進通則裡的「好品味」時,Hickey推崇的則是那種讓兩個纏繞的關切各自挺立的解開交織——同一種直覺,從相反的兩端看去:對的結構並非問題之上的裝飾,它就是被正確地分離成各個真實部件之後的問題本身。Yukihiro Matsumoto為「寫起來感覺如何」而最佳化了Ruby——用Hickey的詞彙來說,就是那個容易——而Hickey為「那件事物是什麼」而最佳化——那個簡單;兩人合起來,正好標出了Hickey花了一整場演講堅持要我們別再混淆的那兩個座標軸。(系列銜接)

我從中汲取的

我牢記的教訓是:容易是一個披著美德外衣的陷阱。一套程式碼裡幾乎每一樁悔恨,起初都是一次對近在手邊之物合情合理的伸手——那個方便的函式庫、那次便捷的突變、那一個多塞進某個既有類別的額外職責。沒有一樣當下感覺像個錯誤,因為容易從來不會。Hickey的贈禮,是那套讓你能在當下逮住它的詞彙:停下來問一句這是簡單,還是只是容易?,並且知道那個誠實的答案,通常就是那個不方便的答案。這與品質是唯一的變數是同一套標準——問題從來不是「我最快能搆到什麼?」,而是「這裡真正未經交織的是什麼?」

在我如今打造東西的世界裡——代理、工具迴圈、那種狀態、提示、重試與副作用最愛把自己編成一團無從治理之物的代理框架程式碼——誘惑是極致的容易:堆疊框架、把狀態抹散在整個迴圈裡、把決策邏輯與I/O與日誌記錄交織到無人能更動一個部件而不冒犯全局。Hickey式的動作則是解開交織:把策略從機制裡抽出來、在能做到之處讓狀態不可變、把每一次執行當作一個值,而非一個我覆寫的位置。那份信念——品味是一套技術系統,是你帶著警覺去選擇的,而非伸手去拿近在手邊之物就承襲來的氛圍——正是從2007年那個自掏腰包的Lisp,一路貫穿到2026年一套代理框架的主線。簡單不等於容易。無論如何,都要選擇它。

常見問題

簡單與容易有什麼不同?

在Rich Hickey於Simple Made Easy中的框架裡,簡單容易是截然不同的兩個座標軸。簡單源自拉丁文simplex——「一摺或一辮」——描述的是事物本身:其中交織了多少關切。它是客觀的,其反面是複雜(「交織在一起」)。1容易衍生自一個意為「躺得近」的字根,與adjacent(相鄰)同源;它描述的是你與事物之間的關係——它有多熟悉、有多近在手邊。2它是主觀的,其反面是困難。一件事物可以是簡單卻陌生的,也可以是容易卻深度複雜的。Hickey的重點是,我們不斷選擇容易,卻把它誤稱為簡單,而日後再為那份複雜付出代價。1

「complect」是什麼意思?

complect(交織)是Hickey在Simple Made Easy裡重新啟用的動詞,用以指稱把數種關切編成辮子的那個動作。他直接下了定義:「它的意思是把……交錯、纏繞或編成辮子。」3交織才是讓一套系統複雜的東西——不是零件的數量,而是它們纏繞得多深。當兩個關切被交織在一起(比方說,狀態與時間,或身分與行為),你就再也無法更動其一而不必去理解、不必去冒犯另一個。補救之道是解開交織(decomplect):把各股抽離成你能刻意組合的獨立部件。Hickey把解開交織當作打造簡單系統的核心紀律。3

Rich Hickey打造了什麼?

Rich Hickey是一位獨立程式設計師,創造了Clojure——一種動態、函數式的Lisp方言,執行於Java虛擬機之上。他大致獨力開發了它,前後約莫兩年半,其中大半自掏腰包、不支薪,並於2007年發布。57他後來又創造了Datomic,一個從不覆寫資料、而是隨時間累積不可變事實(「datom」)的不可變資料庫,於是這個資料庫可被當作「截至」任何過往一點的一個值來查詢。9他也以一系列研討會演講廣為人知——Simple Made EasyThe Value of ValuesHammock-Driven DevelopmentAre We There Yet?——這些演講形塑了業界談論複雜、不可變性與設計的方式。56

Rich Hickey說過「程式設計師懂得一切的好處,卻不懂任何事的取捨」嗎?

這句俏皮話極為廣泛地被歸給Hickey,也精確地抓住了他的思路,但它並未逐字出現在他主要的演講逐字稿裡;它是一句經由書籍與研討會演講流傳開來、被結晶化的轉述。11最接近的逐字原始版本出現在Design, Composition, and Performance裡,他在那裡力勸人們把一個解決方案拆開來,「不只是去看那些好處,對吧?那些通常相當明顯。而是也去看那些取捨:這當中有哪一部分是行不通的?」12那份心意毫不含糊地屬於他——工程師過度看重一件工具給了他們什麼,卻太少審視它的代價——但那句鏗鏘有力的格言,最好還是當作轉述,而非直接引語來看待。


來源


  1. Rich Hickey, “Simple Made Easy” (transcript), Strange Loop, September 2011, matthiasn/talk-transcripts. On the etymology of simple (“sim” and “plex,” “one fold or braid”), the contrast with complex (“braided together”), and the simple-vs-easy distinction. Video: InfoQ. 

  2. Rich Hickey, “Simple Made Easy” (transcript), Strange Loop, 2011. On the etymology of easy: derived from a root (via French, from Latin) that is “the root of adjacent, which means to lie near and to be nearby” – i.e., familiar / at-hand, the opposite of hard

  3. Rich Hickey, “Simple Made Easy” (transcript), Strange Loop, 2011. On the verb complect: “It means to interleave or entwine or braid,” and the corresponding discipline of decomplecting concerns into independent pieces. 

  4. Rich Hickey, “Simple Made Easy” (transcript), Strange Loop, 2011. “Simplicity is a choice. It’s your fault if you don’t have a simple system”; that it “requires constant vigilance”; and “you can write as sophisticated a system with dramatically simpler tools.” 

  5. “Rich Hickey,” Wikipedia. “[K]nown as the creator of the Clojure programming language,” “a Lisp dialect built on top of the Java Virtual Machine”; “He spent about 2½ years working on Clojure, much of that time working exclusively on Clojure without external funding, before releasing it to the world in 2007.” Datomic “launched” in 2012. The talk catalog (Simple Made Easy, The Value of Values, Hammock-Driven Development, Are We There Yet?) is cataloged in 6

  6. Eric Normand, “Rich Hickey programmer profile,” ericnormand.me. Catalog of Hickey’s major talks, including Simple Made Easy, The Value of Values, Hammock-Driven Development, Are We There Yet?, and Design, Composition, and Performance

  7. “Clojure – Rationale,” clojure.org. Clojure as a dynamic, functional Lisp dialect that runs on the JVM (“Clojure is the language, JVM the platform”); “All data structures immutable & persistent”; “Many functions defined on few primary data structures (seq, map, vector, set)”; “a Lisp not constrained by backwards compatibility”; “A Lisp for Functional Programming symbiotic with an established Platform designed for Concurrency.” 

  8. Rich Hickey, “The Value of Values” (transcript), matthiasn/talk-transcripts. On place-oriented programming (“anytime new information replaces old information, you’re doing Place-Oriented Programming”), values as immutable, and facts as things that happened and cannot be updated – only superseded by newer facts. 

  9. “Datomic Overview,” docs.datomic.com. “A Datomic database is a set of immutable atomic facts called datoms”; “Datomic transactions add datoms, never updating or removing them, so you have a complete audit trail”; databases “can be filtered to include only data as of any specific point in the past” and queried “as-of” without modification. 

  10. Rich Hickey, “Hammock Driven Development” (transcript), Clojure Conj, October 2010, matthiasn/talk-transcripts. On thinking before coding, “the least expensive place to fix bugs is when you’re designing your software,” problems as misconceptions, and the “waking mind” vs. “background mind.” Video: YouTube. 

  11. “Rich Hickey,” Wikipedia, citing Mark Richards, Microservices AntiPatterns and Pitfalls (O’Reilly). The aphorism “Programmers know the benefits of everything and the tradeoffs of nothing” is widely attributed to Hickey via secondary sources; it does not appear verbatim in his primary talk transcripts and is best treated as a paraphrase. See also the Goodreads attribution. 

  12. Rich Hickey, “Design, Composition, and Performance” (transcript), matthiasn/talk-transcripts. The verbatim primary source for the benefits-vs-tradeoffs idea: take a solution apart “to see not just the benefits… But also the tradeoffs: what part of this is not going to work?” 

相關文章

工程哲學:Salvatore Sanfilippo(antirez)

Salvatore Sanfilippo 圍繞單一原則打造了 Redis——少做一點。一個小巧、單執行緒、記憶體內的儲存系統,小到能裝進你的腦海,並以 C 語言寫成,供人閱讀。

5 分鐘閱讀

工程哲學:Yann LeCun

深度學習先驅、圖靈獎得主 Yann LeCun 共同發明了卷積神經網路,如今押注於世界模型——一條通往能像人一樣學習的機器、超越當今大型語言模型的路徑。

3 分鐘閱讀

The Shader Gallery That Lied: Debugging 216 WebGL Presets

A user said the shader playground looked broken. Pixel-readback testing found 30 dead presets, 11 that never compiled, a…

11 分鐘閱讀