工程哲学:Rich Hickey,简单不等于容易

核心要点
- 简单不等于容易。 简单意味着不缠绕——每件事物只承担一个关注点——它是客观的;容易意味着熟悉、近在手边,它是主观的。我们不断地选择容易,却把它误标成简单。
- 缠绕是复杂的根源。 复杂不在于部件的数量,而在于它们彼此缠绕的程度。把状态缠绕到时间上、把身份缠绕到行为上、把策略缠绕到机制上——正是这些让系统变得只能听天由命。
- 坚持不懈地解缠。 把缠绕在一起的关注点拆成各自独立、可以有意识地组合的部分。简单是“一种选择”,它“需要持续的警觉”——它绝不会因为你顺手抓起熟悉的工具就自动到来。
- 重值而非重位,重数据而非重对象。 让不可变成为默认状态,让过去作为不可变的事实累积下来,而不是就地覆盖状态——这正是 Clojure 和 Datomic 共同的底层纪律。
原则
“这个词的词根是 ‘sim’ 和 ‘plex’,意思是’一折或一缕’[……]它紧挨着、也正好对立于 ‘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 Easy、The Value of Values、Hammock-Driven Development、Are We There Yet?——它们合在一起,是现代函数式编程中最具影响力的一套设计哲学。6

工作成果
Simple Made Easy:简单 vs. 容易,以及缠绕
Simple Made Easy 于 2011 年 9 月在 Strange Loop 大会上发表,这场演讲重新组织了一代程序员谈论复杂性的方式。1它的全部力量,都来自拒绝让简单和容易指代同一件事。简单关乎构造本身——它是一折,还是许多缠绕在一起?容易关乎你——它是否近在手边、是否熟悉、是否在你当前能力范围之内?你可以拥有简单却陌生的东西(难学,但用起来省心),也可以拥有容易却复杂的东西(熟悉、舒适,却悄悄地带来灾难)。这个行业以“生产力”之名兜售的大部分东西,都是后一种。1
居于核心的动词是 complect(缠绕):编织、交织、缠绕。3缠绕正是使一个系统变得复杂的原因——不在于部件的数量,而在于它们缠得有多紧。状态把值和时间缠在一起。对象把状态、身份和行为缠在一起。继承、ORM、散落在一个方法里各处的条件判断——每一样都在缠绕本可以各自独立的关注点。而一缕缠绕的代价不是一次性付清的;它要在未来每一次改动时反复偿还,因为你再也无法碰其中一根线而不扰动其余所有线。
解药是解缠(decomplect)——把那些线分开,变成你日后可以按自己的方式组合的独立事物。Hickey 的主张——而且是一个很强的主张——是:解缠并不意味着丧失能力。“你完全可以用简单得多的工具,写出同样精巧的系统,”他说——一样的程序,只不过是你真正能够推理、能够修改、能够信任的程序。4简单不是能力的入门子集。它是专家的纪律:拒绝缠绕。
Clojure:为 JVM 打造的 Lisp,数据高于对象

Clojure 是这条原则的可执行版本:一门运行在 JVM 上的动态、函数式 Lisp 方言,由 Hickey 设计为“一门用于函数式编程、与一个为并发而设计的成熟平台共生的 Lisp”。7两个决策把这套哲学编码了进去。第一,不可变是默认,而非选项——Clojure 的核心数据结构是不可变且持久的,因此最自然写出来的东西,恰恰也是那个不会被遥远某处的一次变更所破坏的东西。7第二,数据高于对象:与其堆砌一大批各自把私有状态和行为缠在一起的定制类,Clojure 更偏爱“在少数几种主要数据结构上定义许多函数”——序列、映射、向量、集合。7就用映射。就用数据。
这种拆分,是在语言语法层面上的解缠。对象把状态、身份和行为缠成一个密封的整体;Clojure 把它们拆开——用不可变的值表示一个事物是什么,用普通函数表示你对它做什么,用显式的引用类型来管理随时间发生的变化。通过让 JVM 成为平台而不是与之对抗,Hickey 还把语言从执行环境中解缠了出来:Clojure 不费分文就获得了 JVM 的成熟度、库和性能,从而把全部的创新预算都花在了状态与时间的模型上。7
The Value of Values:不可变与 Datomic
The Value of Values 把不可变这一论点又往上推了一层,推到了数据库本身。Hickey 的靶子是他所称的面向位置的编程(place-oriented programming,PLOP):“任何时候,只要新信息替换了旧信息,你就是在做面向位置的编程。”8我们就地更新一条记录,旧值就此消失,历史也随之消失。他论证道,这是内存稀缺时代的遗留物,而它恰恰丢掉了一个企业用来推理所最需要的东西——过去。值(value)则相反,按定义就是不可变的:一个事实是“发生过的事,已知发生过的事”,而一个事实是无法被更新的,只能被一个更新的事实所取代。8新总统不会覆盖旧总统;它是追加上去的。
Datomic 就是把这个想法造成了一个数据库。它从根本上是不可变的:“一个 Datomic 数据库是一组不可变的原子事实,称为 datom”,而且“Datomic 的事务只添加 datom,从不更新或删除它们,因此你拥有一份完整的审计轨迹”。9正因为任何东西都不会被覆盖,数据库就可以被当作某个时间点上的值来对待——你可以用查询当下数据时一模一样的查询,去查询它“截至”过去任意一刻的状态,无需任何改动。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 的演讲成了共享的词汇——“简单”、“容易”、“缠绕”——如今的一线程序员正是用它们来争论设计的。
不可变,走向主流。 “默认不可变的数据才是理智的默认,而非一种异域的约束”这一观念,远远传播到了 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,一门运行在 Java 虚拟机上的动态、函数式 Lisp 方言。他大体上独自一人,用了将近两年半时间开发它,其中大部分是自掏腰包、没有薪水的,并于 2007 年发布。57后来他又创造了 Datomic,一个不可变的数据库——它从不覆盖数据,而是随时间累积不可变的事实(“datom”),因此数据库可以被当作“截至”过去任意一点的值来查询。9他还以一系列会议演讲而广为人知——Simple Made Easy、The Value of Values、Hammock-Driven Development 以及 Are We There Yet?——它们塑造了整个行业谈论复杂性、不可变和设计的方式。56
Rich Hickey 说过“程序员知道一切的好处,却对一切的代价一无所知”吗?
这句俏皮话被极其广泛地归到 Hickey 名下,也精准地抓住了他的思路,但它并未逐字出现在他主要的演讲文字稿里;它是一句经过沉淀、在书籍和会议演讲中流传开来的浓缩转述。11最接近的逐字原始版本出现在 Design, Composition, and Performance 中,他在那里敦促把一个解决方案拆开,“不只是去看好处,对吧?那些通常相当明显。还要去看代价:这其中有哪部分是行不通的?”12这层意思无疑是他的——工程师们对一个工具给予的东西过度关注,而对它所付出的代价审视不足——但那句精炼的格言,最好还是当作转述,而非直接引语。
来源
-
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. ↩↩↩↩↩↩↩
-
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. ↩↩↩↩
-
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. ↩↩↩↩↩
-
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.” ↩↩↩↩
-
“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. ↩↩↩↩↩
-
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. ↩↩↩
-
“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.” ↩↩↩↩↩↩↩
-
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. ↩↩↩↩↩
-
“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. ↩↩↩↩↩
-
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. ↩↩↩
-
“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. ↩
-
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?” ↩