阅读视图

发现新文章,点击刷新页面。

我(不)想让 AI 帮我做

标题之所以没有使用 LLM 这个在如今大多数情况下更准确的词,是因为我想讨论更宽泛的技术。帮人做事的不只是大语言模型,对于个别人来说,还有可能是文生图模型、图像视觉模型等等。所以我使用了 AI 这个词。

如果你读过本博客其他有关 AI 的文章,你会发现我大部分时候都没什么好话说。我为什么不喜欢这门不少人都相信即将翻天覆地地改变世界的技术呢?我就从我最熟悉的领域说起吧。编程,也正是如今受 LLM 影响最大的技能之一,是我从小学五年级就开始做的事情。我喜欢编程,一开始是因为我喜欢创造的感觉,我还记得我写第一个易语言程序的时候(很不幸,这的确是我的启蒙编程语言),我把 UI 拼成自己喜欢的样子时有多高兴。后来,我意识到自己代码能力太弱,那时的我连分支和循环结构都不知道是什么。

我仍然喜欢创造,但我很快迷上了另一项可以称作是智识锻炼的活动——写代码本身。我喜欢用代码让机器做我想让它做的事,我喜欢思考编程语言和自然语言的关系,我总是在思考什么样的代码是好的代码。可如今,当我放下 Bob 大叔写的《代码整洁之道》时,我叹息。函数体里的代码应该位于同一抽象层上,函数应该简短,一个文件的长度不应该超过一个屏幕的大小…… 这些东西还有人在乎吗?

我从今年开始学 Lisp,准确来说是 Clojure 和最近初探索的 Guile Scheme。在感受函数式编程的震撼之时,我也被另一种焦虑缠绕着:没人在乎你的代码漂不漂亮,没人在乎架构是否合理,没人在乎你用的什么编程语言,人们只想让程序运行起来,把事情办好,而且越快越好。当然,有人会像要求设计师必须用 PhotoShop(否则显得不专业)一样要求程序员必须用丑陋的 Java 和 Spring Boot 做开发,但如果可以,他们真的想要完全把代码消除掉,甚至 把软件工程师也弄走 。讽刺的是,他们既无法理解写代码本身的乐趣,又觉得写程序就只是写代码,觉得软件工程里的工程二字没有实义。

我逐渐把握了我对生成式人工智能的矛盾态度,其实一点也不矛盾:和所有技术进步一样,我想让技术解放我,让我不必做我不想做的事情;但我不想让技术限制我,让我没法享受我想做的事情。

我逐渐意识到,编程智能体(Coding Agents)之所以发展迅猛,很大程度上是因为世界上到处都是不喜欢写代码的程序员和觉得创造软件就是写代码的普通人。当然,它的用户不乏一些乐于接受新技术的工程师,但这些工程师多半也还是会自己写代码,只用智能体完成部分工作。

叛徒的自白

如果你是一名讨厌 AI 的画师,一名对 AI 编程感到焦虑或者厌恶的程序员,一名对 LLM 颇有微词的文字工作者,很不幸,我可能是个叛徒。

过去的一两个月里我一直在用 OpenCode 和 DeepSeek 的便宜 API 做项目,尽管每天最多只会花四个小时在 AI 编程上(再多我觉得我的大脑真的要承受不了了),但我的确给 AI 公司付了不少钱,一定程度上促进了市场需求的增长。

不过还请放心,我发布在 Codeberg 上的项目大部分都是我手写的。我从未想过 Vibe Code 一个爆款产品或开源项目,我仅仅是用它来应付学校的项目。我想如果我去实习或正式谋得一个职位,就算上司不要求(尽管现在不少岗位都希望求职者有 AI 编程经验),我也会用它来写工作上的代码,审查后对交付的结果负责。

这是好事吗?我把不想写的代码外包给 LLM,想写的代码留给自己写,听起来两全其美不是吗?

事实并非如此。

在我开始高强度使用 AI 编程之后,我手写代码的时间明显变少了,我的 Wakapi 统计数据可以证明——过去七天,我只有不到七个小时在写代码,除了有三个小时在写 Clojure,有一个小时在写 YAML 调试 Woodpecker CI 工作流,剩下的时间基本上都是在写配置文件,

此外,更明显的副作用是,我在写 Clojure 代码的那三个小时,脑子变得迟钝,常常面对简单的需求感到无从下手。我目前正在进行的学校项目,我选择了 Go 语言作为后端,这门 初识时让我感到相见恨晚 的语言,在我某天想要自己动手开发时,也让我觉得令人恐怖地陌生。本来我非常乐意解决新问题,可现在面对越来越多的我不知道怎么写的代码,比起思考和寻找他人的解决方案,我的下意识反应竟然变成了……

*按下 ⌘D1

*opencode

*“请你帮我……”

老虎机、偏误放大器和消费载体

LLM 在很多层面都和短视频十分相似。首先,它们都有类似老虎机的交互逻辑,再往下一刷就能看到更有趣、更新鲜、更吸引人的内容,再写一条提示词、再听一句「You’re absolutely right!」,问题似乎就会迎刃而解。尽管总是事与愿违,但我们似乎不愿意停下,就像无法进行更高级的反思的动物一样。如果给老鼠一个按钮,按下之后它就会经历性高潮,那么它就会一直按这个按钮,直到死亡。

在哲学意义上,人与动物的区别并不是会使用工具,而是能够进行反思。过度地刺激动物性的部分,貌似会让人短暂地失去这个能力。

除了 成瘾性 ,LLM 对大脑的影响还有很多。短视频的恶性影响在诞生十年后才得到广泛关注,而即便是这样它的热度也只增不减,谁知道 LLM 会对大众造成什么样的影响?

我有实感的另一个 LLM 对认知的影响是,它加剧了确认偏误(confirmation bias)的发生。什么是确认偏误?即以「证明自己的观点」而非「了解事实」为目的收集和选择性忽略信息,认知过程从证实变成了「确认自己是对的」,这往往会造成错误。

就在最近,我经历了让我感到非常羞耻的事件。我在联邦宇宙上用英文和别人讨论 Git 新特性 git history reword,其中我们谈到了给 commit 签名的问题,对方好奇 reword 会不会影响签名。我记得我能够给 SSH Key 签名的 commit 执行 reword,但 GPG Key 签名的却不行。

这是完全错误的,我被 LazyGit 的快捷键误导了。LG 有 reword 快捷键,但这在 git history reword 发布之前就有了,它实际上使用的是 git rebase -i。由于 LG 的限制,它不能和 GPG 一起使用 git rebase -i,所以就有了 GPG 签名的 commit 不能 reword(实际上是 rebase)但 SSH Key 签名的 commit 可以的情况。当时的我没有搞清楚,于是认定这是事实,所以开始思考:为什么 GPG 签名的 commit 可以 reword,但 SSH Key 不行呢?两者是不是在原理上有所差异,比如 SSH Key 仅仅对 commit 内容签名,而 GPG 还签名 commit 的 parent hash,所以历史的变更不会影响 SSH 签名?

你发现了吗?这个问题的前提就是有错的。

为了快速得到答案,继续对话,我向 Kimi 讨教。我不熟悉密码学,相信了 Kimi 的幻觉。它说:SSH Key 是对 git commit 的内容进行签名的,只要内容没变就不影响;而 GPG Key 签名对 Git 历史更加严格,所以 rebase 等操作会破坏 GPG 签名,而不会破坏 SSH 签名。

听起来很有道理,逻辑是自洽的,但这完全是胡扯。

当我意识到自己犯的错误时,对话已经进行了几个来回了,那时还有一位对密码学颇有研究的用户参与了讨论,我好担心被他发现我在胡说八道!我飞快地跑步找到一个地方坐下,掏出电脑查阅资料求证。我翻了各种相关的文章和文章,都没有证据表明 Git 会以不同的方式处理 commit 签名。根据 Git man 页面 里有关 Git 签名格式的描述:

In every case, the command which is about to create an object or transaction determines a payload from that, calls an external program to obtain a detached signature for the payload (gpg -bsa in the case of PGP signatures), and embeds the signature into the object or transaction.

简单来说,在需要签名的时候,要创建 Git 对象的命令会决定一个载荷(payload),调用外部程序来获取载荷的签名,如果是 GPG 签名,就会调用 gpg -bsa;如果是 SSH Key 签名,就会调用 SSH 密钥相关的外部程序。这里没有说载荷(payload)会因为调用的程序不同而发生改变。也就是说 Kimi 所说的、我相信的、另一个比我有经验的工程师听过之后还觉得很有趣的「SSH 密钥只签名 commit 内容而不包含 parent hash」的说法,根本不存在。

接下来就是狼狈地道歉、编辑、撤回和澄清……

让我来反思一下这段经历:首先,我提出了一个前提就有错的问题,这个问题一开始就不存在;然后,我想出了一个理论来解释这个不存在的问题;再然后,我试图「确认」这个理论,只不过我选错了工具,LLM 通过幻觉「确认」了我的理论,并附加了许多令人信服的解释;最后,我作为卑贱的 LLM 人肉代理,传递了这个彻头彻尾的错误理论。

如果我「确认」的途径是相关的技术文档,或者一位对 Git 了如指掌的专家,就不会出现这个问题。我的「确认」会失效,我会被事实一锤子敲醒。

LLM 是个冰冷的确认偏误制造机。

我为什么用 LLM?是因为我没有能力吗?并非如此,为了写一个 Webmention 接收器和一篇 指南 ,我把 规范文档 读了一遍,把 webmention.io 的文档和源代码都翻来看了,连相关的 microformats 的 Wiki 也读了好几页。实际上,我写不少文章的时候都会查阅大量资料,浏览器会同时打开十几个标签页,开两三个标签页分组。而且,我很享受抽丝剥茧的过程。

既然我能做也喜欢做,我为什么要用不可靠的 LLM 做这种事情?这似乎不再是技术问题,而是心理学问题。

惰性和急躁——这是我目前的解释。某种程度上,高强度使用生成式人工智能还加剧了这两种特质,造成了恶性循环。

这两种特质不是刻在性格里的东西,而是短期内被影响的。短视频这一媒体形式已经被基本证实会影响分析能力2和前瞻性记忆3,与内容无关,哪怕是在摄入大量看起来很有用的知识,也会让人变笨、变得更难集中注意力,而且短期就能造成影响(研究中,刷十分钟短视频再进行认知测试,成绩就会有明显地下降)。所以,使用某种技术是有可能造成认知能力下降的,而且这种下降可能与使用技术的目的无关,只和形式与技术本身有关。技术本身就是有倾向的,Neil Postman 的《 娱乐至死 》预见了这一点。

尽管没有研究证实,但我们凭什么相信 LLM 以及其他的 AI 技术不具有这种天然的降智特性呢?而且它更狡猾,它让人以为自己在思考,因为有半主动的交互过程发生(不过有多少人在和 LLM 对话时仅仅只是在回应它抛出的「要不要我帮你……?」)。只能等待有相关的学术研究出现了。

惰性源自于对痛苦耐受程度的降低,未知是痛苦的,所以人不得不思考、探索、求助来消除未知,如今这个痛苦可以被 LLM 快速地消除,所以人们不再思考。对 LLM 的依赖可能并非源自于求知欲,而是源自与对情绪的逃避。我在《 不做信息的消费者,从写周刊开始 》中是这样定义和批评消费的。

消费是短见的应付当下情绪的行为,这些情绪往往会带来某种不适,而人们用触手可及的消费行为缓解这种不适。比如,人们通过发明短视频消解了「无聊」这一不适,通过进出商场或使用网购软件消除了「空虚」这一不适,甚至,在我看来,美国人滥用止痛药的行为也是一种消费,用于消除疼痛带来的不适。

然而,无聊、空虚和疼痛,任何形式的不适,都是一种「负反馈」,用于修正行为,提醒大脑:下次要更好地安排时间和任务,这样就不会感到无事可做;我必须直面自己的情感需求,找到空虚的源头,才能避免这种深不见底的痛苦;我以后可不能这么冒失了,必须保养好自己的身体,我太怕疼了。拒绝将自己暴露在有益的负反馈下就是在任由自己变蠢。

要说 LLM 真的帮普通人做成了什么,那就是创造了以前所未有的速度消费信息的媒介。知识本身真的重要吗?事实真的重要吗?似乎只要思绪中的未知消失就好。

Ursula K. Le Guin 在她的小说《 黑暗的左手 》里这样写道:

知道错误问题的答案是毫无用处的。

这句话出自书中隐者村的一位老者,他们的聚落举行占卜仪式,就是为了向世人展示这个道理。我写过一篇文章,论述 为什么请教 LLM 和占卜算命极其相似

Head in the Cloud

我在大量依赖编程智能体之前,其实有阅读 软件架构相关的书 ,而我的专业本身也是软件工程,不同于计算机科学等其他相关专业,我还学习了不少有关软件设计模式、需求工程和软件项目管理的知识,也因此我不至于写出漏洞百出,让人无法理解的 Slopware4,而且,我在使用智能体的时候,有尽力清晰地描述需求、做出深思熟虑的系统设计决策、做架构决策、在恰当的时机停下来进行重构,我在费力地思考。这样的过程并不是被动的,那 LLM 的负面影响会被减轻吗?

可以确定的是,我的确会在几个小时内一行代码都没写的情况下感到劳累和…… 某种程度的满足感。这种满足感并不是发自内心的「我亲手做成了某件事」带来的,而是「我好像真的创造了某个东西」。如果是我自己写代码,我会同时感受到两种满足。

劳累的原因一方面是消耗了大量的认知资源,另一方面,使用智能体编程本质上是把软件开发的抽象层提升到了需求描述、系统设计和架构设计的层面,而不再关心底层的实现思路。这好像是令人激动的发现,因为这意味着软件开发过程中需求开发和系统设计占了更多的比重,而写代码则不那么重要了,而且前者是一定要交给人来做的,需求开发在获取阶段就要和客户紧密沟通,系统设计则需要有经验的工程师做出审慎的决策,还有测试和编写文档也很重要。如果从写代码中解放出来,人们似乎有更多的精力关注更重要的事情。

代码本身就不是软件开发的全部,这是肯定的。代码没那么重要?真的吗?

代码不仅是软件行为产生的地方,也是软件架构的体现。早在 LLM 编程之前,不严肃对待架构的开发者就吃了很多苦头。由于源代码之间的依赖关系不合理,耦合紧密,导致需求变更时做出更改非常困难。开发的前期代码飞速增长,中后期则举步维艰。尽管用自然语言编程能够在宏观上把控架构(前提是使用者真的有设计灵活的架构的能力),但难以精细到代码之间的依赖关系,毕竟 AI 编程使用者不会亲自管理依赖。如果完全不读代码,致命的耦合就会悄无声息地发生。

代码也是安全漏洞发生的地方,这是无法通过系统设计消除的。如果不关注代码,就不知道机器具体做了什么,在哪一步会出问题。LLM 产出有安全漏洞的代码并不罕见,而且有些漏洞并不出现在一段代码中,而是出现在组件之间。

写代码也是开发中最令人愉悦的过程。架构设计固然重要,但做高层决策十分消耗精力,而且没有实感。需求开发、系统设计等过程,都需要和很多人协商沟通,不断地讨论和修订文档,而写代码是程序员真正意义上独处的时刻。如果让这个独处时间,也变成和另一个实体的交互过程,至少对我来说,会比自己写代码更累。

让我感到最讨厌的,是某些人抱有的玄学心态。

我某天做家务的时候在听一期讲 AI 的播客,他们没有一个人是相关领域的专家,其中有个男人讲的话非常讨厌,语气和内容都是,我听到这句话之后就立刻关掉了播客。他们本来在讨论和 ChatGPT 聊天时遇到的问题,结果这个男的没头没脑地冒出来一句:「你给 ChatGPT 充钱了吗?」对方回答没有,男的就换了个腔调说:「哎!难——怪——啊——」。

不少人把具体的工作变成了与聊天机器人交互的过程,这就诞生了不少毫无根据或者被夸大的玄学,比如提示词神话,比如「你给它开启专家模式」「你调整一下 LLM 的记忆」,比如订阅什么价位的方案,比如在没有数据支撑的情况下根据自身局限的经验判断模型之间的优劣并十分笃定,以及任何类似于「必须要这样和 AI 聊天才能获得好的结果!」的说辞。

代码本身是确定的,是冰冷的,是无聊的,是可证伪的。如果我们在讨论代码层面的事情,那么我们非常容易相互理解,因为我们都清楚代码的执行路径、依赖关系、数据流等等,也就更容易讨论得到解决方案。倘若我们抛弃代码,去讨论模糊的自然语言,讨论怎么和智能体进行交互,那只会诞生出越来越多的玄学迷思,因为 LLM 本身就不是决定论(deterministic)5的。完全抛弃代码,全面使用 LLM 编程,会把技术问题变成模糊且不可控的儿戏。

如果你不太能理解,请类比:当人们讨论翻译的时候不再讨论新概念的译法,不再争论译文应该保留外国文化还是尽可能本土化,而是争论哪个模型做翻译更好、争论怎么写提示词能得到质量更高的翻译、鄙视那些不用付费模型做翻译的译者……

非决定论的技术

人们似乎都相信一个尚未被证实的假设上:AI 真的能代替人。

几乎所有人都在夸大这项技术的影响,实际上,就和所有计算机程序一样,没有输入就没有输出。银行有非常健壮的自动化软件系统,但仍然需要柜员和人工服务。不过比一般的软件系统更危险的是,大语言模型不是决定论的。

决定论原本是哲学词汇,认为一切都是注定会发生的,因为宇宙从一开始的状态是确定的,而物理规则也是确定的,那么从最初状态按照固定的规则运行下去的世界,任何一个时间点下的状态都是由最初状态和改变状态的规则决定的(这很像个迭代器)。谈到状态,就很容易联想到计算机系统了。状态就是计算机处理的数据,规则就是程序本身。对计算机来说,确定的输入得到确定的输出。

这并不适用于所有计算机程序,因为状态有可能影响规则的执行。程序的语句之间可能存在时序耦合(temperal coupling),即前面的语句在执行后改变了系统的状态,而这个状态使得后续语句的行为发生改变,导致偏离预期。如果说时序耦合还有办法解耦(比如使用美妙的函数式编程),那么近似黑箱的神经网络模型就几乎无法根据输入和输出进行调试了。对于大语言模型,确定的输入无法得到确定的输出。大语言模型是非决定论的。

这样可怕的软件,甚至没有办法编写测试用例来保证稳定性。幻觉已经是陈词滥调了。既然传统的软件系统都没能消除人工,凭什么相信更加不稳定的技术可以?

由于输出不可预测,为了保证可用性,就必须介入人工调控。因为计算机程序没有主体性,不能为它交付的工作成果负责。你不能问责机器,但你可以问责员工,所以人需要为 AI 提供输入,并为它的输出负责。

在维持算力成本的同时还需要支付人工成本,这么做真的值得吗?我不是在全盘否定 AI 技术的应用,AI 会留下来的,我也认为它能给一些行业的某些人带来积极影响,但所有人都立刻将 AI 用于生产,至少在成本上并不明智。关于成本,我会在下下小节谈到,接下来我们先聊聊另一个问题。

幕后的受害者

前文我讨论了我不想让 AI 帮我做事的心理原因,依赖 AI 技术可能造成的认知能力下降,将技术细节提升为高层决策带来的模糊性和不可预测性,以及大模型本身的非决定论特质。接下来我要讨论更棘手的问题——道德。

在 2026 年浏览万维网,除了能够发现更多设计现代化、功能更强大的网页应用之外,还能发现更多无法直接访问的小网站。

免费代码托管平台 NotABug.org 被迫停止 Web 访问,现在用户只能通过 SSH 访问已有的 Git 仓库,原因是:

Due to relentless AI scrapers notabug.org is currently down.
由于没完没了的 AI 爬虫,notabug.org 目前无法访问。

We are attempting to come up with a solution to this problem.
我们正在试图找到问题的解决方案。

稍微大一点的网站,比如 Wikipedia,去年也深受其扰。他们在去年四月发布的 文章 中表示,昂贵的流量中有 65% 都来自机器人。

我平时是关闭 JavaScript 的,只对信任的网站打开,而不少网站的反爬虫策略利用了 JavaScript 和 Cookie(爬虫不执行 JS 代码,也不储存 Cookie),我也会被错误拦截。

访问 Debian 的包目录 ,会显示:

AI scrapers break the web, to use this page you’ll need JavaScript enabled.
AI 爬虫毁了 Web,要使用这个页面你需要启用 JavaScript。

大大小小的代码托管网站都使用了类似的反爬手段,比如 Codeberg ,我自己的 Forgejo 实例 也一样。这些平台本身是开放且尊重用户的,不需要使用 JavaScript 和 Cookies 也能正常访问,但 AI 爬虫的猖獗让他们无法正常提供服务,必须采取限制手段,否则要么服务器被打趴下,要么任由肮脏的机器人给自己留下昂贵的账单。

所以,这显然是个道德问题。科技公司是吸血鬼,他们利用开放的万维网内容训练 AI 模型,从画师在网站和社交媒体上发布的作品,再到各大代码托管平台上的开源代码。他们为了做出有竞争力的产品,不择手段,完全违反 robots.txt 协议6,不管小网站的死活,没有意识到自己行为实际上与 DoS 攻击无异。

使用 AI 绘图、编程、写文档、做任何事情,不都是在变相吸这些受害者的血吗?我们还没有开始讨论版权问题。

更现实的代价

让我们以企业的角度来思考问题,员工使用 AI 技术更快速地工作,让他们变蠢、变迟钝、变得上瘾看起来不道德,AI 技术本身让社区、非营利组织和小公司生不如死好像也很不道德,但道德和金钱比起来算什么呢?AI 好像能以更低的价格实现更快地增长,不是吗?

根据 Axios 发布的一篇 文章 ,互联网科技公司在 AI 上花的钱已经超过了员工的薪水。

运行大模型和如今主流的各种 AI 技术都不便宜。据从事学术研究的某位老师透露,我所在的学校能供学生使用的只有一块显卡,不足以支撑某个学生的研究方向,他不得不放弃,换个方向从头再来。如果在个人电脑上跑,只能以很低的效率运行参数较小的模型。那为什么这么多的科技公司提供免费的 AI 聊天机器人,以至于人们早就习惯使用 AI 了呢?我最不能理解的是那些使用大模型生成随机数以抽点学生的老师,你为什么要消耗这么多的计算资源,就为了得到 Excel 表格也能输出的结果?为什么人们觉得 AI 像是不要钱一样?

因为大科技公司花钱的方式就跟钱不值钱一样。

AI 泡沫如何破裂 》这篇文章从经济学和投资的角度预测了未来 AI 行业的发展,并不乐观。简而言之,大科技公司不需要在技术上胜利,他们只需要一直花钱,花的钱比竞争者更多就赢了。人们推测 Claude 方案的实际成本要比订阅费贵五倍(不过最近上调了),更别提大多数人其实不给 AI 模型付钱,免费使用消耗的算力也够多了。

钱从哪来呢?Google 这样的公司钱很多,玩得过所有人,而 Anthropic 和 OpenAI 这边就不容乐观了。Anthropic 在尝试 降本增收 ,而 OpenAI 不得不往 ChatGPT 里增加广告,因为他们的购物功能以及视频生成模型 Sora 全都没了,赚不到钱。他们极度依赖投资者的钱,而赚不到钱但增长迅猛的企业看起来比那些一直赔钱也没有增长的企业值得投资多了。

不过投资者的钱总会烧干的。作者还推测那些为 AI 建好的数据中心可能因为市场需求的下降而闲置(因为为了赚钱回血,产品的价格会升上;最基本的经济学原理之一是:价格上升会导致需求下降),导致我们可以以非常便宜的价格买到云服务器,而 GPU 的需求也会下降,英伟达就要遭殃了。

尽管这些都是推测,但可以确定的是,搞 AI 很费钱,而不是所有人都愿意支付高昂的价格。此外,由于 AI 公司提高模型价格,我们还看到 IT 公司的 AI 支出超过了人力成本,对使用 AI 的公司来说,AI 也不如人类有性价比

当然,这些情况明天就可能有改变,毕竟现在 DeepSeek 的 API 价格是真的便宜,似乎也没有相关报道显示他们有遇到财政危机,兴许上述问题都会在不久之后被解决。兴许摩尔定律会复活,算力会突然变得更便宜,谁知道呢?

出路在哪?

你问我?我只是个什么都不懂的小屁孩儿。

让我来整理一下这篇已经变得有些奇形怪状的文章吧。

大模型极有可能是《娱乐至死》中所言的那类「有倾向的技术」,其对话的形式与短视频媒体一样具有降智属性——和老虎机一样的操作逻辑,让人成瘾;对比短视频推荐算法创造的信息茧房,大模型的幻觉、模糊性和信息筛选能力可能加剧确认偏误;由于在某种程度上快速地消除了无知给人带来的不适(消除的是不适,而非无知本身),大模型成为高速的信息消费载体。

在工作生产层面,大模型抬高了工作的抽象层,让人们不再接触具体的、确定的、无聊的、可证伪的工作,而是让所有工作都变成模糊的自然语言处理,技术、技能、技巧失去意义,被模糊和不可控的玄学取代。

由于生成式人工智能是非决定论的,并且作为软件无法被问责,于是在消耗算力资源的同时仍然要消耗人力资源来调控输入与输出,并对交付的结果负责。随着 AI 泡沫破裂,价格上升,算力成本也超过了人力成本,对企业来说并不划算。

更值得注意的是,AI 模型建立在不道德的基础上,科技公司用不遵守规范的网络爬虫攻击非营利组织、开源社区、绘画社区、小型企业以获取数据,而 AI 的使用者也被吸血鬼反哺着,付给 AI 公司的每一分钱都是市场需求仍在上涨的证据,是在鼓励这种不道德行为继续猖獗,没有一个人是无辜的。

呼…… 让我歇一歇,来关注我自己的感受。

现实是残酷的,尽管短视频对人有害已成共识,也有科学研究做背书,但人们依旧无法停止刷视频,金钱仍然会汇聚到视频行业中。去做短视频(或者和短视频一样有吸引力的长视频),就是能挣到钱。

同理,尽管各类 AI 技术的好坏还有待辩驳,但无论如何,它看起来都不会消失,它依旧是目前最受关注的领域。尽管行业可能会受到不少冲击,但我不觉得我们能回到 2021 年前的世界。所以,似乎仍然可以得出相似的结论:去做 AI,就是更有竞争力。

兴许最幸福的人不会像我这样思考这么多,他们会投身到这些赚钱的行业里,并且不觉得有任何问题。我想的太多,于是踌躇不前。

唔…… 我好像还在用 AI 编程来着。我该停下吗?

我自然不能在面试被问及「你有 AI 编程经验吗?」「你怎么看待 AI?」时把这篇文章的主要论点给面试官讲一遍,除非我想没饭吃,企业想要的当然是能够用 AI 为它们创造更多价值的人。可我总对撒谎和谄媚感到非常不适。

此外,用 AI 应付工作和学校项目实际上剥夺了我工作的成就感、价值感,这对本身就不喜欢工作的人来说可能无足轻重,但就像我在开头说的,我是个喜欢写代码的程序员。更何况,哪怕是耗时并不算多的 AI 编程,也像刷了一小会儿短视频一样影响了我的认知能力,影响了我手写代码时的状态。这是具有成瘾性的技术,自然有戒断反应。

我谈到我在用 OpenCode 开发学校的项目,但选题是我自己定的,需求和设计是我自己做的,技术栈是我自己选的。尽管多少抱着完成任务的心态,但我在开发过程中逐渐对这个「作品」产生了情感,我突然有了更多期待。它可以作为毕业设计,也可以是更长期开发的项目,我还有可能自己在日常的工作生活中使用它。

而当我翻看它的源代码时,我感到非常陌生。无论怎么辩驳,它的确很像是个 Slopware。我感到陌生、担忧、心虚和失望,只能为我在一开始设计了灵活的抽象接口而庆幸。或许我该做些 Vibe Code 清理工作了。

不过在这之后我该怎么办?我不知道,我只知道,我不想让任何技术、任何人,再夺走生活中为数不多的能让我感到快乐的事了。

推荐阅读


  1. Ghostty 的分屏快捷键,分屏后打开新的终端窗口 ↩︎

  2. 参见: Swiping more, thinking less: Using TikTok hinders analytic thinking  ↩︎

  3. 参见: Short-Form Videos Degrade Our Capacity to Retain Intentions: Effect of Context Switching On Prospective Memory  ↩︎

  4. AI 生成的废料被称作 Slop,而 Slopware 和 Slop 和 Software 的缩合词。 ↩︎

  5. 如果你不了解这个词的具体含义,我会在后文展开。 ↩︎

  6. 大部分网站都会提供 robots.txt 文件,声明允许哪些爬虫,不允许哪些爬虫。AI 公司的爬虫根本不在乎。 ↩︎

Browser’s Bookmark Manager Is Actually Good

I deleted Linkding . It’s been running on my VPS for quite a few months and I decided to retire it. To be fair, Linkding is really nice, and it comes with a powerful ecosystem. There are a lot of client apps and people even make Apple shortcuts for it. The omg.lol community started to host one recently and it seems genuinely cool.

So, why do I abandon such lovely FOSS software?

Well, I don’t really need a service that keeps running 24 hours. It’s just a bunch of links. It’s handy to share bookmarks via a straight-forward web page, but I don’t need it. I post weekly in Chinese and it’s basically a collection of links I have looked at and found interesting.

The only thing I’ll be missing is that a self-hosted bookmark manager acts as something you might call Single Source of Truth. I save links to the one and only Linkding instance from all of my devices. I won’t have to go through different apps or devices to find what I want. There won’t be links scattered around and it won’t feel messy.

I would say SSoT is a natural trait of web services of this kind. Other solutions can aquire this trait, preferably by hitchhiking a service that you already use, like a cloud storage or a remote Git server.

So I found floccus , a tool for syncing bookmarks across browsers and devices. Basically, it stores your bookmarks in open format, into a remote file system, and this remote is very close to SSoT. Browsers installed with floccus fetch from remote and update local bookmarks. Existing bookmarks are either deleted or uploaded to remote, depending on your configuration.

Voilà, all your bookmarks now lives locally in your browser and they’re synced seamlessly. If you backup your cloud storage, they also have backups.

What about tags? And bundles? How can you manage hundreds of links without them?

That is a significant downside of most browser’s native bookmark manager (Firefox supports tags, but they cannot be synced to other browsers). Personally, I settle for folders. Hierachy is almost enough for my bookmark management needs.

An additional trick I do is renaming bookmarks with distinct text. Like this link , it’s titled Thoughts on slowing the fuck down, you wouldn’t know it’s about AI, the IT industry, agents and perhaps a little bit of philosophy. To solve the ambiguity of such titles, simply rename it by appending tags in the end.

Thoughts on slowing the fuck down. #AI #Agents #IT #Coding

Or any other format you prefer.

This may seem dirty, but it’s practical. When I was using Linkding, I almost never use tags or bundles. I like organizing stuff and categorize links. But I don’t find links by categories or tags. I just search.

As far as I know, Linkding and many bookmark managers don’t have full-text search ability. Most of the time I search titles. If titles are clear, finding stuff would be easier. There’s no need for tags.

Well-managed local bookmarks comes with hidden benefits. If you use URL bar a lot, you’ll know that browsers auto-complete your search based on search suggestions, history and bookmarks. If you have a certain link in local bookmarks, you can just find it in URL bar, with enough identical text provided. Vimium also supports this, press O, type what you want in the popup window, and you’ll find it very quickly.

So even if you don’t organize your links, by merely saving it in local bookmarks, you make it easier to find.

I think, overall, this approach is simple and actually good. Good enough for most use cases I’ll say. And it makes me wonder what other services I rely on can be replaced with a local-first or local-only solution.

For those who want to be more organized, in additional to dirty text tags, try the PARA method and Johnny.Decimal . Create your own if you’d like.

Web links can be reading materials (blog posts, news reports and documentation), conversations (social media threads, forumns and issues of git repositories), web apps, media (videos, music and games), product landing pages and many other stuffs. I suggest create individual folders for each category, like this:

  • Reading List
  • Conversations
  • Media
  • Miscellaneous
  • Archive

Create sub-folders if you must. I like to keep minimal hierachy because it’s easier, and with our text tags hack, you won’t need more categories.

I’ve been doing this for two weeks and it feels smooth. Hopefully I won’t get to the point where I find myself desperately going back to Linkding, though I don’t really see why I might.

稻草人周刊 Vol.78

又过去一周了吗?时间仿佛有意志一般,在我最脆弱的时候以极快的速度流动,。 上周去美术馆 的事情到这周日才写,这周一感觉效率很高、状态很好,在周二周三上了两天课之后就失去动力,神智不清了,在周四周五的时候才意识到:这周就这么过去了啊。


止语

THIS MUSIC MAY CONTAIN HOPE. music cover

THIS MUSIC MAY CONTAIN HOPE. 专辑

Raye

一张听起来有剧院感的专辑,尤其是最后一首《Fin.》,非常像音乐剧的原声带,另外你怎么还把致辞放在专辑里面啊哈哈哈

Raye 的嗓音很好听,哪怕是「报幕」也很有质感。专辑是一场完整且连续的剧目,Raye 甚至会在歌曲的开头告诉你这首歌叫什么名字,总之形式上还挺新颖的。专辑里也包含了不少私人情感,我尤其喜欢《I Hate The Way I Look Today.》,不阳光、不积极,但也不丧、不绝望,恰到好处地阴郁和自嘲,听这首歌的时候我想起了告五人的《啊我忘了带伞》。


连接

如何像照顾狗一样照顾自己?

📻

如果狗狗心情不好,狗主人仍然会给狗狗吃健康的、完整的食物,而不是让他吃好吃但对狗狗健康有害的加工食品。无论发生了什么,狗主人都会雷打不动地带狗狗出门活动,让狗狗按时睡觉。狗狗做错了事,好的狗主人也不会苛责狗狗,不会打骂,更不会否定狗狗的狗德,只是会纠正错误。狗主人不会因为狗狗的一点行为就把他彻底当作坏狗狗,而是提供能够接纳他个性的环境,让他感到安心。

而人竟然不会像照顾狗一样照顾自己。

有趣的是,我在这期播客的评论区里看到了这样的内容(我竟然破天荒地去看了评论……):「狗狗需要通过闻嗅和探索来减少在家里的焦虑」。这恰好是我最近在做的事,因为我发现自己在家的时间太多了,一直处在同一个环境里,整个人会废掉,有的时候一整天过去甚至不知道自己做了什么(有可能确实做了不少事情,但没有实感,也不会感到快乐),而且非常容易陷入焦虑和抑郁。

最近我在试图建立起一套新的作息,早晨避免摄入碎片化信息,在晨练后看书或者写作,尽量进入心流状态。如果状态好的话,早晨还能做一些别的工作,推进项目,这时的效率额外地高,有时还能超额完成一天的计划。下午必须要出门,因为这个时候我的状态是最差的,要么出门遛弯,要么去图书馆或咖啡厅等自带专注氛围的场所工作,效果往往好很多。至于晚上,吃过一顿满足的饭之后就开始玩游戏,在《饥荒》的世界里也四处奔波、把比自己大几倍的头目打趴下、收集资源建设基地。这一切结束之后我往往会感到很满足,不会躺在床上焦虑地刷社交媒体,迟迟不肯入睡。

不过我想人和狗最大的区别在于,人(至少是我这样的人)很难保持高能量和对一切充满热情的状态。至少我常常在保持两天的规律作息之后突然力竭,接下来的两天又陷入了不知道自己在做什么的状态,我想这是我下周需要实验和搞明白的课题。

万维网是个吉他音响(字面意思)

📜

不是比喻,就是事实,你可以把吉他插进电脑的接口,然后在一个网页上捕捉音频,再用耳机或者别的音响设备收听。这得益于 Web Audio API 允许网站访问音频输入,以及 WebAssembly 使得浏览器上可以运行低层次代码(毕竟 JavaScript 的性能实在不敢恭维),以获得和原生应用比肩的速度,当然还有背后的开源软件 NEURAL AMP MODELER

总而言之,作者感叹 Web 比以前变得更加强大的,甚至可以代替不少原生应用(尽管严格来说,直接造成这些改变的应该是前端技术的进步而不是整个 Web)。不过我总感觉很多人还是把前端和 UI 当成一回事,听了这些老登言论的小登也对前端开发抱有偏见,甚至都没有去探索前端的真面目,一头栽进了 Spring Boot 这个怪兽里,至少我身边的人是这样。唉。

不过,在前端技术变得越来越强大的同时,也需要警惕,有意识地去控制 JavaScript 脚本的运行,像对待安装在自己电脑上的软件一样严格地对待网页应用。1

容器化是必要的吗?

📜

这周我把一部分服务迁移到了另一台 VPS,我重装了 Arch Linux 并且浅尝了 Guix ,同时我开始考虑要用 Docker 还是 Podman ,不过我很快开始思考更关键的问题:我需要容器化吗?

我记得半年前读过一篇文章,如今已经找不到了(那个时候我还没有很好的书签管理习惯),文中大概是说:systemd 在大部分时候已经能够满足需求了,你不需要 Docker(或者其他容器化技术),而且容器化在某些情况下很麻烦。我向来很喜欢化繁为简的想法,比如我就不喜欢 React 的虚拟 DOM,觉得是没必要的抽象层(除非你真的在开发非常复杂的前端项目),而容器化似乎也是一层多余的抽象(除非你在部署和管理很多服务)。

我要迁移的是 我自己写的 Webmention 接收器 、两个 Hugo 静态网站以及他们的构建脚本、用于触发构建的 Webhook 服务器以及 GoatCounter 。这些服务非常简单,都只需要一行命令就能启动(静态网站甚至不需要单独跑服务,有 Caddy 作为 Web 服务器就好)也不需要管理复杂的环境变量和数据库(文件存储和 SQLite 真是伟大的发明!)。所以,看起来我的确不需要容器化,systemd 足矣。我也有考虑 Shepherd ,这样就可以用 Scheme(一门 Lisp 方言)编写服务了。

不过我还是想要了解其他人的观点,于是找到了这一篇。作者的观点很有意思,他的确认为「你不需要容器化」,但他觉得「你可能想要它」。的确,Web 应用不需要容器也能跑起来,甚至不需要复杂的应用程序框架和前端框架,但要是没有这些现代化的技术,可能大家就不情愿做复杂的开发了;而且如今的万维网已经不是以前那样,一个网站可能一整周都无人问津,现在的开发者要随时做好迎接更多流量的准备。

不过我对这个观点有些质疑:首先,容器化并不是这些问题的一键式解决方案;其次,人们似乎在讨论完全不同的问题,没有把个人项目和用于生产的 Web 应用分开,后者当然要用成熟且易于使用的技术。不过总体而言,我还是很认可「不需要但是想要」这个说法的,我认为开发者能自己做好权衡取舍就好了。

所以我权衡取舍的结果就是:我的软件全部以服务的形式跑在宿主机上,我不想要容器化。

我们一天也没有聊点诗意的东西

📜

读完之后有很多感受,但一个字也写不出来。大概是因为我最近也在被迫思考很多现实的事情,却不想放弃自我和理想,可我某天猛然发现,我好像已经不知道自己的梦想是什么了。在二十岁的年纪失去目标,应该还挺普遍的,但的确很可怕。

我记得一两年前,我的目标是游戏开发者,很巧,我那个时候的室友也有同样的想法。如今看来,这像是老天在给我提供人脉,可我躲掉了,也不能怪我,我不喜欢他的性格,重新分宿舍的时候我刻意填了不要和他待在一个寝室。再过了一会儿,我直接搬离了寝室。回忆起来,开始走读的那段时间,就是我彻底放下游戏设计和游戏开发的时间。之前的我想要去留学,因为国内没有我想要的游戏设计专业,被我父亲以「中国就是最好的」否定了,在那之后,我陷入了漫长且痛苦的迷茫期。我完全不知道自己该干什么。2最近我得知,那位前室友已经去上海某家游戏公司实习了。我感觉所有人都在往前走,而我在交叉路口不知所措。

是的,我最熟悉的是前端技术,我也完全可以做全栈开发,但…… 他们更像是务实的选择,不是诗意的理想,换句话说:没有使命感。到现在我也似乎再也想不明白我到底想做什么了,而我又处在这样一个阶段,所有人都要求我把一切精力都上交给残酷的现实,而这些人,说实话,他们也不知道该怎么办,那个给我上职规课的老师每天危言耸听散播焦虑,而她竟然连 GitHub 是什么都不知道。

兴许我不该从事业中找寻诗意(这句话写出来我才发觉它有多么可笑),而是应该尽力在有限的属于自我的时间里去找寻快乐,去好好生活。具体应该怎么做呢?我不知道,或许我应该先把自己的生活梳理清楚吧。


星群

Olive CSS

使用 Guile Scheme 编写的原子 CSS 框架,类似 TailwindCSS 和 UnoCSS。最大的优势是它完全不依赖 NPM 和 JavaScript 生态。在我看来这对 Hugo 等不使用 JavaScript 或 TypeScript 编写的静态网站生成器来说尤其有用,当然也适用于其他各种语言。正好我一直在找不依赖 NPM 的原子 CSS 引擎,因为我想从博客的构建流程中移除 PNPM,之前我在 UnoCSS 的 Issues 里找到过相关的讨论,主要维护者表示「不使用 JavaScript 的 UnoCSS 没有意义」。当时我还想把他们的 CLI 单独打包成二进制文件,可惜技术能力有限。如今看来 Olive CSS 是近乎完美的替代品。

Olive CSS 没有实现 Tree-shaking,也就是不能自动移除没有用到的 CSS 类。我提了个 Issue ,作者表示它的确想要加上这个功能,但近期还不会加上。我在考虑学 Scheme 去帮忙开发,但我的速度大概不会比 Joe 自己动手来得快。


然后我提 Issue 的第二天有只 狐狸 就飞快地提了 Pull Request可怕,实在可怕。

我还没来得及研究怎么使用这个库,毕竟我不熟悉 Scheme,这应该是我下周会做的事情。我准备用 Olive CSS 替代 UnoCSS,这样就可以移除网站的 PNPM 依赖了。最近 NPM 又被投毒了 ,这次是 Bitwarden CLI(命令行工具就别用 JS/TS 写了吧!),真害怕下一次就轮到我用的库了…… PNPM 似乎有规避供应链攻击的手段,但我还没仔细研究,如果不是做复杂和大型的前端开发,还是想尽量离 Node.js 生态远一点。

访问: jjba23/olive-css

url.town

omg.lol 社区维护的万维网目录(Web Directory),我之前在《 带着鸭鸭和狗狗逃离咕噜咕噜 》里介绍过这种目录。在现代搜索引擎还没有诞生的时候,人们手动维护目录,按类别归类网页链接,这就是当时的人们在万维网上发现新东西的方式。url.town 也是这种模式,十分复古,在上面能找到社区成员手动挑选和添加的链接,是发现高质量新鲜内容的好地方(不过里面的很多链接你可能已经很熟悉了)。

访问: url.town

miasma

本周刊不能讨论的技术往往使用不道德的网络爬虫获取新鲜的人类内容,他们忽略 robots.txt 协议,对服务器发起大量请求,造成负担。Miasma 给这些机器人投毒,把他们困在无止尽的垃圾内容循环中,增加大科技公司处理数据的成本。

简单来说,在网站中添加一个隐藏链接,真人看不到,但爬虫会跟随链接并发送 GET 请求。

<a href="/naughty-bots" style="display: none;" aria-hidden="true" tabindex="-1">
 Amazing high quality data here!
</a>

在 Nginx 或 Caddy 等 Web 服务器中,把 /naughty-bots 反向代理到 Miasma,接下来它就会为这些不怀好意的爬虫提供无止尽的垃圾内容。这种做法不会误伤,你只需要在 robots.txt 里这样写:

User-agent: *
Disallow: /naughty-bots

这样所有听话的爬虫(比如搜索引擎爬虫)都会乖乖地不去动 /naughty-bots 路径下的内容,而那些贪婪的、什么都想要的爬虫就会掉进陷阱里。当然,爬虫程序忽略 /naughty-bots 路径很简单,所以 Miasma 允许自己配置路径。

我的 Forgejo 实例 也使用了反爬虫策略,由于不需要 SEO 所以就无差别禁止了,也没有做投毒。Codeberg 使用的应该也是类似的方法。我参考的是 Yann Esposito 的文章 ,简单来说,除了 User-agentgit 和部分特殊路径的请求,都默认返回一个只有 <script> 的网页,这个脚本往用户的 Cookies 里写入一个字段,然后刷新页面;拦截器不拦截带有这个 Cookie 的请求,所以刷新后直接放行。由于爬虫不执行 JavaScript 代码也没有 Cookie,就会被拦截。

这种做法的缺点是,它也拦截了那些禁用 JavaScript 或 Cookie 的用户,所以只能在拦截器页面留下一段说明,友善地请用户打开 JavaScript。不过 Miasma 不会直接拦截整个请求,而是在普通的页面里留下陷阱,大概是更好的做法。

访问: Miasma


切片

  • 个人主页新增了 /speaks 页面,列出了我会说、正在学和想学的人类语言。

  • 把博客的 标签 重新整理了…… 正在严肃思考应该怎么对待这个混乱的东西。

  • /glossary 现已登录 slashpages.net ,你可以查看我的 /glossary 页面。我最近发现 RMS 也有 glossary ,他给…… 特朗普取了很多外号

  • 因为大量依赖自托管服务,为了防止失联,做了很多措施。首先是邮件服务完全依赖靠谱的提供商(位于瑞士的 Migadu ,这个国家有着全世界最严格的隐私法律)。这周我还在 xmpp.earth 这个公开实例上注册了 XMPP 账号(eltrac@xmpp.earth)备用,自建的 Matrix 服务器意外下线时使用,也和一些不用 Matrix 的 XMPP 用户联络。

    我的联邦宇宙账号也在自建的 Akkoma 实例上,所以我也找了个看起来不错的公共实例注册备用账号,顺便用来发英文内容,和英文使用者社交(毕竟我的主账号大多数时候都只发中文内容)。这个账号是 @eltrac@tech.lgbt

    另一个措施是(前文提到过)把一部分服务迁移到了另一个 VPS 上,使用不同的服务提供商,这样如果一台服务器爆了,另一台多半也在线。

  • 新 VPS 装了 Arch Linux 和 Guix 。Arch 我还算熟悉,但 Guix(虽然很像 Homebrew)还是太新了。我在配置频道的时候硬跑了好几次 guix pull,因为 VPS 的 CPU 性能太差导致每次拉取都要跑十多分钟…… 再者我还没有学会 Scheme,所以…… 下周再说吧。

  • 最近的主线和支线:

    • 读书,读一些技术相关的书,也重新开始读哲学。目前正在读《Functional Design》和汉娜·阿伦特的《人的境况》(你怎么知道我有仲树老师亲笔签名的版本?

    • 做学校的项目,也算提前为毕业设计做准备。由于不想手写所以高强度使用 Coding Agents(DeepSeek API 好便宜,我爱你……)。有意识地优化架构和提供清晰的系统设计思路的话,即便用很一般的模型效果也不会差(就是 Debug 的时候会难受很多,还得自己亲自下场)。唯一的乐趣是在这个项目里嵌入了一个轻量级 Lisp 方言当作脚本语言(Lisp 真的很方便嵌入其他语言欸),最大的败笔是为了讨老师欢心,要往里面加上不少 LLM 功能。3

    • 消遣时写 Lisp 代码,有写 Clojure 推进某个 Side Project,也在用 Fennel 配置 Neovim,最近还打算学 Scheme。我严重怀疑学校项目不想手写的很大一部分原因是我连 Go 代码都不想写了,哼哼,什么时候可以用 Lisp 做前端开发?

    • 开了个《饥荒联机版》单人档,每天晚上固定上线,某天在一天之内打了三个 Boss,下线的时候还在为打另一个做准备…… 总之非常解压,是维持 san 值稳定的好方法。

      我发现火女薇洛真的是最适合我的角色,没有队友就把小熊放下来一起暴揍怪物,还不需要像韦伯和沃特那样培养一大堆军队才能上场。小熊还能吸引仇恨,对付影怪,不需要了就收起来放包里,没血了就用缝纫包缝好。这种又方便又可靠的伙伴只能在游戏里找到了吧!获得技能树之后能喷月火也很方便,清群怪堪比温蒂,拉远一点还能用来无伤打克劳斯。

      说起来,我有点想自建一个 PeerTube 实例录点游戏实况,不知道会不会有人看。

  • 唔,也算是暂时把我的生活梳理清楚了吧。


  1. 参见:《 什么毁了 JavaScript? 》 ↩︎

  2. 相关文章:《 写在 2026 的开头 》 ↩︎

  3. 等等,这好像是本周刊的禁忌话题…… 正文里没有出现就好…… ↩︎

我们摆出不被理解的面孔自得其乐

上周末出门遛弯,去了趟美术馆。尽管有些路程,但我预约看展的次数还不少,这类活动既满足了出门摸草的需求,也不需要和人打交道,即便是出在公共空间,也是在和自己的思绪和感受独处,总之是很高质量的体验。

我去的时候,美术馆一共有三场展览,第一场是长期的美术馆的馆藏展示,第二场是某个品牌赞助的雕塑展,第三场是一个艺术家的个人展,我似乎还恰好赶上了这场展览的最后一天。对我来说,去美术馆其实还能固定看到隐藏的第四场展览,那就是其他看展的人。来看展的人一般不多(也使得这个地方逛起来很舒适),人员很容易归类:给学生讲解展品的老师,带小孩来感受艺术的家长,情侣,拍照打卡的大学生,和独行或成对出现的真正对艺术感兴趣的人。去美术馆看的不就是人文嘛,路人也是极佳的素材。

馆藏展

第一场展览进门的地方几乎都是又红又专的展品,比如旧时宣传革命胜利的连环画就摆了一整面墙,还有不少描述大好河山的风景画。我只能稍微加快脚步,让展品滑过我的视野,同时也不错过可能出现的有趣展品。

有两幅画看起来还不错,第一幅是花,我很喜欢低饱和度的色彩,看起来没有很亮眼,但也不暗沉,质感又有点像是布料,很舒服。第二副是人物画,比例很有趣,人物的头和眼睛都被放大了,但没有夸大人物的情绪和神态,有点像写实风的卡通角色。

作品名:花与桃

这幅看上去像暴风雨夜,能看到雨滴,隐约似乎还有海面的波涛。中间有一块方形区域格外突出,似乎是画中画,里画的波涛清晰很多,画风看起来和外面略有差异。不过这幅画中画和外面的部分是连着的,雨和浪的位置和外部是重合的,但里画如果单独拿出来也是完整的。好有意思的构图。

还有一副吸引我的作品名叫《蜉蝣日记》1,老实说我完全看不懂作者想表达什么,我只是觉得整幅画的风格很有意思。浴缸里的人有两个头,另一个不正常的头有点像是哥布林之类的生物,他们都从游泳圈里冒出头来。画面底部还有一些看起来像是虫的黑色线条,可能与名字里的「蜉蝣」有关系吧。

作画方式似乎有融合拼贴,所以画纸的周围参差不齐,画面中有些位置有不自然的轮廓,中间的血渍貌似也是拼贴上去的。

这个展厅的人是最多的,我想这是美术馆有意设计,把最大众2的展品放在离入口最近的地方。进门的时候看见有很多人坐在墙边,还有一些蹲坐、聚集在一起的男大学生,看起来根本不属于这里。他们的样子让我想起那些聚在厕所偷偷抽烟的高中男生。我猜测这些人是被强迫来参观的,发现无人看管,便跑到了一边玩。

还有一些聚集在楼梯间,我不敢接近他们,绕了一圈才找到电梯上楼。

雕塑展

上楼之后晕头转向地走进一个展厅,貌似是雕塑展。其实我刚来的时候,只在预约的小程序上看到两场展览,这场不含在内,也算是意外之喜吧。这些雕塑没有一个符合我对雕塑的刻板印象,这些美术生个个都在整花活。

展厅里有一个区域堆满了各种座椅,而且都是办公室里常见的,可以调节高度,有一定金属结构的。座椅上黏着着膜状和化石一样的东西,地上还散落着石头(也可能是骨头碎屑)。其中有一个雕塑接上了电源,一直在上下伸缩,这个椅子本身也是畸形的,椅子腿像是章鱼触手,看起来像外星生物。

去读了读作品介绍,主题是「劳动对身体的异化」,不得不说的确很形象。

另一个雕塑应该是全场最高的,延伸到了天花板,到现在我也没想明白工作人员是怎么把它运送进来的,难道是作者在现场组装的吗?如果是这样的话,这年头搞美术都要会操纵升降梯之类的施工工具了吗?无论怎么样,非常佩服。

这个雕塑名叫《一百个人的孤独》,完全由小人组合而成,像藤蔓一样延伸,从地板爬上墙,一直到天花板。每个小人都不一样,有没有一百个人我没数过,但很震撼就是了。雕塑摇摇欲坠的感觉应该是刻意营造的,不过的确很吓人,我怕被砸到不敢久留。我想这件作品的确把孤独的窒息感表现出来了。所有人都连接在一起,都没有人相互理解,没有交流,这个集合体随时有可能散落,不复存在。看起来,这些人也不在乎群体的命运。

展厅里最有趣的应该是下面这个系列。

雕塑描绘的是一个一个的场景,这些场景都是人群聚集的公共场所,比如电梯间、剧院和展馆(在展馆里看展馆,十分 Meta)。不过这群人都没有脑袋,雕塑带有一套机械结构,每隔一段时间就会降下似乎是装有肥皂水的装置,装置移开之后这些小人就会长出泡泡脑袋。其中有一个雕塑的人是倒立过来的,旁边有一个摄影机把画面翻转过来之后,显示正立的图像在显示器上。我不太明白用意,一开始以为是肥皂水必须放在下面的水缸里,所以雕塑就要倒过来,但其他作品倒是可以保持雕塑正立。可能作者尝试了不同的结构吧。

以剧院为场景的雕塑,是可以按下按钮互动的(还有一个电梯间场景,也可以按按钮,但我没拍照),按下之后幕布就会打开,但打开之后看到的是观众而非舞台角色。看着这些鼓掌的人的脑袋一个接一个地爆掉,还真是奇妙。

这组作品令我联想到阈限空间,尽管阈限空间里一般没有人,但此类作品也是以「感觉好像有点不对劲」的心理恐怖为主题的。

艺术家个人展

我又绕了好久才找到这个展厅,尽管美术馆有布局图,我还是花了几分钟才找到入口。由于难找,所以这个展厅里的人就少很多了。不过我想人少也有另一个原因,马上你就会知道了。

这个意大利艺术家叫作 Donatella Spaziani ,不太清楚她为什么会来中国办展,她的个人网站是意大利语写的,我看不懂。她的作品似乎有很多形式,甚至有自拍和声音作品,绘画的风格也别具一格,甚至难以理解。好笑的是,和我差不多同一时间进入展厅的有一对男女,男人先开口说到「这些是什么意思?」,他一边走一边重复了好几遍,而女人则接着他说「这也太艺术了吧?」。男人每说一句看不懂,女人就接一句。「太艺术了」并不是感叹,而是「过与艺术,我也看不懂」的意思,不过为了显现自己对艺术品的尊重,女人没有像男人一样发问。

这对情侣的对话引发了我的思考。首先,我也看不懂,我相信大部分不在艺术界的普通看展者也无法用准确地词句来解释 Donatella 要表达的东西,那么,艺术一定是要看懂的吗?

值得思考的问题是:对艺术来说,「看懂」是什么意思?理解数学问题有很明确的判断标准,但艺术呢?我想只能用阐述来衡量理解,如果一个人能用清晰、有条理的文字解释某件艺术品(不只是对作者和创作背景的交代,而是对艺术品内容及其象征意义的描述),那么就可以说他理解了这件艺术品,尽管这个理解和艺术家本人的理解可能有差异,但至少他以及其他人可以认为「他看懂了」。

那么,艺术品一定要看懂才行吗?一定要阐释吗?

对马克思来说诸如革命和战争这样的社会事件,对弗洛伊德来说个人生活中的事件(如神经官能症症状和失言)以及文本(如梦或者艺术作品)——所有这些,都被当作阐释的契机。根据马克思和弗洛伊德的看法,这些事件只不过看起来可以理解罢了。实际上,若不对他们进行阐释,他们就没有意义。去理解就是去阐释。去阐释就是对现象进行重新陈述,实际上是去为其找到一个对等物。

因而,阐释不是(如许多人所设想的那样)一种绝对的价值,不是内在于潜能这个没有时间概念的领域的一种心理表意行为。阐释本身必须在人类意识的一种历史观中来加以评估。在某些文化语境中,阐释是一种解放的行为。它是改写和重估死去的过去的一种手段,是从死去的过去逃脱的一种手段。在另一些文化语境中,它是反动的、荒谬的、怯懦的和僵化的。


当今时代,阐释行为大体上是反动的和僵化的。像汽车和重工业的废气污染城市空气一样,艺术阐释的散发物也在毒害我们的感受力。就一种业已陷入以丧失活力和感觉力为代价的智力过度膨胀的古老困境中的文化而言,阐释是智力对艺术的报复。

不惟如此。阐释还是智力对世界的报复。去阐释,就是去使世界贫瘠,使世界枯竭——为的是另建一个「意义」的影子世界。阐释是把世界转换成这个世界(「这个世界」!倒好象还有另一个世界)。

世界,我们的世界,已足够贫瘠了,足够枯竭了。要去除对世界的一切复制,知道我们能够更直接地再度体验我们所拥有的东西。


在现在大多数情形中,阐释无异于庸人们拒绝艺术作品的独立存在。真正的艺术能使我们感到紧张不安。通过把艺术作品消减为作品的内容,然后对内容加以阐释人们就驯服了艺术作品。阐释使艺术作品变得可被控制,变得顺从。


现在重要的是恢复我们的感觉。我们必须学会去更多的看,更多的听,更多的感觉。

我们的任务不是在艺术作品中去发现最大量的内容,也不是从已经清楚明了的作品中榨取更多的内容。我们的任务是削弱内容,从而是我们看到作品本身。

现今所有艺术批评的目标,是应该使艺术作品——以及,依此类推,我们自身的体验——对我们来说更真实,而不是更不真实。批评的功能应该是显示它如何是这样,甚至是它本来就是这样,而不是它意味着什么。


为取代艺术阐释学,我们需要一门艺术色情学。

——苏珊·桑塔格《 反对阐释

离开美术馆的时候,我就留下了这个问题,一周后我才开始阅读有关艺术阐释的文章,其中的观点令我醍醐灌顶。兴许是现代科学对人们思维方式的普遍影响,人们在面对新事物时习惯了用智力去理解,而不是去体验。当人们在欣赏艺术时,难以理解的存在使他们不安,不断地发问「这是什么意思?」,他们希望有人来阐释。我在游览 Donatella 的展厅时听到有导游带着一群小孩子和家长路过,她一直在阐释,给那些孩子和中年人讲述那些画用了什么手法、内容是什么、讲了些什么。我无意冒犯她,但那些话,真的好无趣,难以想象她在描述艺术。

桑塔格用「艺术色情学」总结全文,真的很妙。人们应当像感受色情片一样感受艺术,感受艺术本身的质感,专注艺术带给人的强烈感觉,而不是在脑中思考性高潮的生物学意义,更不是思考自己的脑子里现在有哪些化学物质正在发挥作用。

我想,欣赏艺术时,只需要关注眼前的图像让自己联想到了什么、感受到了什么,就足够了。生活中需要让智力费劲转动的场合已经够多了,就让艺术占满感性的领域吧。去创造艺术或观赏艺术,就是为了放弃思考,让自己不至于疯掉。

接下来就欣赏 Donatella 的作品吧。

首先是她的摄影作品,我选了一部分我喜欢的。这些都是她在生活空间中的自拍。由于光线的原因,某些照片里能看到我的轮廓,不小心入侵了画面呢。

我也很喜欢她的绘画,其中人似乎是主体,但只有黑影和轮廓,背景和修饰物反而是色彩最丰富,细节最多的,而且在一团黑影中还能想象出画中人物做的是什么样的动作,很耐人寻味。不过,这几张的背景实在是太白了,拍照的时候我整个人都被映出来了,于是我只能去她的网站上找到我拍摄的那些照片了。

这张是实拍

不过我最喜欢的还是接下来的作品,其实也是绘画,但这些画基本上都占满了整张墙,背景是墙纸的纹理,人物的轮廓是一样的黑影,但只占很小的一部分。整体的观感很神奇:引入眼帘的是一张纹理很美的墙,色彩不亮眼,看起来很舒适,但墙上有很明显的两个黑点,走近一看,竟然是两个人紧密地相拥在一起,其中一个人几乎要跌倒地撞进了另一个人的怀里。

这样的墙纸还有很多,我只选了我最喜欢的。除此之外还有声音作品,我就没有录音了,不过我只完整听了其中一个四分三十秒长的音频,名为《归来》。音频里是贯穿整场故事的脚步声,听者可以跟随脚步声去到很多地方,似乎有闹市,还有热闹的房间,以及关门后安静的卧室。Donatella 作品的魅力像是生长在想象力上的,要去感受,就必须要动用想象。

离去

其实还想写写第四场展览的,也就是美术馆里的其他人,不过我累了,而且我最近对人类的兴趣的确越来越弱。那么就让我为各位描述我上次在美术馆见到的三位来访者吧,同样地,需要动用想象。

美术馆一层,某个角落摆着一幅航天主题的绘画。一个女人带着一男一女的小孩子出现,小学一二年级的样子。

“你们要好好学习,开发这样的新技术,如果你们发现了新东西”,女人顿了顿,似乎在寻找词句描述自己的想法,“你们要第一个告诉我。”

男孩子似乎没有听进去,对着女孩子说:“你知道为什么在太空里会飘起来吗?因为太空没有摩擦力。”

女人又迟疑几秒钟,说道:“对。”

离开美术馆的时候我穿着黄色的衬衫和绿色的长裤,让我感觉像是路边的野花。我掏出耳机戴上,因为我突然很想听 Lady Gaga 的《Donatella》,尽管她和那位 Donatella 一点也不像。


  1. 不过我忘了这里是「浮游」还是「蜉蝣」了。 ↩︎

  2. 如果你觉得不够大众,那是因为不少展品我都没有拍照,更没有在文中提及。 ↩︎

Living Clojure

还不错的 Clojure 入门书籍,适合有较强编程基础(我认为至少要熟悉一两门编程语言,有实际开发经验)的人用来快速了解 Clojure 各方面的特性和编程模式。作者用《爱丽丝梦游仙境》的例子串起了 Clojure 的许多知识,通俗但对不了解这个故事的读者可能有些摸不着头脑,而且大部分例子都不是实际项目里会用到的做法,只能用来理解语法和函数的作用。

整体而言,可以把这本书当作不全面的对 Clojure 的快速浏览。由于我一边读一边写了个 Clojure 项目 ,读到某些章节时我发现我已经熟悉作者要讲的东西了。所以…… 不读书学 Clojure 也完全可行甚至更快?不过读一读有经验的 Clojure 程序员的文字总归是有些帮助的。

对翻译和编辑的…… 吐槽

我觉得我写技术书籍的第一节都会是翻译相关的内容了…… 之前读的《 整洁架构之道 》译得很糟糕,这本其实还能忍受。尽管语句不自然,但至少没有低素质的译者搞事,还是很尊重原作者的。只是有一些句子读起来确实很不自然,完全保留了英文逻辑,比如:

“如果我们有一个需要做一系列转变的 Java 对象,这是很有用的。”

虽有读起来磕磕绊绊,但习惯了就好。不过,这本书的文字编辑似乎常有疏忽,第 86 页有错别字:

有时候,当不需要这些结构化的数据时,你就可以使用 deftype,避免为某些你不想要的东西单。

95 页也有明显的错误,在介绍 Leinigen 定义依赖的方式时,书本先是给出了 [org.clojure/clojure "1.6.0"] 的示例,随后告诉读者上文中的 group-id artifactversion 分别代表什么,然而上面根本就没有这些文字!后面举例时,[org.clojure/clojure "1.6.0"] 又重复出现了一次,很明显第一次出现的代码应该是 [group-id/artifact "version"]

书里还时不时拼错一些单词,比如把 Google 写作 Goole,把 Clojure 写作 Clojur。我认为这是编辑校对的问题,不是翻译问题。

以后的技术书籍我都尽量找英文原本来读,不受翻译的气。只不过英文原版很难找到纸质书,或者说纸质书更贵,我又不太喜欢读电子书。

高信息密度的暴风式旅程

之所以选这本书,是因为在 Clojure 官网 上看到了,而且这本书是 O’Reilly 出品的,对发行商印象很好,所以就找了中文版来读。

书分两个部分,第一部分名叫《Clojure 之旅》,的确名副其实,作者暴风式地把 Clojure 各方面的特性毫不啰唆地讲了一遍,信息密度很大的同时也不觉得很难跟上(不过的确需要扎实的编程基础才行)。作者先从 Clojure 的数据结构开始,从简单值讲到容器(Collection)再讲到函数,此时读者就已经对 Clojure 的各种括号有基本的认识了,知道 '() 是列表、[] 是向量、{} 是映射、#{} 是集合,知道如何定义函数。这基本就是 Clojure 的…… 全部语法了,几乎所有 Lisp 方言都是这样,语法只有括号而已,非常容易学习

然后就是如何用 map filter reduce 等等函数操作上述数据,还介绍了惰性,此时读者已经能通过操作序列来做到很多操作了。不过,如果不熟悉函数式编程,可能还是有些不顺手。这本书的缺点也是缺少对函数式编程的讲解,至少我刚开始学 Clojure 的时候还在大量使用 for

我拖了好久才读到第三章,有关状态和并发的内容。这里我略读了,因为,呃…… 这显然不是函数式编程常用的,纯函数的方式很少管理状态,一直递归就好了。不过实际项目中难以做到纯函数式编程,所以了解状态和并发算是务实的选择。

我比较疑惑的是,作者在第三章讲了核心库里提供的 future 等并发方式,和 atom agent 等状态管理方式,可它把同样用来实现并发和状态管理的 clojure.core.async 库放到了后面的章节。然而,它们并没有什么分开的理由,只不过 clojure.core.async 不在标准库里,要额外引入依赖。所以作者在讲了 Leinigen 的项目管理之后才单独介绍这个库。我是觉得有些没必要。

而且在我看来 clojure.core.async 里提供的并发方法要比核心库里的并发和状态管理好用得多。这个库和 Go 语言一样,提供 go 代码块和 channel,Go 语言程序员可以直接复用 Go 的并发模型。我对 Clojure 的印象是它非常灵活,实现并发和状态管理的方式就有很多种,Clojure 程序员可以自由选择,不需要像 Go 程序员那样遵循同一套最佳实践(尽管我多半还是会用最好用的那套方法)。

Clojure 比较丑陋的部分是和 Java 相关的,由于这门语言跑在 JVM(Java 虚拟机)上,所以可以方便地调用 Java 的库,也因此需要处理面向对象编程。比如,在 Java 里写作 String.ToUpperCase(...) 的方法,在 Clojure 里要用专门的点语法,写作 (.ToUpperCase String ...),还有一系列有关创建对象和取对象属性值的语法糖。的确挺方便的,但总觉得不够优雅,因为要记忆的语法变多了。

值得赞许的是,作者一开始就教读者使用 REPL,并且在讲解新特性时鼓励读者自己把代码输入到 REPL 里实验。Lisp 程序员当然是要熟悉 REPL 的,一边了解概念一边实验无疑也能帮助理解。整本书的确有点跳进兔子洞梦游仙境的感觉,而且还配有导游。

抛砖引玉的写法

作者在第一部分的后面某一章非常快速地讲解了如何用 Clojure 开发 Web 应用,把后端和前端相关的技术栈都压缩到了一章里,如何启动 Ring 服务器,如何用 Compojure,如何用 ClojureScript 和 Enfocus 库操作 DOM,如何用 Hiccup 生成 HTML,同样是信息密度非常大,但完全没有深入讲解。

不过这对本身就了解 Web 开发的人不成问题,假设你已经熟悉什么是 DOM,要怎么监听事件实现网页交互,这种凝练的写法就相当于在告诉读者:你知道在 JavaScript 里怎么操作 DOM 对吧?在 ClojureScript 里,你只需要用这个库这么写就能达到相同的效果。你知道设计后端 API 一般要返回 JSON 是吧?你可以引入 ring-json 中间层帮你自动把 Clojure 数据结构转换为 JSON 字符串响应。我很喜欢这种不讲废话的写法。

当然,坏处就是不熟悉 Web 开发的人会一脸懵,其他某些章节也是这样。

在第二部分,作者也继续抛砖引玉,还试图把读者带入 Clojure 程序员社区里,列出了各种有用的工具网站、IRC 群组、新闻网站和值得订阅的 Newsletter。有点可惜的是,有一些网站如今已经无法访问了。

这也是我认为这本书很适合有经验的程序员入门 Clojure 的原因,作者不把你当什么都不懂的菜鸟来教,而且点到为止,余下的内容就留下引子让读者自行探索。

练习计划和…… Emacs

本书还提供了练习计划,规定了每周专注什么,每天具体要做些什么事情来练习 Clojure 编程。看起来很贴心,兴许对一些人有用,但我不打算用这个计划。

一方面是我在读到这一章之前就已经用 Clojure 开发过完整项目了,另一方面是这套计划的前四周几乎都是在…… 刷题,直到最后一周才开始做真正的项目,对我来说非常无趣,我更喜欢直接上手,遇到不知道如何实现的需求时再查阅文档找解决方案。

作者 Carin Meier 是个 Emacs 用户,有公开她的 Emacs 配置 。在去网上搜索她之前我就有预感她应该是用 Emacs 写东西的,因为本书第五章第一节的标题就是「配置一个 Clojure 编辑器」,其中虽然提到了 Vim 和别的编辑器,但对 Emacs 的叙述最多,甚至出现了「Emacs 不仅仅是一个编辑器,还是一种生活方式」这句话。此外,她毕竟是个 Clojure 程序员,写 Lisp 的大多都用 Emacs,配置这个编辑器的 DSL 就是一门 Lisp 方言(虽然我也可以用 Fennel 来配置 Neovim)。

最近感觉 Emacs 在我生活中出现的频率有点太高了,总觉得是某种征兆。不过我三次尝试入坑 Emacs 都失败了,前两次都是使用 Doom Emacs,但各种已经配置好的、我不理解的功能让我感到害怕(Neovim 都是我自己从零配置的,我很难上手别人的配置),而且…… 你的启动速度再慢点就能赶上 VS Code 了。自己从头配置的话,我还没找到容易入门的资料,连装 Evil 都不会(拜托,没有 Vim 键位我怎么活得下去啊!)。

我跑题了,我想说的是这本书的确让我再次考虑要不要用 Emacs,目前考虑的结果是:我还没准备好。

核心训练和腹肌训练是一个东西吗?

读者们好,今天是世界读书日,所以我打算来讨论如何锻炼身体。是的,我就喜欢做不合时宜的事情。本来想说在世界体育运动日谈读书,但发现这个节日在四月六日,已经错过了,那就留到明年再说吧。

不久前我还会和同室讨论健身话题(后来发现我们两个的观点差异巨大,而对方在某种程度上根本无法双向交流),有一次他问我练核心是不是就是练腹肌。我表示否定,因为核心和腹肌就不是同一个东西,此外核心注重的是稳定性、抗阻力的能力等等,而腹肌是可以瘦出来的,体脂率足够低的人几乎都有明显的腹肌(当然不一定好看就是了),但他们可能一碰就倒,核心不稳。

他似乎没听进去,当时的我还有些生气,现在想来:我为什么要跟这个觉得酸性和腐蚀性是一个东西的人较真?人类真的很无聊,但知识很有意思。时隔数月,我决定找一些靠谱的资料来读,认真研究这个问题。

什么是核心?

在英文里,核心是 core(也叫作 trunk),一般被认为是躯体(torso)的同义词,最简单的定义是:除去四肢之外的身体部位。依照这个定义,在解剖学上,头和脖颈也属于核心。1如此看来,核心覆盖的范围要比腹肌大得多。不过,这个定义在健身语境下可能就不适用了,我稍后会详细讲到。

解剖学上有差异,那么功能上呢?谈到核心训练,人们一般会混用「核心力量」和「核心稳定性」两个词,它们是同一个东西吗?相应地,有没有「腹肌力量」这个说法呢?腹肌力量和核心力量有关系吗?

在维基百科上,Core strength(核心力量)被重定向至 Core stability(核心稳定性)这个条目,但不少网络文章则专门分开讨论这两个概念。于是我找到了一些学术文献,希望能做区分。

奥尔登堡大学和罗斯托克大学的一篇研究报告2是这样讨论核心力量和核心稳定性这两个概念的:

Given that the constructs of core strength and core stability have been widely accepted, it is surprising that no clear distinction is made between these constructs. ( source )

核心力量和核心稳定性的概念已经被广泛接受,令人惊讶的是,这两者竟然没有被清晰地做出区分。

所以在引言部分,这篇文献就引用了另一篇在 2024 年发布的文献,对这两个概念做了清晰的定义,还重新定义了核心的范围。鉴于维基百科上相关词条引用的文献已经有些年头,而且有不少表述还被标注为 citation needed(需要引用),本文就使用这篇学术报告中对核心的定义:

In general, the core is anatomically described as a box with the abdominals in the front, the paraspinal and gluteal muscles in the back, the diaphragm as the roof, and the pelvic floor and hip girdle musculature at the bottom. ( source )

一般而言,核心在解剖学意义上被描述为腹部肌肉在前、脊柱旁肌肉(paraspinal)和臀部肌肉在后、隔膜为顶、盆底和臀骨肌肉系统(hip girdle musculature)为底的盒子。

在我的理解里,这应该是肺部往下、大腿往上的身体部位。即便是这个定义,核心和腹肌仍然相差甚远,因为核心还包括脊部和臀部等肌肉。读者可以参考下面两张图来定位核心的位置。

呼吸系统图示,注意膈肌的位置。

标红的是臀骨,周围的肌肉就是核心的底部。

核心力量就和上述肌肉的力量有关。

Functionally, the core musculature can be classified into local, global, and (axial-appendicular) transfer muscle systems that generate forces and work synergistically to achieve proximal stability for distal mobility in athletic movements. Thus, core strength can be defined as the ability of a core muscle or a core muscle group to generate muscular force. ( src )

功能上,核心肌肉系统可以被归类为局部、整体和(轴肢肌)转移肌肉系统3,它们产生力并协同达成近端稳定性,为的是体育活动中的远端活动能力。因此,核心力量可以被定义为一个核心肌肉或一个核心肌群产生肌肉力量的能力。

至于核心稳定性:

Neuromuscular control of the core muscles is critical for the precise and coordinated execution of muscle activation, which occurs at the right time, for the correct duration, and with the right combination of forces necessary to control the movement or position of the body. Thus, the body can respond to internal and external as well as expected or unexpected perturbations to ensure static and dynamic core stability Consequently, core stability can be defined as a dynamic process that requires optimized core strength (maximal core strength, core endurance, and core power) and neuromuscular control (accurate joint and muscle receptors and neural pathways) that allows efficient integration of external and internal sensory information. ( source )

这里就不整段翻译,我累了。大概是说,核心稳定性是一个动态过程,需要充分利用核心力量和神经肌肉控制(聚合内部和外部的感官信息,来控制准确控制关节、肌肉受体和神经通道)来控制肌肉活动

我有个例子可以更通俗地说明这一点。我想对于任何肌肉来说,都有力量和协调能力的区分,前者可以短期锻炼实现增长,但后者必须长期积累,类似于熟练度、直觉和身体的经验。我的爷爷常在仓库搬运货物,每天都在高频率、长时间地使用手臂肌肉,不过他的肌肉看起来并不大,和我差不多;我的表哥经常健身,用器械规律地、高强度、爆发性地刺激肌肉,整个人看起来要健壮很多。这两个人扳手腕,谁会赢呢?

显然我的爷爷赢了,哪怕他的肌肉看起来没有那么健硕,但他能更熟练地调用手臂肌肉,对身体有更精确的神经控制。许多追求健美的人并不是缺少力量,而是拥有力量却不懂得如何使用力量。

类比到核心力量和核心稳定性,核心稳定的前提是核心有力量,核心肌肉能够发力,同时身体应该能够熟练调动核心肌肉,把力精准地用到正确的地方。

ScienceDirect 这个网站上有 Core stability 专题,但并没有 Core strength 条目。我想这和维基百科把 Core strength 重定向到 Core stability 的原因类似,单独讨论核心力量意义不大,因为有力量却不懂得如何使用就派不上用场。如果关注核心稳定性,就会知道一个人不仅应该锻炼核心力量,还应该熟练调用核心力量,在锻炼时收紧核心,让核心帮助自己完成身体活动。

不过说了这么多,核心究竟是干嘛的呢?

核心稳定性有什么用?

既然我们已经知道核心稳定性是更值得关注的概念,那么就深入探索一些更实用的知识吧。核心稳定性有什么用?不锻炼核心会有什么问题?核心训练是不是最有用的锻炼种类?

核心稳定性的简单定义是:稳定核心的能力。4所谓稳定,就是在受到外力影响时保证身体不弯曲、不改变躯体的姿态。人的身体一直受到重力影响,一个强健的核心能帮助个体抵抗重力。最常见的核心训练动作是平板支撑,仔细想想(或者现在请读者站起身来,趴在地上做一分钟的平板支撑),做这个动作时人的大部分身体是悬空的,尽管手臂能提供相对稳定的支撑,但腿和地面形成了较小的夹角,对下半身(也正好是核心的位置)的支撑是不够的。为了不让核心受重力影响而塌陷,核心必须发力把自己撑起来。

如果做平板支撑感到腰疼,那大概率是因为核心没有发力,导致腰部肌肉进行了代偿。所谓代偿,就是在锻炼时,应该发力的肌肉因力量不够或姿势不对等原因不足以支撑身体,为了维持姿势,身体其他部分的肌肉帮忙支撑。如果锻炼之后经常感到腰酸背痛(比如最常见的斜方肌疼痛),很有可能就是肌肉代偿导致的。

所以核心稳定性的第一个好处就是可以避免肌肉代偿,避免锻炼后不该痛的地方感到疼痛难忍,尤其是能够保护腰部,这个身体最勤劳的器官。肌肉代偿的一部分原因是姿势错误,而核心稳定性弱或者不习惯使用核心发力,就是无法进入正确姿势的原因之一。

读到这里应该不难发现,核心锻炼是用来提升核心稳定性的,是完全功能性的锻炼,为健康和运动表现而服务。腹肌锻炼则只针对腹部肌肉,对核心稳定性当然有帮助,毕竟腹部肌肉也是核心的肌肉,对核心力量很重要,不过我想大部分人练腹肌都不是为了锻炼核心力量,而是为了健美和…… 别的东西。

另一个核心稳定的好处,据说是能够降低运动时受伤的风险,不过根据维基百科的 相关条目 ,核心锻炼对于体育运动中的受伤风险并没有预防效果,至少没有被证明,对运动表现的提升也没有证据。这个维基百科页面的编写者认为没有证据表明核心训练比其他训练方法有显著优势,最多只能说它和其他锻炼一样有益。

不过,根据 Healthline(一个没那么学术的健康相关网站)上的一篇 文章 ,有研究能证明核心强壮的这些好处:

  1. 稳定腰背(lower back)
  2. 提升柔韧性
  3. 帮助身体平衡
  4. 支撑更好的体态
  5. 让日常活动变得更轻松
  6. 帮助减轻或预防疼痛
  7. 让跑步更轻松
  8. 帮助减轻腰背(lower back)受伤

不过无论是维基百科上对核心训练的质疑,还是这篇文章的称赞,都仅仅是基于几篇学术报告得出的结论。要非常严谨的话,最好是把现有的全部文献都读一遍,写一篇综述(我当然是没有这个能力的)。我想有关身体的知识,对普通人而言最大的不同就是,它并不是你缺乏专业知识就没办法去证实或证伪的,如果不去践行和尝试这些知识也没有意义。

无论如何,至少没有证据表明核心训练有害(不过高强度的腹肌训练,比如卷腹,倒是会增加腹腔压力,过度的话会引发某些问题),核心训练究竟有没有那么关键,读者完全可以坚持一段时间后感知身体的变化,自己得出结论。

我自己的观点是,应该尽可能尝试更多种类的运动,因为普通人毕竟不是专精的运动员,充分发展身体的各项机能才是最重要的,核心稳定性只是身体机能的一部分。

练核心和练腹肌的区别是什么?

前面提到核心是一个盒子,由很多肌群组成,腹肌仅仅是其中的一个,而且只是最前面的一个。一般人们说的六块腹肌是 Abdominals,也就是 Abs;此外还有腹斜肌(Obliques)、背部、盆底、脊椎、臀(Glutes)和隔膜(Diaphragm)。练核心时,这些肌群都要照顾到。

练腹肌的常见锻炼是卷腹,以及卷腹的各种变体。我个人最熟悉的是单车卷腹(Bicycle crunch),大致的动作是躺在地上,让核心保持在地面上,双手抱头,双脚抬起,左脚往后收时转动手臂,让右手的肘关节碰到左脚膝盖,然后交换,如此循环。由于转动手臂时头也要跟着动,胸腔差不多也是离开地面的,此时身体只有核心保持在地面上,核心要在身体其他部位都移动的情况下保持稳定不动。

讲到这里可能就不难理解为什么人们把核心训练和腹肌训练混为一谈了,因为两者的确有很多重合的地方。我想这是因为身体本来就是整体,很难在移动和锻炼某一个部分的时候不带动其他部分,更何况腹肌就是核心的组成部分之一。

不过,如果只做卷腹而不做其他核心训练,或者说只关注锻炼腹肌而不关注核心稳定性,身体其实会出现问题。

Not only can a one-sided preference for abdominal muscles (lack of exercise focused on other core muscles) result in creating muscle imbalances, but the effectiveness of exercise is also far from what could be achieved with a balanced workout planning. ( source )

对腹部肌肉的单一偏好(缺乏专注于其他核心肌肉的锻炼)不仅会造成肌肉不平衡,锻炼的效果也和平衡的锻炼计划相差甚远。

其实还有一个微妙的差异不得不谈:健身者可以按照目的简单地划分为两类。一类人关注身体机能和健康,就算是为了炫耀,也是为了炫耀自己身体的能力;另一类人关注身材比例和肌肉线条,他们锻炼是为了获得令人愉悦的好身材,无论是为了愉悦自己还是愉悦他人,亦或是在发展浪漫关系时获得优势。

在我的观察里,前者更注重核心稳定性,后者更在意腹肌是否明显。我自认为属于前者,因为我就算没有令人瞠目结舌的健硕肌肉和身体线条,也已经长得很帅了(叉腰),而且我更贪生怕死,不想让无止尽的对硕大肌肉的追求让自己陷入焦虑和过度锻炼的循环中,这真的很不健康。当然,我不是说后者就一定焦虑或者有心理问题,我也没有在比孰优孰劣,毕竟,我们都支付了相应的代价。追求形体美的健身者,自然也可以在集中锻炼腹肌的同时关注其他的核心肌肉以避免失衡,前提是他们有这个意识。

我真正想批评的,是那些消耗自己的身体健康来换取形体美的做法,这类人觉得核心训练和腹肌训练是同一个东西的根本原因在于,他们根本不觉得核心稳定性在他们的考量范围内,他们只关注自己的腹肌够不够明显。所以和腹肌训练有一定重合度的核心训练,在他们眼里看来不过是腹肌训练的别名,是时尚的健身概念。

实际上,健康和形体美可以共存,只要尽力保持均衡,做「杂食者」。不过,在我看来,健身和规律锻炼对人外貌最大的提升其实是气质层面的,规律的锻炼会让人变得更自信,因为人会感到对身体有更多的掌控感,更不用说锻炼本身也是很好的排解负面情绪的方法。那些整天在镜子面前拗造型,对自己本来就健康甚至必要的体脂率感到焦虑的人,反而是起到了反效果。

核心训练应该是健身入门课吗?

之前在《独树不成林》的某期运动博客听到树老师分享过这样的观点,她建议那些觉得一运动就浑身痛、不舒服,甚至受伤的人,先去练核心,提升核心力量。某种程度上,这个观点不坏,因为强健的核心能帮助稳定身体,降低受伤风险;由于减少了肌肉代偿,腰酸背痛的情况也能缓解。

不过,我不觉得一个毫无运动习惯的人应该以核心训练起步。

首先,核心训练总归是抗阻力训练,或者说是无氧,是力量训练。它不会像有氧运动和跑步那样让人大汗淋漓,至少对我而言没那么畅快。由于对力量有一定要求,刚开始练核心的时候其实很痛苦,我记得我刚开始做卷腹的时候痛得嗷嗷叫(不夸张),我想我可能是不习惯核心肌肉发力的感觉,以及当时我的核心力量的确不强,有点勉强。对本身就不习惯规律锻炼的人,核心训练很少会让人觉得:好畅快,我还要再来一次!相反,由于肌肉发力困难,练不到位,很有可能锻炼后心率都没有什么变化,痛苦之后还觉得像是完全没有锻炼一样。

核心锻炼的进步也没有那么明显,必须长期坚持才能获得一些反馈。没有锻炼习惯的人可能不懂得观察身体的变化,也就更难获得正反馈。有锻炼习惯的人会更了解自己的身体,知道自己之前还做不了的锻炼姿势经过几个月的锻炼之后就解锁了(比如从标准俯卧撑过渡到钻石俯卧撑),知道锻炼是一个渐进的过程。但这需要时间和长期积累的对身体的认知。

门槛比较低,能在短期获得及时反馈,且长期而言也能看到明显进步的运动会更合适,比如强度合适,让身体出汗并产生内啡肽,以跳跃和肢体运动为主的有氧运动。有氧运动虽然锻炼不同的身体机能(有氧运动提升心肺能力,核心训练提升核心稳定性),但都能提升锻炼者对身体的认知,并且比抗阻力训练更容易坚持。低冲击的有氧运动不容易受伤,也很容易根据健身进度逐渐调整负荷和强度,在我看来是更好的入门运动。

什么样的人应该练核心?

我想只要没有影响运动的身体疾病,人人都应该练核心。

在《独树不成林》第 265 期博客《 古罗马名医如何讨论健康? 》中,树老师讨论了古罗马希腊医生盖伦如何定义健康与疾病。其中令我印象最深刻的观点是,这位医生认为「臃肿」是不健康的。这个臃肿包括了被脂肪填充的肥胖,也包括了被肌肉填充的过度锻炼。大部分专业运动员的运动方式都是不健康的,只不过他们有专业的医疗团队指导陪护,并且会有意识地休息和主动恢复。

在某个方面过度锻炼、不均衡地发展身体机能,在盖伦的眼里是不健康的。对于不以运动为职业的普通人而言,做健身的杂食者是更好的选择。

对我而言,心肺能力、肌肉力量、核心稳定性和柔韧性就是至关重要的身体技能,理想情况下不应该偏科。

心肺能力一般用最大摄氧量(VO2 MAX)量化,通过跑步和有氧运动锻炼,在锻炼时要控制呼吸,维持心率稳定。

肌肉力量一般用肌肉率量化,也就是身体中肌肉的占比。不过前文也讨论过,其实还要考虑神经适应性和使用力量的熟练度;一般来说,锻炼肌肉要给对应肌群施加足够多的阻力,让肌纤维撕裂,撕裂过后的恢复过程中,肌肉就会长得比之前更大,这就是肌肥大的基本原理。

核心稳定性在前文已经讲过了,应该在锻炼时收紧核心,让核心发力抵抗外力,比如做平板支撑时抵抗重力,做死虫式、单车卷腹时抵抗身体的弯曲,让核心保持静止。不过核心稳定性似乎比较难量化,也不如肌肉那样明显,这可能是一些人不重视核心力量,痴迷于锻炼肌肉的原因吧。连着做半个小时的平板支撑固然令人敬佩,但视觉冲击力的确不如大肌肉。

柔韧性就更难量化了,而且没人会突然当着所有人的面劈竖叉(不过我会,嘻嘻),不容易得到外部反馈,更何况柔韧性很容易反弹,不够稳定。这也是大部分健身房撸铁人最容易忽视的点。我有一次找拉伸的视频跟练,发现有一个肌肉男教练竟然没办法直着身子把手放在脚后跟的位置,他必须弯曲膝盖才行,看起来胸腔都要贴到膝盖了。如果我弯曲膝盖,就完全感受不到韧带拉伸。实际上,柔韧性是身体最好的盔甲,能降低受伤风险,我想我会单独写一篇文章谈柔韧性。

所以,人人都应该练核心,并且还应该维持心肺能力、肌肉力量和柔韧性等其他身体技能。当然,这只是我的观点。

最后

如你所见,这是新系列《 健康黑客 》的第一篇文章(不过我还把之前的一些文章也归入这个系列了),最后一节交代了许多和核心训练关联不大的内容也是为了抛出引子。除了锻炼,我还想讲讲肠道健康和口腔健康,这些都是我最近有在实践并取得成果,或者有在关注和研究的话题。

之前在《 The Hacker’s Diet 》里读到过令我印象深刻的观点,大概是说人体也像计算机系统一样可控,通过输入得到输出。我想只要有相关知识和一套系统,就能够用调试软件的手段调控身体。本文的黑客味可能还不够浓,兴许这个系列之后的文章会更多地把人体当成一整个系统来讨论,就当这篇文章讨论了身体的一个功能模块吧。

我现在要去做平板支撑了,回见!


  1. Core (anatomy) - Wikipedia  ↩︎

  2. Relation between core strength, core stability, and athletic performance—a mediation analysis approach  ↩︎

  3. 我不懂这些生物学名词具体指代什么,所以可能出现翻译错误,请各位以原文为准。 ↩︎

  4. 来源: Core stability - Wikipedia  ↩︎

整洁架构之道

由于很不喜欢软件架构课老师的授课风格,所以决定完全自学。选这本书当教材可能不太合适,但的确收获颇多。眼看 Coding Agents 的趋势只增不减,就算在个人项目和自由软件项目中拒绝使用,工作时也无处可躲,我想每个程序员都需要做架构师了。如果缺乏整洁清晰的架构设计,那 Coding Agents 就只是在高速产出屎山代码而已,后续的维护只会是一场接一场燃烧 Token(或者说燃烧美元)的灾难。总之有必要关注架构问题。


对翻译的批评

丑话先说在前头。书很好,但翻译是真的烂,只给这本书三分也完全是因为翻译问题。尽管我理解翻译技术类书籍的人都是从业者而非专业译者,对翻译质量有一定容忍度,但本书的四位译者实在是缺乏最基本的素养和素质,我读着非常恼火。

在第 27 章《服务:宏观与微观》中,图 27.1 的文字标注全是英文,比如 Taxi Selector,这没问题,因为编写程序时就会用这些单词命名。有问题的是,在几个段落过后的图 27.2 中,只有 Taxi UI 是英文,其他的全都变成了「出租车匹配」之类的词。就算抛开出现在同一章节的两张图前后不一致不谈,同一张图里也是中英文混杂,明明是相同的元素,有的翻译了,有的却没翻译。更不谈图表之外的文字段落中使用的还是 Taxi Selector 等英文单词,读者要怎么把图表中的元素和文字段落中描述的对象联系起来?文字段落里有的是英文原文 Taxi Selector,有的又用的是译名,比如「出租车分配」(原文是 Dispatcher,居然不是「分派器」吗?)。真不知道要干嘛。

在图 27.3 中,原本还被翻译成「小猫」的 Kitty 原样出现在图中,这次更好笑,图里写的是「kitty 查找」「kitty 来源」「kitty 匹配」。难道这个 Kitty 和前文的「小猫」是不同概念吗?做到术语统一对专业软件工程师来说不难吧?做到语言统一对译者来说也不难吧?在图 27.4 中,又出现了「小猫匹配」这个词。

最让我感到气愤的还不是翻译问题。前面的只能说是「缺乏译者素养」,接下来要提的问题就纯粹是「没素质」了。

同样是第 27 章,这一章的最后一节是「本章小结」,原文只有两段话,如下:

As useful as services are to the scalability and develop-ability of a system, they are not, in and of themselves, architecturally significant elements. The architecture of a system is defined by the boundaries drawn within that system, and by the dependencies that cross those boundaries. That architecture is not defined by the physical mechanisms by which elements communicate and execute.

A service might be a single component, completely surrounded by an architectural boundary. Alternatively, a service might be composed of several components separated by architectural boundaries. In rare2 cases, clients and services may be so coupled as to have no architectural significance whatever.

然而在译本中,这一节有五段话。在原本应该结束的地方,译者毫无预警、肆无忌惮地把自己想写的东西紧跟着写在了译文的后面,看起来就像那些文字本来就在那个地方一样:

Bob 大叔的案例非常精彩,确实,……(此处省略三四段极其平庸的论述)

在本就不应该出现在这里的三段话的最后,译者恬不知耻地写上了「——译者注」。我想这位译者不仅英文翻译水平值得怀疑,中文理解能力也需要打一个问号。因为我非常确定,「译者注」一词中的「注」表示「注释」,而不是「正文」。在我的理解里,译者注存在的意义是辅助读者理解文本,如果译文没有跨文化理解问题,或者不需要交代什么背景信息,那译者注就不该写;译者注绝对不是译者对同一话题的理解或对文本的解读,更不是对原文的入侵

倘若译者真的觉得自己有什么值得一读的见解,完全可以写在译者序或者后记里(这样方便我直接跳过),或者自己写一本书,而不是在别人的书里「借楼打扰」。

我读的译本是机械工业出版社出版的,我找到了由电子工业出版社出版,由孙宇聪翻译的译本,后者的第 27 章小结只有原文出现过的两段,没有多余的内容。孙译本也没有翻译插图,文字段落中使用的名称也是英文原文,术语是统一的。此外,机械工业出版社的译本中其他的很多大大小小的问题,在孙译本里都没有出现,比如第 34 章《The Missing Chapter》被我手上的译本译作「细节决定成败」,我真的哭笑不得,孙译本的翻译是「拾遗」,不一定是最好的,但至少和原文不至于毫无关联。

总之,如果你想读这本书,我推荐直接读《Clean Architecture》英文原本;如果要读译本,请选择电子工业出版社的孙宇聪的译本,绝对不要读机械工业出版社这四个译者译出来的垃圾译本。

需要注意的是,我不幸读到的译本叫作《整洁架构之道》,而孙译本叫作《架构整洁之道》。前者发行年份更晚,是 2024 年发行的,更推荐的那本是 2018 年发行的,不知道是不是为了故意混淆才这样命名。我记得 Bob 大叔的另一本《Clean Code》的译名是《代码整洁之道》。


架构是永恒的

当你仔细观察编程实践时,你会意识到在过去 50 年里几乎没有什么变化。编程语言变得更好了,工具也变得更加出色了,但计算机程序的基本构建块并没有变化。

编程语言在更新迭代,编程范式和开发模式也在推陈出新,但组织软件系统的方式、定义组件边界的方式、软件设计的基本原则、管理依赖关系的方式,几乎都没有改变。架构是永恒的,此外,良好的架构也能让延长软件的生命周期。

Bob 大叔认为软件有两种价值维度:行为价值和架构价值。前者是大多数人更关心的「软件能做什么」,非开发人员希望软件能更快地推出新功能,也就是允许更多的行为。然而,架构价值可能比行为价值更重要,因为架构决定了开发效率、维护难度和变更成本。如果急着满足需求,实现行为价值,而使用了不合理的架构,那么后续增加新功能时要修改的代码就会越来越多,还有可能出现修改了某一段代码导致另一段代码不可用,需要继续修改的情况。我想这有点像一些人说的「慢就是快」,一开始求快只会在整体上拖慢速度,甚至最终不得不重头来过。

书本还用艾森豪威尔矩阵解释了两种价值维度的关系,这个矩阵就是生产力爱好者常说的「重要且紧急」「重要不紧急」「不重要但紧急」和「不重要不紧急」的划分。架构属于「重要不紧急」的范畴,而软件行为是普通人更关注的「不重要但紧急」的事项。至于另外两个象限是什么:紧急的事情永远不重要,重要的事情永远不紧急。

架构往往和变更成本联系在一起,如果一开始使用了不好的架构,那么变更就会变得很难,添加新代码会很难,重构的成本也很高。如果一开始使用了良好的架构,那么整体而言软件开发的速度会更快,变更的成本也更低。好的架构往往是灵活的架构,而坏的架构很难改变,在这个意义上,架构也是永恒的。

编程范式、设计原则和组件原则

本书的第 3、4、5、6 章讲的是编程范式,主要有三种:结构化编程、面向对象编程和函数式编程。前两种大多数程序员应该都很熟悉,而函数式编程通常是 Lisp 实现的编程范式。三种范式并没有给编程增加什么新东西(可能有一些新概念,但实际上没有范式也能做到这些概念做的事情),相反,他们限制了某些东西。

  1. 结构化编程限制了对程序控制权的直接转移,也就是 goto 语句的使用,认为程序由顺序、分叉和循环几种基本结构组成,这样就能把程序分成可证伪、可测试的基本单元;在以前,goto 语句有害还不是共识,那个时候人们对 goto 的反对者 Dijkstra 冷嘲热讽。
  2. 面向对象编程限制了对程序控制权的间接转移,主要是限制函数指针的使用,因为指针很危险;所谓的封装、继承和多态,在 Bob 大叔眼里都不是 OOP 的新东西,这些都可以通过操作函数指针实现;OOP 的另一个好处是可以很方便地实现依赖反转,让其他组件成为业务规则的插件,而不让核心的业务规则知道其他技术细节的存在。
  3. 函数式编程限制了赋值操作,变量通常是不可变的(不过我印象里像 Fennel 这样的 Lisp 方言并不是纯血函数式编程,可以正常声明和操作变量,只是有括号的 Lua 语言而已);函数式编程的一个思想是,如果有足够的空间和储存能力,就可以用不可变、纯函数的方式实现程序,只存储事件记录而不储存状态,Git 就是这样的。

第 7 到 11 章讲的是 SOLID 设计原则,即:

  1. Single Responsiblity Principle(单一职责原则)
  2. Open Close Principle(开闭原则)
  3. Liskov Substitution Principle(里氏替换原则)
  4. Interface Segregation Principle(接口隔离原则)
  5. Dependency Inversion Principle(依赖反转原则)

所谓单一职责,并不是说一个模块只做一件事情,因为「一件事情」其实很难定义。准确的定义是:一个模块只对一个行为主体负责,或者说,一个模块只因为一个主体发生变更。具体来讲,要分离不同主体相关的代码,不同的主体不应该依赖同一个模块,这样一个主体的需求变更而引发的代码更改就不会影响到另一个主体。

所谓的开闭原则,是指软件应当对拓展开放,对修改关闭。所有组件的依赖关系都应该是单向的,最终指向不会经常更改的组件。这个没有任何依赖的组件往往是核心业务逻辑,与任何技术细节都无关,而数据库和用户界面等技术细节应该在外围,去依赖业务逻辑。如此一来,用户界面就作为「插件」存在,是对业务逻辑的拓展,可以随时拓展更多的其他用户界面,比如分出桌面端应用和 Web UI,这都不会导致核心业务逻辑的修改。

所谓的里氏替换原则,主要应用在 OOP 编程,用来指导「继承」的使用。比如,Square(正方形)不能作为 Rectangle(矩形)的子类,因为不符合 LSP。这两个类若是相互替换,软件的行为就会发生改变,参考一下代码:

Rectangle r = ...
r.setW(5);
r.setH(2);
assert(r.area() == 10);

如果 r 是 Square 类型,因为是 Rectangle 的子类,所以能通过类型检测,但最终 assert 会失败。

所谓的接口隔离原则,是为了避免依赖不需要的东西。假设 User1 User2 User3 分别依赖 OPS 对象里的 op1() op2() op3() 方法,更好的做法是创建 U1Ops U2Ops U3Ops 这三个接口,由 OPS 实现这三个接口。三个 User 去依赖各自的接口,避免直接依赖 OPS,因为它提供了许多自身不需要的东西。如果不这么做,OPS 的更改就会导致三个 User 都需要重新部署,若不直接依赖 OPS,就不会有这个问题。

最后是依赖反转原则,这是说源代码应该多依赖抽象类型而不是具体实现,这有点像前面的开闭原则和接口隔离原则,代码的依赖关系应该最终指向最抽象、最不容易发生变更的核心业务逻辑,同时避免依赖自身不需要的东西。这能避免不必要的代码变动,以及因为所依赖的组件发生变更而不得不重新编译和部署多个组件的繁琐工作。

常见于 Java 等 OOP 语言里的工厂设计模式也是为了依赖反转而服务的,也有了先写 XXXService.java 接口,再写 XXXServiceImpl.java 实现类的做法,这样可以使源代码依赖于抽象工厂和抽象的服务接口,而不直接依赖易变的具体实现;而 ServiceImplServiceFactoryImpl 等类由于是对接口的实现,依赖关系也是从具体实现指向抽象接口的,保证依赖关系从具体指向抽象。

以前我总觉得这种编程模式很繁琐,如今也算是理解了一些背后的原因。这么说来,我的 Java 老师还真是一点没讲清楚。我想这样的 Java 开发者应该不占少数,这才是 Java 这门语言令我厌烦的根本原因吧。无脑复用某种软件组织方式,不明白这么做的目的,违反了某些原则也不自知,最终的软件架构照样很乱。


第 12、13 和 14 章讲的是组件原则,包括组件的历史、重定位和链接器等技术,以及组件内聚和组件耦合相关的原则,不只是「高内聚低耦合」那么简单。

组件内聚主要要保证复用/发布等价原则(REP)、共同闭合原则(CCP)和共同复用原则(CRP)。REP 如今已经成为事实标准了,它说的是「没有通过发布流程获得版本号的组件是无法复用的」,主流编程语言几乎都有发布组件的标准流程,锁定版本号以保证组件行为可预测也很重要。CCP 是单一职责原则的组件版本,即「将相同变更原因而需同时更改的东西放在一起,将不同变更原因或无需同时更改的东西分开」。CRP 简单来说就是「不要依赖不需要的东西」,如果依赖某个组件,最好是依赖该组件的每一个类,否则无关的代码变更可能影响自身。

组件内聚的三个原则构成了一个「不可能三角」,需要架构师权衡取舍,一般来说只能同时实现两个。如果牺牲 REP,就要面临组件难以复用的后果;如果牺牲 CCP,就可能会出现太多不必要的版本发布;如果牺牲 CRP,就会出现太多的组件变更。

组件耦合的三个原则是无依赖环原则(ADP)、稳定依赖原则(SDP)和稳定抽象原则(SAP)。ADP 就是不应该出现循环依赖,这个很好理解。SDP 提出了一个稳定性指标,依赖的组件越少、被越多组件依赖的组件越稳定,否则越不稳定,而组建的稳定性指标应该沿着依赖关系递减,即依赖关系最终指向最稳定的组件(往往是核心业务逻辑)。SAP 是说,稳定的组件应该是抽象的,有多稳定就有多抽象。

稳定但具体的组件维护起来是痛苦的,这部分应该是数据库 Scheme 和 string 之类的少数易变组件;非常抽象但不稳定的一般是那些没有被实现的抽象类,是无用的;而中间的那部分、稳定且高度抽象,或者不稳定但十分具体的组件,应该占据大多数。


以上各种原则和概念名称都是深入理解软件架构的基础,我个人感觉 Bob 大叔非常强调依赖反转原则,它的确也串联起了很多其他的设计原则和组件原则。如果上面的内容太多太杂,只要记住核心业务逻辑应当不依赖任何组件,程序的其他部分应当作为业务逻辑的插件存在,去依赖业务逻辑而不影响它。这和「软件应该与设备无关」的思想是同源的。

尽可能推迟细节决策

软件分为策略和实现细节。细节是软件中最「脏」的部分,包括如何操作数据库(使用 SQL 还是 NoSQL,编写什么 SQL 语句,甚至直接使用文件系统而不用数据库)、如何呈现用户界面(怎么把数据传送给前端、前端怎么展示数据)等等,甚至包含如何与硬件打交道(不过这可能是操作系统和固件的活儿了)。软件最脏的部分一般是 Main 组件,它是程序的入口,调度和加载所有必要的资源。

策略往往是高度抽象的,包含实体和用例。实体一般是指核心业务逻辑实体,比如一个员工管理系统里可能就有 Employee 实体,这里包含最核心的数据和操作。所谓核心业务逻辑,就是没有计算机、没有自动化系统,也能为企业产生价值的操作,比如银行没有自动系统,也会请专人来做必要的计算。而用例,就是有了软件之后才产生的东西,一般是站在用户视角的,比如「用户应当能通过系统提交工时数据」就是一个用例。

编写软件时,最先写的应该是最抽象的核心业务逻辑,其次是用例,定义用户如何与实体交互,最后才决定要不要用数据库、用什么数据库系统、用什么应用程序框架、要用 Web 还是桌面端 GUI——换句话说,应该尽可能推迟细节决策。

为什么?首先,业务逻辑是最重要的,是给软件创造价值、给企业赚钱的东西,而技术细节可以随时更换,并不重要,使用什么类型的数据库并不会显著影响软件行为。其次,尽量推迟决策可以让架构师有更多的时间收集信息,决定这个系统更适合用什么技术。如果架构足够灵活,技术细节就仅仅作为业务逻辑的「插件」存在,可以随时更换。

在开发初期如果没有数据库和用户界面,要怎么调试程序呢?很简单,让实体和用例使用抽象接口,比如编写 Storage 接口,然后实现一个 InMemoryStorageMockStorage 类,等决定要好用什么数据库了,再编写 MySQLStorage 等具体实现就好,业务逻辑和用例的代码完全不需要修改。如果要给软件添加更多的存储方案,还可以再写 FileStorage PostgreSQLStorage 等等,这就是技术细节作为「插件」的思想。

此外,由于最抽象的业务逻辑不应该依赖比他更具体的组件,这时候依赖反转和依赖注入就派上用场了,使用这种编程模式就能让更具体的组件依赖业务逻辑。

总而言之,先编写最抽象、最高层的组件,忽略技术细节,尽可能推迟细节决策。

良好的架构是灵活且可测试的

我原本以为各种测试方法是为了保证软件质量而不得不采取的措施,通过让测试编写者和开发者慢下来,更仔细地思考如何写代码。可 Bob 大叔在书里表示,使用测试驱动开发,在短期和长期都会让开发速度更快。我想这是因为写好测试用例之后就了解输入和预期结果是怎么样的,编写算法实现也就更符合直觉。

我读技术类书籍往往很慢,一方面我需要更多的时间消化信息,另一方面,尽管这类书读起来也有醍醐灌顶的感觉,但整体上不如文学作品吸引我。所以,这本书我花了一两个月来读,这期间我也有开发一些玩具软件,每往后读一点,我就觉得我的软件架构问题越来越多,首当其冲的就是「不可测试性」。

大概是被 Lisp 系语言的 REPL 宠坏了,我从不编写单元测试(甚至有段时间会让 Coding Agent 帮我写测试),在本地测试的时候能跑通就行,导致我很多时候是把代码推送到生产环境之后才发现问题。最近我想要给 Weepinbell 加上单元测试,Clojue 和 Leinigen 提供了很好用的测试工具,但我发现我的架构不允许我对单个组件进行测试。

首先,我的大部分组件都依赖 config 组件,它直接从配置文件里读取配置。

(defn load-config []
 (let [default-config (when-let [resource (io/resource "config.edn")]
 (-> resource slurp edn/read-string))
 external-file (io/file "config.edn")
 external-config (when (.exists external-file)
 (-> external-file slurp edn/read-string))]
 (merge default-config external-config)))

(def config (delay (load-config)))

(defn get-config [key & keys]
 (get-in @config (cons key keys)))

我想先从最简单的 Webhook 组件下手,这个组件只提供 trigger 方法,从配置里读取 Webhook URL 然后向它们发送 HTTP 请求。

(defn trigger [keyw]
 ;; keyw = on-receive, on-create, on-update, on-delete
 (when-let [hooks (get (get-config :webhook) keyw)]
 (->> hooks
 (filter string?)
 (filter valid-http-url?)
 (map #((client/post %)
 (timbre/info "Webhook triggered: " %)))
 doall)))

假设我要测试 Webhook 能否成功发送,那我要做得就是在测试代码里启动一个接收 Webhook 的测试用服务器,让 webhook/trigger 给测试服务器发送请求,测试服务器判断有没有收到请求。问题来了,我要怎么改变 (get-config :webhook) 的取值呢?它只能从配置文件里读取配置。这个组件和 config 组件是耦合的,而我没有提供其他注入配置的方法。

如果我要解决这个问题,我就必须重构,其他调用 get-config 的组件大概率也要做修改。这就是不好的软件架构带来的问题,软件变得难以测试,重构又会导致大量的代码变更。

很快我又发现了更多的问题,那就是用于处理 Webmention 请求的 processor 应该是抽象的核心业务逻辑,然而他却依赖更具体、更脏的 webhook,我在一开始没有考虑到依赖反转原则。

config 的问题也可以用依赖反转解决,应该想办法让配置被「注入」到业务逻辑中,而不是让业务逻辑调用 get-config、依赖这个更具体的组件。我的代码里,业务逻辑依赖了太多细节,导致架构变得凌乱,不够整洁,也增加了维护难度,还让软件变得难以测试、容易出现缺陷。

而这样的代码是大部分人(包括 Coding Agent)都很容易写出来的代码,如果一开始不从宏观层面考虑架构问题,就只会在开发中后期才意识到问题所在,那个时候就已经晚了。一开始就应该考虑架构的灵活性、可测试性和软件的可维护性。

依赖关系和可维护性

整洁架构的目的是让软件系统变得灵活(易于变更)、容易测试(证伪软件缺陷)、保证软件质量、保证可维护性。看起来架构的关键要素之一就是依赖关系,之前一直在谈依赖反转、无循环依赖等原则。我想这是因为,如果软件没有被分成多个相互依赖的组件,就没有架构存在。架构(archtecture)的本意就是建筑,是把软件一个一个有序地堆叠在一起的方法。

自己编写的软件内部的组件相互依赖关系很重要,软件依赖的第三方库也很重要。前面提到组件耦合的共同复用原则(CRP),要求如果某个组件依赖另一个组件,最好要使用其中所有的类和方法,否则依赖的组件只要发生了一点改变,哪怕自己没有依赖更改的这一部分,也需要升级依赖、重新编译和部署软件,有时候甚至要变更代码。这会提升工作量。

读到这里的时候我立马想到了 JavaScript 开发者的现状:大部分的工作都是在维护依赖,软件几乎没有真正「稳定」的时候,如果几个月都不升级就会被淘汰。我想很大一部分原因是 JavaScript 开发者没有遵循共同复用原则,依赖了大量不需要的代码。

对比 Go 语言这边,Rob Pike 说: A little copying is better than a little dependency. 比起依赖会动态变化的软件库,直接复制粘贴自己需要的那一小部分代码更好,因为写在源代码里的东西是静态的、稳定的,不会改变。保持依赖树的整洁和精简有助以提高软件的可维护性。

微服务不是架构、应用程序框架不是架构

许多人觉得使用了微服务就默认拥有了一套架构,因为服务是独立开发、独立部署的,所以一定符合「高内聚,低耦合」的原则,但实际上并非如此。微服务架构本质上是把软件组件之间的函数调用变成了网络通讯,数据通过序列化的对象在网络之间传递。Bob 大叔举了某个产品的例子,它们一开始使用这种通信方式,可后来发现客户根本没有独立部署服务的需求,软件在本地的一台机器上通过网络互相传递数据。因为边界已经确定,修改起来很困难。

由于改变的只是组件之间的通信方式,并没有改变依赖关系,所以组件之间仍然有可能是耦合的。微服务架构并没有提供一套默认的整洁架构。

不少应用程序框架(比如 Spring)都有一套架构思想,并期望开发者使用,并将他们的代码完全与框架耦合。然而,这些框架尽管方便,但并不一定适合所有软件系统。应用程序框架不是架构,相反,它只是实现细节,和数据库一样,应该作为业务逻辑的插件存在。也因此,应该推迟「使用什么程序框架」的决策。

这让我反思,我在编写前端项目时做的第一件事就是选择框架,用框架自带的脚手架搭好项目结构才开始写代码。后端也是,在学校里教的 Java Web 开发,几乎就是 Spring Boot 的框架知识,都是先选择了 Spring Boot 框架之后才开始写代码、才开始考虑架构,而此时的架构就是完全与框架这个技术细节耦合的。似乎很少有人意识到,框架不是架构,使用框架不代表有良好的架构这个事实。甚者,和 Java 开发者离开了 IDEA 不会写 Java 代码一样,离开了框架一些人也不会开发程序了。

前端开发或许有其特殊性(因为按照书里的说法,前端作为 GUI,本来就是技术细节),但如果要考虑整个软件的架构,应该先从业务逻辑开始,再考虑组件之间如何通信、要不要用微服务架构,以及要不要用 Web、要不要用框架的问题。


最后

  1. 去读电子工业出版社出版、孙宇聪翻译的《架构整洁之道》,或者直接读《Clean Architecture》英文原本,不要读机械工业出版社的这本《整洁架构之道》。
  2. 软件的依赖关系应该指向最抽象、最稳定的组件,即核心业务逻辑。
  3. 数据库只是技术细节、Web 只是技术细节、应用程序框架只是技术细节,应该尽可能推迟细节决策。
  4. 好的架构是灵活且可测试的,测试和文档一样也是软件的一部分。

稻草人周刊 Vol.77

这周三得知周四周五有校运会,停课两天,加上周末,我突然拥有了四天的假期,于是溜出去看了《挽救计划》,逛了美术馆,还和朋友租了 Minecraft 服务器玩。精神状态似乎好了不少,接下来的一周要重振旗鼓啊。

这周听了不少新音乐,但阅读的时间倒是变少了。效率最高的时候永远是摸鱼的时候,这周有一半的时间都没在干正事,也就没怎么读文章了。抱歉,下周再写点有意思的吧。


止语

Brand New Eyes

Brand New Eyes music cover

Brand New Eyes 专辑

Paramore

Paramore 的第三张专辑,目前听下来感觉一张比一张更像流行、更不像朋克,不过第一张专辑《All We Know Is Falling》其实也只是被归类在「流行朋克」下而已,本身就更偏流行。不过一开始我是把 Paramore 当作朋克摇滚乐队来听的,所以多少有些失望。

最喜欢《Misguided Ghosts》。

Paramore

Paramore music cover

Paramore 专辑

Paramore

这张给我的感觉就是完全的流行了,摇滚要素当然也是有的。到这里似乎乐队成员也换了不少,风格有明显的改变,没有听第一张专辑时的惊艳感了。不得不说这张专辑的 Paramore 听起来成熟不少,尽管特色没有那么鲜明,但听感要比上一张好一些。

最终的评价是:能听。

A Matter of Time

A Matter of Time: The Final Hour music cover

A Matter of Time: The Final Hour 专辑

Laufey

看完《Madwomen》的 MV 之后爱上 Hudson Williams 了,之前看《巅峰对决》的时候还只是有点欲火焚身而已。春天真是把我害惨了。

认真地讲,Laufey 的这张专辑我还挺喜欢的,很有意思的中式复古元素(至少我只能这么形容),没有太淡也没有太流行,对我来说恰到好处。最喜欢的是《Lover Girl》《Too Little, Too Late》《Madwomen》。

drop dead

drop dead music cover

drop dead

Olivia Rodrigo

Olivia Rodrigo 第三张专辑《you look pretty sad for a girl so in love》的首张单曲《drop dead》在这周发布了。虽然这首不是我更喜欢的朋克,但主题和曲子都一如既往地很对我胃口,还有这句歌词,不亚于上一张专辑中《ballad of a homeschooled girl》里的那句「Each time I step outside, it’s social suicide.」

“Kiss me and I might drop dead.”

另外 Bridge 部分的这句歌词也让我很在意:

Pisces and a Gemini

But I think we might go really nice together

在意的原因是我这个太阳双子一两年前喜欢过一个双鱼座直男,这下真的 drop dead 了。总之专辑将会在今年六月 12 日发布(等等这不是双子座生日吗?),期待有 Olivia 和冷泡咖啡的夏天。


连接

有屁就放的艺术

📜

作者讲解了克洛克法则(Crocker’s Rules),查阅后我发现这是 MediaWiki 的主要贡献者和 Wikipedia 编辑 Lee Daniel Crocker 提出的概念1。大概的意思是:直接交代信息,去掉社交缓冲层。这是一种社交协议(protocol),前提是双方都同意应该以这种方式沟通,而且一般是在专业场景下和工作关系中。

反例是回复邮件时先道歉「抱歉回复得太晚了」,或者在回复 PR 的时候表示「希望你周末过得愉快」,亦或是在提出问题时写「我知道我可能不该在这里问,如果你不同意的话我完全理解,但我想现在的错误处理方案可能有些问题?」——如果这么问的话,处理这个问题的人就必须再问一句「你能展开谈谈吗?」,才能知道问题具体出在哪里,明明可以在一开始就把问题说清楚,而不是先表明自己是个友善的人,然后征求提出问题的许可。作者认为直接提出问题,就事论事,才是工程师的做法。

作者在开头表示这条规则仅限于文字交流,并且应该在彼此熟悉的团队伙伴之间进行,如果是面对面交流或者面对新人,缓冲层可能是必要的,而且克洛克法则并不鼓励恶意攻击。在我看来,这只是做了课题分离:你听了我的话之后会不会产生情绪、如何应对情绪,是你自己的课题,与我无关。况且,预设对方听不得直接的话所以加上一大堆噪音信息,在我看来更不礼貌。

作者举的一个反例是 I know this might not be the right place to say this…,我意识到我前不久才在 Anna’s Archive 的 Matrix 群组里说过相同的话,不过我想这是面对不熟悉的环境和人时必要的做法(况且我也真的不知道应该不应该在开发群里讨论这个问题)。在熟人之间能建立起这种就事论事、有话直说的社交氛围,我觉得还挺好的。

用 Git 提升写作质量

📜

作者用 Git commit 作为「思考单位」,大约每两三百个词之后,就会提交一次 commit,每篇文章由十多个 commit 组成。一方面,这是循序渐进的写作过程,能避免在写作的初期投入太多精力导致力竭(burnout);另一方面,养成习惯之后,这种方式也能帮助写作者更好地计划写作。

我一般都是在写完一大串文字之后觉得累了,准备离开电脑休息时才提交一次 commit,或者有别的事情要去做,需要离开当前的工作区时才提交。仔细想象,我的确很容易在一个项目上花费太多时间精力,即劳神费心,也因为用了太多时间打乱了原有的计划。

间歇性地停下来回顾自己之前写了什么,提交工作之后再继续,也能提供必要的反思。总之是值得一试的方法。

另外作者还写了个 Emacs Mode,展示自上一次提交起,自己写了多少字,以及今天提交了几次 commit。我承认我有点眼馋,但至少现在我还没有准备好使用 Emacs。

从 DigitalOcean 迁移到 Hetzner

📜

作者分享了他把有着三十多个 MySQL 数据库和三十多个 Nginx 虚拟主机的服务,从 DigitalOcean 迁移到 Hetzner,并且在迁移过程中保证服务一直在线的方法。大概就是先在新服务器上复现生产环境,迁移数据,保证可用后再动 DNS,这中间还经历了系统升级和版本兼容性问题,详细的技术细节和一些疑难杂症的解决方案可以在原文阅读,作者开源了过程中用到的脚本。

迁移的契机是他们在土耳其发现服务器的价格和美元汇率变得越来越离谱,以至于每个月要花出去一千多美元。他们发现 Hetzner 提供的性能更好得机器反而更便宜,而且便宜得离谱,一个月只需要花两百多美元。

谈到这个我就不得不再提一嘴,脱离美国公司,选用欧盟地区的云产品,还有别的优势。只要运营商不是美国公司,就不受 CLOUD Act 影响,欧盟还有十分严格的 GDPR 法案保障隐私,瑞士的隐私法律更严格。如果需要租赁高性价比的 VPS,建议从 Hetzner、Contabo、OVHCloud 和 Netcup 等欧盟服务商中选择。


切片

  • 更新了个人主页的 /uses/creates ,诚邀读者观摩。

  • 现在你可以再次给极客死亡计划上的文章「献上心脏」了。

  • 某天丢垃圾的时候两个老人抢我丢的纸板箱吵起来了,我很懵。好像还动手了,走了一段路还能听到声音…… 不过说实话是那个老大爷半路杀出来抢的,把我都吓了一跳…… 这么热的天在家里好好待着不行吗?

  • 我在 4 月 18 日发了一条「I’m a teapot」但是无人看懂,唉。

  • 想要一个备份的联邦宇宙账号以防失联,在 FediDB 翻了半天发现大部分公开实例都是 Mastodon,我又不太喜欢 Misskey 系的软件,而我几乎找不到公开的 Akkoma、Pleroma 和 GoToSocial 实例,于是…… 只能去 Mastodon 了,找个郊区待着吧。

    因为还打算用备用账号发英文内容、和国际友人社交,所以找个看起来靠谱的英文 Mastodon 实例是最好的。最后看中了 tech.lgbtWhy not?),注册了,等待审批中。

    不出意外的话,过几天就可以在 @eltrac@tech.lgbt 上找到我。

  • 自己维护基础设施真的会很害怕服务下线导致失联啊,这是我还没有决定自建邮件服务器的主要原因。

关于「林卷」页面的详细说明

本来不想淌浑水,像以往一样保持沉默是最好的,但我发现还是有不少人误解 林卷 页面存在的意义,以至于对页面内容的微小变动都产生了不必要的关注和猜想。所以,解释是必要的,尽管我有预感写完这篇文章之后我被误解的概率会只增不减,但至少我把话说明了。

极客死亡计划没有友情链接

本网站没有「友情链接」这个东西。我不是在重新定义友情链接,也不想要改变任何人,我只是没有友情链接这个东西。我不知道这样说够不够清楚了:极客死亡计划没有友情链接。

林卷页面里列出的博客链接,请读者看清楚了,我从来没有说过它是友情链接,我写的是「我常看的博客」。不要因为不少博客喜欢用「左邻右舍」这样的词代替「友情链接」四个字,就以为我说的也是一个意思。请读者再看得仔细一些,我是这样说明「我常看的博客」这一栏内容的:

以下内容直接从我的 RSS 阅读器导出的 OPML 文件生成,是我订阅的所有 RSS 源,包含我常读的博客和关注的媒体。每次构建时乱序输出。

所以,如果发现我添加了谁或者删除了谁,这不是因为我和对方达成了某种契约,友好地进行了交换,也不代表有任何矛盾和冲突发生。这是个相当中性且相当主观的过程:我发现了我觉得有意思的网站,我把他添加到了 RSS 阅读器里,后来被导出为 OPML 格式,我的静态网站生成器 Hugo 直接读取 OPML 文件生成列表。

请允许我为你详细讲解这个过程有多么无聊,多么缺少钩心斗角。

在我博客主题的 layouts/_shortcodes/opml-links.html 文件中,我定义了一个可以嵌入在页面中的短代码。它从网站源代码的 /data 目录下获取名为 rss 的数据,这里指的是 rss.xml 文件。

{{ $opml := hugo.Data.rss }}

<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
{{ range shuffle $opml.body.outline }}
 {{ $title := index . "-title" }}
 {{ $url := index . "-htmlUrl" }}
 {{ if and $title $url }}
 {{ $parts := split $url "/" }}
 {{ $url := printf "%s//%s/" (index $parts 0) (index $parts 2) }}
 <a href="{{ $url }}" target="_blank"
 class="block rounded-md overflow-hidden box-border p-4"
 style="background-color: var(--block-background-color);
 color: var(--text-color);
 text-decoration: none;">
 <h3 class="m-0 text-lg font-medium">{{ $title }}</h3>
 </a>
 {{ end }}
{{ end }}
</div>

rss.xml 文件也不是我手动编写的,而是从我的 RSS 阅读器直接导出。我使用基于命令行的开源 RSS 阅读器 blogtato ,导出时我只需要执行一条命令1,然后推送到 Git 仓库即可。

cd ~/Projects/geek-death-project/
blog feed export > rss.xml
git commit -m "[chore] update rss.xml"
git push

所以,「我常看的博客」中有任何新增和删除,都只是它们在某次数据同步时程序自动化处理的结果,而之所以数据会发生变更,只是因为我调整了我的 RSS 订阅,调整的策略非常简单:我添加那些更新之后我希望第一时间被通知的订阅源,我移除那些我很久都没有点开阅读、仅仅是增加未读数量的订阅源。

想要被通知可以有很多原因:我喜欢某个作者的内容,想要在未来读到更多;我觉得某个订阅源有一些高质量内容,可以作为资讯和知识来源;我想看某个蠢货继续犯蠢,以作为人类观察样本;我感到无聊,需要一些新鲜内容。

很久没有点开阅读有很多原因:近期某个作者开始发一些我不感兴趣的内容;我一开始关注某个作者是因为他的某一部分创作,深入了解之后我发现整体而言我对他兴趣寥寥;某个订阅源更新频率太快了,我读不完;猎奇心理减弱,我对蠢货提供的样本感到厌烦;我最近接收的信息太多,所以想要精简和整理订阅源。此外,移除之后不代表我就此与某个作者决裂,我仍然会时不时点开他们的网站,我只是不想要被通知而已。

我想我解释得够清楚了,我绝对没有和人闹矛盾之后,阴暗地念叨着骂人的话,然后把它从我博客的某个本来就不是友情链接的页面里移除。

“你为什么这么反感友情链接?”

我不反感友情链接!我说的只是:极客死亡计划没有友情链接!

极客死亡计划也没有常规的评论系统,但我并不反感评论,相反我很期待交流,我只是在众多的交流媒介中选择了当下最适合自己的,而这个媒介恰好不是「默认选项」而已!

请不要用「默认选项」来解读我网站上的内容。

“所以你删了谁啊?”

太多了,数不清。另外我其实不太喜欢「删了某个人」这种说法,因为我没有删掉谁的联系方式,没有在人际关系层面上和任何人决裂,我只是把某个订阅源从我的 RSS 阅读器移除了,然后数据被同步到了我的博客上而已。

只不过另我感到匪夷所思的是,在我删过的众多链接中,有一个脱颖而出。对方看起来没什么意见,倒是有其他人感到异常好奇。

?不是,这几天老有人突然出来问我为什么和极客死亡计划互删“友情链接”,主要是我都不知道他删了我,我只是最近整理了一下列表,单纯是因为不常去逛了,我确实看不懂技术类的东西,这是我的个人能力问题。而且我页面的“友情链接”真的单纯是因为我想要有个入口进入这些页面,也有原因确实有友情部分,比如非理勿试,他是我这个博客第一个朋友。

刚才来了一个人问,我认真回答了,他就删除了我们的telegram聊天框,啊卧槽,你知道这对于一个事事回应的人有多烦躁吗?没有前因后果,哪怕你告诉我你想八卦我也接受,不能把我当个洞插了说不够润滑就把我扔了啊!!!

—— ♾️莫比乌斯环世界♾️

我把莫比乌斯从我的 RSS 订阅列表移除的原因是「内容不感兴趣了,所以不常读了」,对方把我的链接移除的原因是「单纯是因为不常去逛了,我确实看不懂技术类的东西」。他的网站也没有「友情链接」这个东西,只是作为入口;我的网站没有「友情链接」这个东西,只是展示我的 RSS 订阅列表。

如果没有人告诉他我删除了他的链接,他就不知道这件事情;如果不是我删掉订阅源之后仍然会时不时去逛逛,我也不会知道他也删除了我的链接。你看,这本来就是双方都不知情也无需知请的小事(因为我们都没有友情链接,没有形成任何必须保留链接的契约),我俩把自己的事情管得好好的,不觉得有什么问题,其他人可以也把自己的好奇心管一管。

而且,我不仅没有刻意地把莫比乌斯从我的页面上移除,他的链接仍然还在林卷页面的另一个地方。林卷页面是外部链接的聚合,包含我的 88x31 按钮墙、我的 RSS 订阅列表和博客的外部链接引用次数排行。所谓的引用次数,就是来自某个域名的链接在我的文章中出现的次数。

这个引用次数统计是由一个 Go 语言程序 生成的,在网站每次构建时,它会自动扫描所有 Markdown 文件,匹配文件里的所有链接,提取出域名,然后放入一个键值对数组,最后导出为 JSON,由 Hugo 生成静态的引用次数排行。

如果读者看得足够仔细,就会发现 onojyun.com 这个域名安然无恙地躺在那里。如果我真的阴暗地要与对方决裂,我就会在那个 Go 程序里写个特例,屏蔽掉 onojyun.com 域名,这不难。

“你搞这么复杂干嘛?”

因为我喜欢。

认真地讲,RSS 订阅列表能最真实地反映我关注什么,外部链接引用排行能最真实地反映我提及得最多的是哪些网站、从哪里获取信息用作援引、和哪些博主有直接的智识交流。为了维护这种真实,我需要排除所有人际关系的束缚,让我自由地、主观地调整订阅列表;我需要用最冰冷的自动化程序呈现最真实的数据,比如,尽管我更喜欢 Codeberg 而不是 GitHub,我也要接受 GitHub 现在就是极客死亡计划外部链接排行榜的榜首这个事实。

极客死亡计划本来就是我真实思考和真情实感的载体,林卷这个包含了最多「外来者」的页面也是一样的。

不过也有朋友提醒我,订阅列表这类私人的东西或许不该公开。尽管我不觉得见不得人,但难免会引发误会、纠葛和不必要的讨论。我仔细想了想,留着的确也没有太多用处,而且我也不想手动再维护一个列表,我懒,维护 RSS 订阅列表就很费精力了。我最近的确在博客上删掉了不少页面,或许林卷会是下一个呢?

从另一个角度看,仅仅因为有人误解和不想要处理麻烦的人情世故,就删掉友情链接(是的,几年前博客还不叫「极客死亡计划」的时候是有友情链接的),再删掉任何形式的链接,未免有些窝囊。

话说回来,自从换掉评论系统后,和我产生交流的大部分人都不是路人,偶尔会收到陌生的读者发来的电子邮件,大部分都很友好且诚恳。那些不愿意了解我,继而让误解占据他们头脑的人,也因为懒得读一大段关于评论的说明、懒得注册联邦宇宙账号,也不愿意发电子邮件而就此止步。

真正愿意交流的人会找到方法的。我很感激 远景 友人前不久通过 Webmention 跟我进行的有来有回的对话。简单来说,我们是在各自的后花园网站上发布页面,然后相互提及,发送 Webmention。我还在用 Giscus 的时候,也有人专门注册 GitHub 账号留下评论。如今我也能收到不少有趣的电子邮件。顺带一提,如果你更偏好即时通信的话,我没有 Telegram,但可以用 Matrix 找到我,我的账号是 @eltrac:eltr.ac

而且说实话,如果我今天没有去逛莫比乌斯的网站的话,也不会知道居然有人关注这些鸡毛蒜皮的小事,我已经和无聊人士离得很远了。

所以,我大概还是会保留林卷页面,爱订阅什么订阅什么,爱删谁删谁。我本来就没有向任何人保证任何东西,我只向自己保证我的诚实。


  1. 感谢作者 kantord 的及时响应,我给他提了这个 需求 之后他很快就实现了。 ↩︎

Gaming to Stay Sane

I’ve been playing a lot of DST lately, pushing towards 1000 hours of total play time. It’s odd that I actually stopped playing video games for months (more than half a year I think?) before this. And I’ve been thinking about why I started it again all of a sudden.

One of the many reasons is that I had to look for internship opportunities and I’m sort of overwhelmed by… everything. Sure, I can blame bad economy, AI hype and coding agents making it objectively hard to find jobs because there are fewer available. But I feel like I’m not really in the position to put any blame because, well, I haven’t sent out a single resume yet, when I had planned to do so for weeks.

“Why not?”, I asked myself. “I don’t know.”, I respond.

I actually found some interesting jobs. One of them is founded by YC. They are located near me. They want someone who can read and write in English, which I’m obviously capable of. They’re hiring backend interns. Everything seems nice.

“So why not?”, I asked again. And again, “I don’t know!”

I realized there are some internal obstacles keeping me from making any real contact with any company, probably because they’re too real and it’s scary. I feel like a little baby saying this but it’s brutally true. My anxiety is real. I find it psychologically and physically impossible, even though I know I meet their requirements and it wouldn’t hurt to try.

But I can’t. There is a huge gap between rationale and action that people seldom talk about.

I guess it’s one of the 4 F responses, Fight, Flight, Freeze and Fawn. I was frozen in action. My mind went blank. And then I fled. I tried to get busy with other things and hopefully they’ll ease the pain. Uncertainty is the greatest pain that a human can bear, apart from giving birth I assume.

And video game was one of the other things.

I just spent the last two or three hours beating Deerclops, gathering resources, taming my beefalo and constructing my base. Before that, I cleaned my apartment, the floor, the tables, the closet and everything. I finished reading La Mort Heureuse, written by my favorite author, and I wrote a book review . I exercised and sweat the hell out of myself. And that was my day. I did nothing productive.

For readers who are not from China, I probably should fill you in with some information. Universities here usually don’t permit students to find intership on their own during a semester, because the courses are scheduled (and we don’t get to choose the major courses either). Skipping class is possible but the counselor can be annoying, which I will not elaborate. In the meantime, I have a course called Career Planning and Employment Guidance, which is pretty much pushing me to get a fucking job. The teacher was like: If you want an internship you should apply now! However, tell the employers you wouldn’t be there until like two or three months later.

I don’t know if this is normal. It feels nonsense to me. But I wouldn’t know. I’m too scared to even try. It took me 2 months to draft a resume and god knows how long it’ll be to actually find a job.

By the way, my DST save is named I don’t wanna find a job!.

As I mentioned, I haven’t played video games for months. I had been reading, writing, coding and doing other productive things. I had a job actually, but it was way less frightening. I worked in a tuition place where I teach spoken English. It was easy and the people were nice. And I got that job because I took classes there, and they just offered me the job. My colleagues were my teachers and classmates, not strangers on the Internet from a big scary company. Wow, I really am a baby.

So, here I am, stuck in an awful situation where I’m not allow to do the thing I was told to do, and everything is too new and too strange for me. Worst part? Nobody understands.

I hate being around people so I moved out of dorm a year ago. It was nice living alone but it feels lonely (I do have a roommate, but again… I will not elaborate). My only friends are older than me and they’re working their asses off these days. And I suck at being vulnerable to people online (and I probably shouldn’t anyway). I feel miserable and unheard.

I never felt comfortable running away from my problems. I know life is a never-ending series of problems, and solving them was one of my life purposes. I like solving problems to be honest. But I hate being unable to solve problems I’m aware of and that are slowly sucking my soul and energy with its mere existence. It’s a black hole.

So I had to run away from it. I know things will look up in a few months, or maybe in a few weeks. But there’s nothing I can do at the moment, at least nothing that I’m mentally capable of. With my hands tied and a giant black hole sucking me dry, I just had to run. Or dance, if you want to be poetic or a swiftie1.

I ran straight into The Constant, the world where DST lores take place. Filled with scary-looking monsters, The Constant is not really that scary. There are constant troubles I had to deal with and the problems are what kept me moving. I had to kill the winter boss and make an umbrella out of its eyeball to survive rainy spring. I know I also had important problems in real life and I had to get moving to solve them, but not while I had drained my sanity.

I listened to a podcast. They were talking about what to do when you hit rock bottom, or just had too much chaos in your life. One of the solutions was to do nothing, lie down on the bottom and rest. As long as it’s a cautious decision, there’s nothing to be ashamed of, because you knew you will bounce back, just not now, not while you may go insane forcing yourself to bounce back.

I will live with chaos, because chaos is constant in life. I can solve some problems, but it’s a sickness dying to solve them all at lightning speed. On days like this, I should just do nothing and play video games all night long, for I know I will bounce back eventually.

And you know, it would hurt to indulge occasionally.


  1. OK. I’m guessing nobody gets this, so I will explain. Taylor Swift have a song called Dancing With Our Hands Tied, my favorite track on that album by the way. ↩︎

快乐的死

一本没有太多情节,以主人公的自我意识为主导的哲学或心理小说,主题显而易见,关于快乐、生命和死亡,当然还有活着的意义。《快乐的死》是加缪 24 岁写下的小说,也是他的处女作。尽管我对我最喜欢的作家多少有些滤镜(这话不是说说的,我现在坐的地方的左右两边都贴着加缪的海报),但这部小说的确不算出彩。给三分太低,给四分又偏高,于是我花了十分钟的时间写代码,让我的网站支持显示 3.5 这个分数——这就是对作家的爱和尊重啊。

主要情节

故事很简单,主人公帕特里斯·梅尔索厌倦了每天上班的生活,想要找寻自己和追寻快乐,于是他杀死了女友马尔特的前任扎格厄。扎格厄很有钱,但下半身瘫痪,被困在轮椅上,他作为年长者给了梅尔索一些人生建议。梅尔索在拿走了扎格厄的财富之后用枪崩掉了扎格厄的脑袋,并营造成自杀的样子,直到最后他都没有落网。这场谋杀对小说后续的情节可以说无关紧要,重要的是梅尔索拿到了一大笔钱,他可以去找寻自己想要的生活。至此,第一部结束。

梅尔索出发去到了布拉格(巧合的是我前不久才读完了《 不能承受的生命之轻 》,故事也发生在布拉格),在异乡的第一晚以及接下来的几天他都非常落魄,闻不惯街上酸黄瓜的味道、没有买到梳子所以顶着蓬乱的头发出门、听不懂服务员讲话所以多付了钱。接下来他又不断地旅行,中途在三位女性朋友的家里住了下来,那间房子名为「面向世界之屋」,因为景色很好,他们经常躺着晒太阳和欣赏自然。后来,他又遇到了吕西安娜,并与她结婚,只不过梅尔索不爱她(但他的确喜欢她,觉得她很美,他们让彼此快乐),那时他正在构建自己的「外在形象」,还开了一家药店,随便招了个人看店,并不在乎营收,只是为了给别人一个容易理解和接受的标签,以换取自由。

他也交到了一些朋友,比如一名独臂渔夫和医生贝尔纳。除了贝尔纳,其他角色都没有给我留下太多印象,毕竟小说的篇幅不长,而加缪把笔墨都放在了环境描写和梅尔索的自我意识上了。对其他人物的刻画不少,但不足以构建鲜明的形象,实际上就算是贝尔纳,他让我印象深刻的原因也只是他和梅尔索的死有关联。贝尔纳作为医生和朋友告诫梅尔索关心自己的身体健康,但梅尔索本人不以为然,他只顾着追寻快乐和理想的生活。梅尔索在深思过后,向贝尔纳阐明了自己的生活哲学,贝尔纳评价他为「理想主义者」。在我读过的一些法国小说中,医生都在某种程度上象征着科学,比如《 包法利夫人 》里的药房老板奥梅,他与象征宗教的神甫之间的互动令我印象深刻。贝尔纳对梅尔索的评价或多或少也反映了这一点,我想这也在某种程度上解释了梅尔索与现代社会的格格不入、一次又一次抛弃已经建立起来的生活的动机源头,以及注定的悲剧结尾(不过是否悲剧要打个问号)。

最后梅尔索死于疾病,在一场让他感到快乐的海水浴过后,他的身体开始抗议,潜藏已久的病灶终于发作,他在床上、在妻子的陪伴下,孤独且满足地死去了。

在他的体内,自腹部深处仿佛缓缓升起一颗石子,沿着他的喉咙向上攀升。顺着那石子经过的轨迹,呼吸也越来越急促。这股力量持续向上攀升。他看着吕西安娜,自然而然地露出微笑,毫无紧张感,这个微笑发自内心。他仰倒在床上,感受着体内的力量缓缓上升。他凝视着吕西安娜丰满的嘴唇,以及她身后大地的笑容。他用同样的目光和渴望注视着两者。

“再过一分钟,一秒钟。”他想。攀升停止了。然后,他化作众多石子里的一颗,满心欢喜地回归亘古不移的宇宙真相之中。


由于小说中其他人物的形象不够鲜明和立体,也就不足以构成值得分析的典型性,所以这篇书评余下的内容就简单地分析两个与梅尔索有关的问题。这两个问题分别关注第一部《自然死亡》和第二部《自觉死亡》,关于梅尔索的谋杀和他自己的死亡。

为什么梅尔索厌恶扎格厄?

梅尔索谋杀扎格厄当然是为了金钱,为了用金钱将自己从他不在乎的工作和他厌倦的生活状态中解救出来,但让他如此轻松且毫无愧疚地犯下杀人罪的原因是:他本来就厌恶受害者。为什么?为什么梅尔索厌恶一个束手无策的残疾人,一个在绝境中也有着好心态的年长者,一个喜欢他且慷慨地给予他人生建议的好人呢?

厌恶残缺、厌恶废物,还有最简单的雄竞。

厌恶残缺其实是厌恶肉体,这点在后续的情节中也有体现,比如梅尔索完全不关心身体的疾病,最后也死于疾病。在梅尔索第一次见到扎格厄的时候,他不想正眼看他,他告诉当时的女友马尔特:残疾人让我不舒服。不过,有趣的是,在第二部,梅尔索和一个只有一只手臂的渔夫做了朋友。失去行走的能力和失去一只手臂之间的区别在哪里呢?

在扎格厄与他独处,向他分享一些关于追求快乐和生活的思想时,梅尔索似乎一点也没听进去,他当时心里想的是:“一个废物,在这个世界上毫无用处。”第二部的断臂渔夫,能用奇特的姿势和梅尔索一起打台球,当然还能在海上捕鱼,失去了一只手臂的渔夫仍然有对抗自然的力量。由此我们可以进一步理解梅尔索的人生理想,包括在快乐之内的还有力量,抽象地讲,是指改变自己生活处境的力量(我们在小说中读到梅尔索一次又一次推翻并重新构建自己的生活),具体地讲,是指拥有健康的身体,或者用「健壮」这个词会更准确。

扎格厄其实和梅尔索有着相似的理想,扎格厄也曾想过拿到一大笔钱之后去过自己真正想过的生活,但意外发生了,他变成了残疾人,于是过起了质朴的生活。我想这可能是因为他觉得没有健全双腿的自己过不了想要的生活吧。某种程度上,扎格厄和梅尔索是极其相似的,只不过扎格厄比他年长,而他们的人生路线也因扎格厄的意外致残发生了分支。梅尔索对扎格厄的厌恶完全有可能是出于自我厌恶,他甚至心想扎格厄和他说话时是在取笑他,我想这是因为他觉得扎格厄的存在本身就是「小丑」版本的他自己,是他未来不想要成为的样子。他不想要失去健康、失去力量、失去追寻快乐的欲望,不想要成为废物。

至于雄竞,是因为梅尔索去见扎格厄的契机就是他突然得知女友马尔特以前有过不少情人,他想象着她和其他情人做爱时也做出相同的表情,这种想象让他受不了,于是他想要知道那些情人的名字,甚至去认识他们。是的,这还挺不健康的。

为什么梅尔索希望健壮且清醒地迎接死亡?

梅尔索在得知自己的情况时做了一个令人匪夷所思的决定,他没有向医生贝尔纳要求止痛药,而是要了几瓶肾上腺素,他想要清醒地迎接这个过程。在这之前,小说也写到,梅尔索在潜意识里期待死亡与血气方刚的身体相遇,而不是奄奄一息地死去。显然,梅尔索不想要寿终正寝的死法,他想要在健康(甚至年轻)的时候死去。这种想法很耐人寻味,我也格外感兴趣,因为我就跟朋友们表露过类似的想法:我觉得人活到四十岁就差不多了。我还觉得 蓝天白云、阳光明媚是值得去死的天气 。我想这是因为我接受不了衰老(至少现在还不能),我没有笃定这个想法,但也没有动摇。所以,我想要分析,为什么小说的主人公梅尔索也不想要在身体虚弱和意识模糊的时候死去。

前面我提到,梅尔索厌恶残缺,他渴望快乐的同时渴望健康和力量。一个人死去的方式反映了他活着的状态,梅尔索不想要奄奄一息地死去,是因为他不想要生命定格在自己失去健康和失去力量的那个瞬间。保持清醒也是如此,他之所以抛弃旧有的生活,就是因为他不想要迷迷糊糊、浑浑噩噩地活着。比起麻痹自己、忍受生活,他更想要保持清醒、面对生命的现实,同时在现实中追求自己想要的快乐。

到这里我想我需要解释一下「快乐」的含义,小说标题的原文是 La mort heureuse,这里的形容词是 heureuse 而非 joyeuse,意思更接近幸福而非欢乐或快感。但这里的快乐与幸福也有微妙的差异,从梅尔索的行为和最终的归宿来看,他追求的快乐大概就是没有束缚、与世界合二为一和不受世俗烦扰的状态。这种快乐的前提是自由,本质是无休止的对快乐的追求,追求快乐本身就是快乐,就像生活本身就是生活的意义。

然而,对梅尔索来说,衰老的过程是快乐逐渐消失的过程,衰老时人会渐渐失去追寻快乐的欲望,同时也会失去力量。我想梅尔索不会是服老的人,他不愿意接受智力和体力都被时间剥夺。他想要生命结束在这种快乐还持续着的时刻,健壮且清醒地迎接死亡,就是快乐的死。

与《局外人》的关联

小说的主人公名为梅尔索,这和《 局外人 》里的默尔索有什么关系?查阅过后,我发现梅尔索和默尔索其实是对同一个人名 Meursault 的两种译法,不过《局外人》里的 Meursault 似乎没有名字,只有姓氏,当然也有可能是我没找到。《快乐的死》里 Mersault 的全名是 Patrice Meursault

用同一个名字命名小说角色可能不是出于什么审慎的考虑,但这两个 Meursault 的确有相似性,可以说《快乐的死》里的 Meursualt 也是个局外人。不过,他不像《局外人》里的 Meursalt 一样漠视规则,想到什么说什么,《快乐的死》的主人公对社会规则仍保持着距离,但设法与之相处,比如通过结婚和开药店树立起外在形象,使他到处旅行的形象显得可以接受。也正是因为他不直接反抗规则,他才获得了自由和快乐的死,而不是像《局外人》里的 Meursault 一样死在监狱里。


摘录

第一部

  • 在绽放的空气和丰饶的天空中,仿佛人类唯一的任务就是快乐地活着。
  • 在那样简单明了,与世隔绝的日常中潜藏着一种隐秘的幸福。
  • 我们没有时间做自己。我们只有时间去快乐。
  • 去行动、去爱、去忍受痛苦就是生活,但前提是要变成透明人,坦然接受自己的命运才行。

第二部

  • 健康的人有一种艺术般的自然直觉,能避开病患火热的目光。
  • 事实上,只要向世界展示一个世人能理解的面貌就够了。懒惰和怯懦会解决剩下的问题。独立自主、无拘无束的日子可以用几句廉价的倾心话换取。
  • 他在潜意识里仍然希望,让血气方刚的健康生命与死亡相遇,而不是让死亡与奄奄一息相逢。
  • 而那些未曾付诸关键行动来升华生命的人,那些畏惧并颂扬无能的人,他们都害怕死亡,因为死亡宣判了他们未曾投入和参与过的人生。
❌