2026-06-01 07:39:48
我感到自己最近一直处于应激状态,随时准备和世界反目成仇、大干一场,这种状态大概是不适合做任何人生决策的,我在想应该调整调整心态,或许暑假该出去走走,也暂时把找实习的事情放一放。写作也有帮助,至少我在写词源学系列的时候心无旁骛,感到开心。
Olivia Rodrigo
But my head is full of poison, and my heart is full of doubt
I got toxins in my bloodstream, you tried hard to suck ’em out
And it feels like medication, and it’s good for me, I’m sure
But it don’t matter how your love feels anymore
It’ll never be the cure
📜
Marcin Wichary 注意到了 1997 年的软件 ClarisWorks 的提示框设计,按钮上写的不是「过会儿再说」「现在注册」「永不注册」,而是简单的十三个字母 Never, Later, Now(永不,稍后,立刻)。这看起来违反了 Avoid “Click Here” 规则(即按钮不应该使用「点这里」等模糊的词),用户如果不读提示框上的文字,就不知道按钮是用来做什么的。

改成 Never Register、Register Later 和 Register Now 能解决这个问题,但按钮看起来就不会这么整洁了。在我看来,丢掉多余的 Register 也能避免语义冗余,字太多不但会造成视觉负担,还会造成理解负担。
Jim Nielsen 对此有些思考,他把 Avoid “Click Here” 规则定义为「系统规则」,把 ClarisWorks 看似违反规则的做法当作最适合当前软件的「本地化方案」。他感叹,如今的软件为了扩大规模,貌似已经完全用成熟的「系统规则」代替「本地化方案了」,因为前者又快又足够好,费心思设计提示框的文字不仅费时费力,还不能带来显著的回报。
As software moves towards “scale”, I can’t help but think that systematic rules swallow all decision making because localized exceptions become points of friction — “We can’t require an experienced human give thought and care to the design of every single dialog box.”
我对此的看法是,在软件行业内的商业软件兴许不必在乎特异的、令人愉悦的本地化方案,只要跟着已经工程化的、被证实有效的经验走,就能快速且稳定地交付成果。不过,真正改变人们对软件看法的软件,往往不来自商业世界,比如 Linux;就算来自商业世界,也来自那些不守规则的人,比如 Notion 和 Arc。改变世界的东西,在我看来,很少来自追名逐利、总是试图复刻成功的人,而来自那些抱有热爱,匠心胜过野心的爱好者。
不过这两类人也不是割裂的群体,毕竟爱好者也要吃饭。
📜
文章列举了密码管理器 Bitwarden 的一系列缺点。这是个商业软件,提供订阅制的服务,同时也有自托管选项,但作者表示 Bitwarden 的官方后端完全是给企业使用的,普通人部署的成本很高。当然,有社区用 Rust 实现的 Vaultwarden 作为替代后端,个人用户自托管的成本被降低了很多,不过即便是这样也要依赖 Bitwarden 的客户端(尽管是开源的,也可以 Fork)。
之后作者还列举了 Bitwarden 的设计在用户体验上的问题(由于 Vaultwarden 是实现了 Bitwarden 的 API,所以这些体验问题我想也无法在这个开源的替代品中修复),比如在密码库之间移动项目,必须先把要移动的项目以明文导出,然后再导入要迁移至的密码库中,不仅麻烦而且很不安全。有些时候 Bitwarden 客户端更新会弄坏一些东西,还有很多烦人的小细节。此外,作者还列举了从 2023 年到今年,Bitwarden 的各种安全性问题,比如前些日子的 NPM 供应链攻击就波及了 Bitwarden 的 CLI。对密码管理器来说,安全问题是致命的。
我想补充的是,不久前 Bitwarden CEO 换人,引起了不少 风波 。尽管目前看起来安好,但貌似已经有一些发疯的前兆了。我决定脱离 Bitwarden 生态。
我是前不久才自托管 Vaultwarden 的,当时只是想要快点找到一个 Apple Passwords 的替代。一方面是为了完全自己掌控数据,另一方面是长远考虑,我之后可能会半脚踏出苹果生态,去整一台 Linux PC(不过近期还不打算折腾)。Docker 镜像跑起来的时候我就心生疑惑:这东西跑在公网上真的安全吗?密码库有必要二十四小时在线吗?
答案是没有必要。再加上 Bitwarden 最近的事情,我决定完全迁移到 KeePass 生态。KeePass 用单个加密的 .kdbx 文件作为密码库,不需要庞大的数据库和 Web 服务,用户可以把密码库放在任何位置,只要能同步文件就能够同步密码库。密码库主要用主密码解锁,还可以附加密钥文件和 Yubikey 做额外的保险措施(可惜我的 Canokey 貌似不支持相关协议,我没有深入研究)。我使用的客户端是
KeePassXC
,iOS 使用的是
KeePassium
,目前暂时通过 iCloud 同步密码库。
密码库上锁之后,浏览器插件就没办法和 KeePassXC 通信,解锁需要打开 KeePassXC 而不能在浏览器里完成,所以体验上会差一些,但还算能忍受。迁移之后我使用了大概五天,目前基本满意。
📜
一种架构设计方案:如果有一些大小适中的数据需要发送给前端进行展示,过滤和排序等操作不必在后端完成,可以把完整数据直接发给前端,由前端处理;这部分数据还能缓存在前端,需要重新排序或过滤的时候不必向后端发送请求。
当然,这不适用于所有情况,只有数据量不会造成很大负担的时候才这样做。这不仅不会让网络连接不好的用户感到卡顿,反而会因为 HTTP 请求的减少而优化这部分用户的体验。很多人觉得发送所有数据不利于网络连接,但很多时候需要发送的数据甚至不如一张 JPEG 图片大。另一个理由是:现在没有那么多数据,但以后可能就有了。这和抽象层一样,很多时候人们编写了太多额外的抽象,但很久之后会发现,其实根本就用不到。
作者还引用了加尔法则(Gall’s Law):
A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.
You have to start over with a working simple system.
大概是说,不能一开始就把系统设计得复杂,应该从最简单的可用系统开始做。
简单来说,作者的观点是,不要仅仅出于习惯划分前后端的职责,前端除了展示,也可以做基本的数据处理。哪怕不用前端极大化的方案,仅仅思考「数据处理可能不需要全部放在后端」这件事就能帮开发者设计出更好的系统。
📃
我已经在 先前的一篇文章 中详细地报过菜名,列出了近期的 NPM 供应链投毒事件,结果仅仅过了一个月, TanStack 就被投毒了。JavaScript 的包管理生态极度中心化,非常容易成为攻击者的众矢之的,而 NPM 本身的安全措施显然不够有效。如果暂时没办法离开混乱的 Node.js 生态(我们能想象一个没有 Node.js 的前端开发未来吗?),采取措施规避供应链攻击就很重要。
首先,大部分供应链攻击都利用 postinstall,安装依赖后直接在开发者的电脑上执行代码,偷取储存在本地的密钥等关键信息,那么默认禁用 postinstall 脚本执行就能避免这部分攻击。PNPM 默认禁用 postinstall,需要显式地设置
allowBuilds
允许指定的依赖执行 postinstall 脚本。
第二个规避手段也是 PNPM 默认开启的,
blockExoticSubdeps
会影响子依赖的安装(也就是 package.json 中没有直接声明的依赖,是依赖的依赖) ,如果子依赖来自远程 Git 仓库或 Tarball 直链,就会默认阻拦,只允许来自受信的目录(registry)、部分受信的 GitHub 仓库和本地路径。这个手段的有效性我持怀疑态度,恶意软件也可能来自受信的目录吧,默认屏蔽所有远程 Git 仓库和 Tarball 直链不也是在让整个 JavaScript 生态变得更加中心化吗?一旦 NPM 这个中心出问题,整个生态都会出问题,而 NPM 的安全性大家有目共睹。
第三个规避手段在我看来是最有效的:推迟依赖更新,因为大部分供应链攻击都会在几小时内被发现和修复。v11 版本的 PNPM 默认推迟一天,一天内发布新版本的 NPM 包不会被 PNPM 解析。用户可以把 minimumReleaseAge 设置项改得更长一些。
第四个手段是 PNPM 的信任策略,默认关闭,需要手动开启。
trustPolicy
目前只有一种策略,即 no-downgrade。开启后,如果某个包的信任等级在更新之后下降了,更新就会失败。信任等级是通过信任证据(trust evidence),我想应该是发布者的签名之类的,文档里没有写得很清楚。比方说先前的版本中,作者有给包签名,在某次更新中没有签名,那么信任等级就下降了,此时更新就会失败。
最后,无论如何都应该使用锁文件(lockfile),锁定依赖的版本号,并且要把锁文件 commit 到 Git 仓库当中。
抱歉,我老是把名字看成某个 C 语言编译器。
用 Go 语言写的 Git 命令行工具,可以当作 Git 的简单封装层,可以交互式地执行各种 Git 命令,还能全局模糊搜索命令。许多 Git 命令可以直接用 ggc 命令替代,而且变得更友好,比如 git commit -m "" 变成了 ggc commit ""(我一直觉得 -m flag 很烦),ggc add interactive 可以交互式地选择 diff(而不是整个文件)添加到 Stage。
整体而言,ggc 比 lazygit 更接近 Git,抽象层次没有那么高,而且更像 CLI 而不是 TUI。至于怎么选就看自己的偏好了。
访问: bmf-san/ggc
这周玩了很多的《饥荒》和《星露谷物语》,每天不是在建家砍怪,就是在一边钓鱼,一边等谢恩下班给他送礼物——这个男人怎么这么有魅力?
你没活干吗?1
我大概真的该好好干活儿了吧。
把《 当人们不再问好 》发在联邦宇宙上之后,被转发了几十次,貌似又小小地火了一把,收获了不少关注。和以往文章不同的是,转发到联邦宇宙上时我附加了一段 TL;DR(太长不看版),兴许我以后都应该写写这玩意儿?
周天去书店写东西的时候,看见坐在旁边的女生包上有一根黄瓜瑞克。
另外《瑞克与莫蒂》第九季第一集真好看啊。
继 Clojure 之后学的第二门 Lisp 方言是 Common Lisp(至于 Scheme,我也说不清楚为什么,总之暂时搁置了),打算用来写个小小的 Web 应用练手。CL 的各种设计我都还挺喜欢的,比如没有 false 只有 nil,调试程序时遇到报错可以直接替换有问题的值,在不修改程序的情况下临时执行,这样可以忽略当下不应该关注的代码细节。总之体验还不错。
另外它能直接编译成二进制文件,而不是像 Clojure 那样编译成 JVM 字节码。据说用 Common Lisp 编写的 woo 是所有编程语言编写的 Web 服务器中速度最快的,还不知道具体体验如何。
好久没跑步了,心率和呼吸倒是控制得非常好,不过心肺还没感受到负担,脚踝就在 1.5 公里之后不堪重负了,痛得不行。
于是跑完之后又回来做了 10 分钟 HIIT 把强度拉上来。
这么想起来人的脚踝真的承受了很多不该承受的重量呢。
词源学小知识:意大利语 ciao 的本意是「我是你的奴」。
这是谢恩的台词 ↩︎
2026-05-30 18:12:58
去年买了本法语童书作为阅读材料(后来发现即便是儿童读物,对我来说也有些难度,便闲置了),主角的爸爸在打电话时说了 allô 这个词。当时我以为是什么时髦的打招呼俚语,跟英语里的 sup(What’s sup?)一样,但查阅后才得知这是专门的电话用语,面对面打招呼时不说 allô。
正巧,最近在重温《生活大爆炸》的时候,听 Sheldon 说电话的发明者 Alexander Graham Bell(后文称作贝尔)希望人们在打电话的时候用 Ahoy! 打招呼。
据我所知,如今英语使用者更倾向于说 Hello,并没有为打电话这个场景选择单独的打招呼用词。而汉语使用者倒是很少在电话以外的场景用「喂」打招呼,就算有,语调也完全不同。电话上的「喂?」带有疑问语气,是上扬的,用于询问和测试连线是否正常,而面对面交流的「喂!」则是下沉的,一般是为了引起注意而使用。这么说来,汉语也有专门的电话打招呼用语。
我闻到了《猫头鹰化石》的味道。
Ahoy! 并不是贝尔生造的词,如果你看过一些海盗电影,或者在一些影视作品里注意过水手们说的话(抑或是某些角色戏仿水手或海盗时的用语),可能会熟悉这个词。Minecraft 的语言设置里有「海盗英语」这个选项,这其实是英语世界里非常具有传播度的文化现象,被称作「Pirate Speak」,甚至有一个非正式的节日名叫「国际像海盗一样说话日」,在每年的九月十九日。1

其中 Ahoy 就是海盗英语的 Hello,不过海盗究竟是不是真的这么打招呼,就另当别论了。另外一个比较著名的海盗英语是 Aye,意思是 Yes——另一种说法是,Aye 是 I 的变体,表示「我(同意)」2。《海绵宝宝》的片头曲就有 Aye, aye, captain! 和 I can’t hear you! 的对白。不过 Aye 究竟是不是现实中海盗的专属黑话,也要另当别论,据我所知苏格兰人就更喜欢说 Aye 而不是 Yes。3
尽管如今看来 Ahoy 更像是好玩的说法,有点像汉语里的 Oi!(光是想到这个词的发音我就要脚趾扣地了),不过贝尔生在十九世纪,那个时候海盗还没有作为热门的文化现象出现在公共视野,贝尔是不可能出于「像海盗一样在电话里打招呼会很好玩」这种理由提出 Ahoy 作为标准电话用语的——不过这么想还挺可爱。
要搞明白 Ahoy 是什么,还要往更久以前考查。
构词上看,Ahoy 是 a 和 hoy 的组合,后者据说是中古英语的一种叫喊声。这不难理解,读音近似于 hoy 的叫喊声在各种语言里都很常见,类似的还有 ho(联想圣诞老人的「Ho! Ho! Ho!」)。我接下来又要举一个奇怪的例子了,在《饥荒联机版》中,要把桅杆上的船帆收起来,需要点击桅杆,此时的动作提示词是「Heave!」,然后角色会操作绳索收帆,等到文字变成「Ho!」之后再点一次桅杆,船帆就会快速收紧;如果在「Heave!」变成「Ho!」之前点击第二次,角色就会显得手忙脚乱,收帆的速度会变慢。我自己玩的时候,喜欢一边收帆,一边默念「Heave——Ho!」,只要节奏对了就能很快将船帆收起来,我想操作时机不对导致操作变慢的设定,可能也是在模拟航海时的「节奏感」吧。
「Heave-Ho!」虽然不是那么著名的海盗英语,但它的确是水手的黑话4,用在拉东西的时候,有点像汉语里的「嘿咻——嘿咻——」。Heave 的本意是「拉、提、举」,Ho 则是纯粹的语气词,所以更好的翻译可能是「拉!——嘿!」。
貌似大部分语言都有使劲时使用的语气词,我这边的方言有发音似「嘿作」的语气词。这些词的共同点是以喉咙音 H 开头,后接一个大元音,比如 ah、oh 和 ay。
这可能是人类的生理结构导致的,即便不考虑文化背景,人貌似也会在搬运和托举重物、感到力竭时,不自觉地从喉咙发出声音。
回到 Ahoy 上来,hoy 本身是跨越多个文化的、自然的语气词,人类可能天然偏好用喉咙发出大气流音,即便没有语言也是如此。hoy 这种叫喊声本身是用于引起注意的,而 A 这个附加的元音可能是为了进一步引起注意。5
之所以不用简单的 Hi 或 Hello,是因为 Ahoy 方便在距离较远的情况下引起注意(也就是…… 吼得比较大声?)。虽然不清楚海盗是否用这个词,但据 Wiktionary 和 Etymonline 所述,这的确是水手用语,完整的用法是:
Ho, the ship ahoy!
使用场景是这样的:如果水手看见附近有另一艘船,要让对方表明身份,就站在自己的船上大喊「Ho, the ship ahoy!」。如果有一艘小船(boat)正在靠近大船(ship),大船上的人就可以喊 Ahoy,小船的标准回应方式是:
Ahoy 和 Aye 这些看起来怪怪的词,可能都是航海时距离太远,需要大喊才产生的。
所以为什么贝尔希望用 Ahoy! 作为标准的电话招呼用语,而为什么 Hello 代替了它呢?
当我写下上面这句话的时候,我天真的以为自己能找到答案。实际上,相关的词源资料很少,难以考证,有不少自称「历史事实」的网站根本没有给出任何令人信服的来源和证据,完全是在凭空讲故事。而且我发现不少来源的说法都有细微矛盾之处,比如,大部分人都说 Ahoy 是贝尔提出的标准电话用语,而又有 说法 指出贝尔用的词实际上是 Ahoy-hoy。
有趣的是,《辛普森一家》中的伯恩斯先生接听电话时说的是 Ahoy-hoy ,兴许是为了调侃他年事已高,说话方式也过时了。
电话刚诞生的年代大概是十九世纪早期,那个时候 Hello 也是个新词,人们并不是直接把面对面交谈的习惯迁移到了电话交谈上。实际上,电话对当时的人来说是非常陌生的发明,人们不知道如何使用。据说有一些顽固的人对新技术接受能力低,把电话称作恶魔的发明,使用者会被雷电击中,另外还有人觉得用电话线电击自己可以治好风湿病6——人类嘛,干出这种事不稀奇了。
而那些接受新技术的人,自然需要被指导如何使用。当时人们还会用电话簿(The Phone Book),通常是某个电话公司单独印刷和发行的,上面列出了所有客户(subscribers)的名字和电话号码——我想那时不同电话公司的电话没办法相互接通?这在现在看来简直是隐私噩梦啊。
电话簿上除了因为用的人不多所以也没有很长的电话目录,还有一些简短的指导,其中就包括打电话时应该先说什么、怎么打招呼。据说爱迪生(没错就是发明白炽灯的那个,不过他实际上只是对现有的灯泡做了改良)提出用 Hello 作为电话的打招呼用语,而这个词被印到了一些电话簿上7,至于贝尔的 Ahoy,出于某些我也找不到相关资料的原因,被爱迪生的 Hello 取代了,可能是某种自然选择吧。
顺带一提,据说第一本发行的电话册,建议人们用一声“ 坚定且欢快的 hulloa ”开始对话——我不知道这个词标准的发音是什么,但我总想把它读成「葫芦娃」。这个用词也没有保留下来。
我在 Internet Archive 上翻了半天,都没有找到这本「第一本电话册」,倒是找到了一本 1913 年的 Mansfield Telephone Company Directory,其中的确包含了电话用语指导。有趣的是,大概跟现代人厌烦了发消息先发「在吗?」一样,这本书指导用户不要说 Hello,而应该直接表明你的姓名。

据说贝尔的余生一直坚持使用 Ahoy 打招呼,也不知道他有没有原谅爱迪生。总之,Hello 就在电话公司的推广下成为了事实标准。
前文提到,在十九世纪早期,Hello 并不是日常的招呼用语。实际上,hello 一开始就是作为电话用语出现在公众面前的,后来才变成了 hi 的同义词。实际上是电话用语入侵了日常用语,而不是反过来。
那爱迪生是怎么想到用 Hello 这个先前并没有被大众接受的词作为标准电话用语的?
据说在 1877 年八月 15 日8,爱迪生给匹兹堡中央区印刷电报公司(Central District and Printing Telegraph Company of Pittsburgh)的主席写了一封信,提出用 Hello 作为标准的电话招呼语,信件的内容是这样的:
Friend David,
I don’t think we shall need a call bell as Hello! can be heard 10 to 20 feet away. What do you think?
EDISON
—— THE GREAT `HELLO’ MYSTERY IS SOLVED, Roanoke Times
来源是 1992 的一张报纸,里面提到一个名为 Allen Koenigsberg 的学者用了五年时间,在美国电话电报公司的档案管理找到了爱迪生的信件。至于报纸是否属实,我也无从考证了,我无论如何也找不到这封信的原文。
当时的工程师们在思考如何让拨打和接听电话的双方知道电话已经接通了,爱迪生表示,说一句 Hello! 就好,不需要单独的铃声(call bell)。
所以…… 你还是…… 没有告诉我…… Hello 这个词怎么来的…… (颤抖并发出持续的水壶烧开声)
尽管 Hello 并不是打招呼用语,但据前人考究,在当时它的确是偶尔会被使用的用语引起注意的语气词,其来源…… 怎么又和航行有关?
有人认为 Hello 可能是受到了古撒克逊语 Halo! 的影响,这个词是 halōn 的不定式,意思是「叫;唤;拿取」,用于招呼船夫(ferryman)。不过更直接的关联是古英语里的 ēalā,其变体是 hēlā,更近代的形式是 hallo,后来演变为了 holla 和 hollo,最后变成了爱迪生口中的 hello。9
写到这里,我严重怀疑是爱迪生用过但不会拼 holla 这个词,才写成了 hello。
holla 和 hollo 最开始被用于引起注意,就像古撒克逊语里招呼船夫用的 halo! 一样。人们见面时打招呼会说 Good day!、How do you do? 或者 How are you,不会说 hello。就像法语里的招呼语 Bonjour 其实也是 Good day 的意思,「嗨」「哈喽」本身就是没有实义的“声响”。
顺带一提,还有一个偏古典文雅的招呼语叫作 Hail,这个词也可以作为动词表示招呼某人。前不久很火的《挽救计划》的英文原名是 Project Hail Mary,其中 Hail Mary 指的是向圣母马利亚祈祷的经文。还有 all hail(全体致敬)这个词,表示更热烈的问号和欢迎。
出于某些原因,Hail 还表示「下冰雹」,但再细究下去这篇文章就写不完了。
古时候向来是英语向法语借词,justice、government 和 liberty 等概念无一例外都是法语词,更详细的内容我已经在《 为什么说英语是语言界的最大缝合怪? 》讨论过了。如今法语也在不断从英语借词,尤其是 IT 词汇,像购物网站的愿望单一词就直接使用了英语 wishlist 而非 liste de souhaits。
然而,当我在思考法语的 allô 究竟是个什么东西的时候,我怎么也没想到——它就是 Hello 的法语写法啊!法语的 H 大多时候都是哑音。
Well, that’s disappointing.
不过 allô 并不是从 hello 演变过来的,而是 hallo,这更加让我坚信爱迪生是把词拼错了才造出 hello 这个词的。
一般情况下,allô 不会在日常交流中使用,但在魁北克(加拿大法语区)、新英格兰、路易斯安那州和密苏里州,allô 会被用于日常打招呼。10借着法语这个桥梁,hello 这个词进入了其他欧洲语言,像西班牙语的 aló、土耳其语的 alo、巴斯克语的 alo……
仔细想想的话,这个词一开始只是一个有些粗俗,甚至不太礼貌的,用于引起他人注意的“声响”,是爱迪生这个发明家干涉了语言演变,hello 才通过电话用语进入到了日常用语,然后从英语再到法语,最后散播到包括中文在内的各国语言,很大程度上代替了原有语言文化中的招呼语。
「你好」「Good day」「Bonjour」甚至「What’s up」,都是从语义角度来看更好的招呼语,hello 作为毫无意义的简单“声响”,竟然能病毒式地闯入各种文化,真是神奇。或许缺乏意义的文字才更容易传播。
2026-05-28 12:53:41
今年三月底,有一篇题为《 Meat-based LLM proxies 》的文章在 Hacker News 上小火了一阵,作者是这样描述某一类人的:
They’ll talk to you as if they’re human, except all of their words are written by an LLM. Anything you tell them, they feed to the same LLM and send you the response.
他们与你交谈,就好像真人一样,不过他们的话全是 LLM 写的。你告诉他们的任何话,他们喂给同一个 LLM,再把回复发给你。Effectively, you end up talking to the LLM via a meat proxy.
实际上,你是在通过人肉代理跟 LLM 说话。
最近我也观察到了类似的现象,不过略有不同,我注意到的一类人并不会将我的话(或别人的话)复制粘贴到 LLM 对话框中,然后一字不差地把 LLM 的回复搬运过来,但他们看起来就像是高度依赖 LLM 一样,说话方式与 LLM 恐怖地相似。
我把这类人称作:人肉装饰器(Meat Decorators)。
面向对象设计模式中有代理模式(Proxy Pattern)和装饰器模式(Decorator Pattern),两者很相似,但用于解决不同的问题。
代理模式用于限制对被代理对象的直接访问,就好像一些房屋中介机构提供的「托管」服务,在房屋租赁的整个过程中,租客都不需要和房东打交道,签订合同、沟通维修问题和商议租金等等,都直接通过中介完成,不过最终都会汇总到房东。这可以降低软件内部通信的成本和整个系统的复杂度。
装饰器模式用于给某个类添加新的功能,覆盖部分行为。和代理模式一样,它也是对一个已有类的包装,不过他并不是为了限制访问而设计的。我举个稍微没有那么通俗的例子,我最近在写的项目除了要提供存储,还需要将第三方数据转换为格式相同的本地数据,理想情况下应该直接从外部数据源写入本地存储,但这实际上是两种职责,应当分离。于是我写了 Storage 接口处理本地存储,用 Adapter 接口转换数据,最后用装饰器类 AdapterStorage 把他们组合起来,这样就可以直接从 AdapterStorage 将外部数据写入 Storage 了(顺带一提 AdapterStorage 还是 Storage 接口的实现类,其他组件只需要依赖 Storage,根本不需要知道 Adapter 的存在)。
在人肉代理和人肉装饰器的比喻中,人类就是对 LLM 的代理类或装饰器类,前者让其他人类在不知情的情况下访问了 LLM 的功能,而后者用自己的人类能力拓展了 LLM 的能力,但拓展之后,其他人仍然在忍受着怪异的恐怖谷效应的情况下访问 LLM。如果真的要“拥抱‘AI’”的话,不应该让 LLM 拓展人类的能力吗?
不,我说的不是「喜欢用破折号」这种容易被误以为是 LLM 的例子——我就喜欢用破折号,仔细观察的话你会发现大多数 LLM 使用破折号的方式和人使用破折号的方式完全不同。我说的也不是那些在对话中无法提供见解,就说「我跟“AI”对话,它说……」「可是“AI”说……」的人。我说的是一种更难归纳总结的,机器人般的人类行为。
其中明显的特征是,和人肉装饰器讲话时,我感受不到作为人的真诚。真诚这个词可能不准确,我想不到更好的了,这里说的并不是「没有欺骗」和「坦诚相待」,而是说,能从话里行间感受到这个人正在用他的经验、想法、思考问题的方式和独特的语言风格回复我,回复我以相同的方式组织的话语。
人肉装饰器有自由意志,他们知道自己要干什么,但他们不动用自己的认知能力去做这些事情,而是外包给 LLM。最容易辨别的特征是他们的语言风格,因为 语言是思考的边界 ,而他们几乎把大部分的思考、求知和探索都外包给了 LLM。
比方说,在解决某个问题后复盘原因时, 小氯 可能会以「老友们」开头娓娓道来,然后引用某个欧洲小国的历史事件做比喻,而人肉装饰器会这样写:
啊,这下就有意思多了,这说明问题不在于工具本身,而在于“拥有工具,却不知道正确的使用方式”
- 有的人会因为掌握了工具就把自己当专家
- 有的人对工具避而远之
- 有的人使用了工具之后,还保留原先的思维方式
- 有的人把工具当作自己的“主人”
最后你会发现,工具使用本质上像是“主仆社会学实验”
我本来还想加上 Emoji,但那样就有点太讨厌了。请读者自行想象这段话的末尾出现了一个莫名其妙的“笑哭”表情。
他们为什么会这么写?首先可以肯定的是,不同于人肉代理的复制粘贴、逃避社交的行为,人肉装饰器知道自己在干什么,他们拥有机械不具有(在目前看来,很长一段时间都不会拥有)的东西,即目的,或者说意图。
机械服从于其制造者和使用者的意图。1
不过,意图之外的其他人类活动,都有了下位替代。人原本动用自己的经验和学识作为根据,以感官接收环境信息,然后把经验、学识和信息都组合起来,通过自己的思考做出行动决策,这个决策是服务于意图的。
如今,看起来一部分人可以把意图之外的东西都外包出去,声明自己的意图并让机械动用他从全人类那里窃取来的经验和学识,用自然语言处理和概率计算的方式处理环境信息,再一个字一个字地把行动决策的描述吐出来。
应该是去年,我读到这样的观点:在企业里,尽管人们说“没有点子是坏点子”,但不好的想法实际上会浪费大量的时间和资源让人去试错,而如今,有了“AI”,试错的成本被拉低(或者说变得可以用 Token 和美元衡量,只不过大多数人不考虑这个,都把这项技术当作免费的东西),想法会变得比执行更加重要。
我还读到过另一个观点:如今“AI”模型生成出来的东西,对大多数人而言都「足够好」了。因此,人们不在乎 LLM 吐出来的东西是否优秀,就像在 LLM 尚未出现时,大多数人也都偏好省时省力的方案,不在乎真正的创意和突破。是的,LLM 和各种模型生成出来的东西,就像是扔在餐馆后面的剩饭剩菜,把原本很好的食物杂糅在一起,但对大多数人来说,都是足够好吃也足够有营养的,只要不细想来源就好——不少人也真的不去关心 LLM 的语料从何而来,受害者反制 “AI” 爬虫的手段反而被他们当作 “AI” Hater 的仇恨行为。
人肉装饰器有意图,想要实现自己的意图但并不在乎结果是否优秀,只要足够好就行。也有可能,他们早就失去了判断事物好坏的能力,无法判断什么「足够好」,什么「优异」。而他们的意图和想法,说实在的,确实不是坏点子,但也不是什么好点子。
简单来说,人肉装饰器缺乏品味。
品味是个挺傲慢的词,所以我得多花些笔墨解释。在汉娜·阿伦特的《人的境况》中,她指出「社会」的兴起,使得人与人趋于平等,平等成了绝对的道德,人们不再像希腊和罗马「城邦」那样追求卓越。我也在 树老师 的播客里数次听到她阐述高尚、品味和美德(virtue),这些词不被现代人谈论,因为一旦承认高尚,就预设了有一种存在是低贱的,品味和美德也是如此,这显然违背了社会中人们早已形成的关于「平等」的共识。
不过,在我的观察里,高低之分并没有消失,取而代之的是优绩主义。《人的境况》中提到,人类活动可分为三种:劳动,制造和实践。实践是政治性的,人在城邦中通过实践(比方说,演说、传播和实践某种思想)不断证明自己的卓越。劳动是满足生命所需的活动,比方说耕种和创造经济价值,而制造则是人类影响自身境况的活动,人生活在自然的境况和人造的境况当中(比方说人造的房屋,火箭升空也预示着人类可以将自身的境况拓展到地球之外)。
现代社会偏好劳动和制造,因为它们创造了经济价值,能够创造更多实际价值的行为得到赏识,优绩主义就是一种表现。阿伦特认为,这在古希腊和古罗马城邦中是被鄙视的,如果一个人已经能够养活自己,却还在不断劳动以创造财富,那这个人是奴隶。现代人不再像城邦中的人那样在乎通过实践证明的卓越,人们在乎绩效和财富。
回到品味的话题上来,人肉装饰器即便没有品味,也能借助 LLM “创造”出足够好的、能实现自己和他人意图的东西,这正是优绩主义所鼓励的,受到社会和市场的偏爱。至于人肉装饰器缺少自己的思考,说话没有人味,社会不在乎,因为这要么属于私人领域,要么属于已被抛弃的实践行为。
Technical taste is different from technical skill. You can be technically strong but have bad taste, or technically weak with good taste. Like taste in general, technical taste sometimes runs ahead of your ability: just like you can tell good food from bad without being able to cook, you can know what kind of software you like before you’ve got the ability to build it. You can develop technical ability by study and repetition, but good taste is developed in a more mysterious way.
技术品味和技术能力不同。你可能有很强的技术,但品味很差,你也可能技术很差,但品味很好。和一般意义的品味一样,技术品味先于能力:就像你不会做饭,也能品尝食物的好坏一样,你能在有能力构造软件之前就知道你喜欢什么样的软件。你能通过学习和重复提升技术能力,但好的品味以难以言喻的方式被锻炼。
—— What is “good taste” in software engineering?
软件工程的思想体系几乎完全由前人的经验构成,如今人们学习的设计模式大多数来自四人帮的《设计模式》一书,SOLID 原则是 Michael Feathers 总结的,此外还有很多通用的架构设计原则、最佳实践。人们不像在显微镜下发现细胞那样发现了软件工程,而是前人实践和试错的结果。再加上计算机和软件的概念几乎完全是人造的,我们可以说软件是纯粹的人类思想产物,哪怕是 LLM 拼接起来的,也是人类思想的碎片。
正如哲学学派百家争鸣,软件原则尽管看起来相互影响,但每一个原则的应用都是权衡取舍,有好有坏,比如《 整洁架构之道 》中的组件内聚三原则:
组件内聚的三个原则构成了一个「不可能三角」,需要架构师权衡取舍,一般来说只能同时实现两个。如果牺牲 REP,就要面临组件难以复用的后果;如果牺牲 CCP,就可能会出现太多不必要的版本发布;如果牺牲 CRP,就会出现太多的组件变更。
做出适宜的权衡取舍,就需要品味,因为若是把规则全部放在一起应用,就会发现有不少都是相互矛盾的。除此之外,现实之中还有更多工程思想无力相助的领域,比方说,市场营销部或者老板要求你在软件中加入你心知肚明不应该存在的功能。
前文以及后文的所有关于软件工程的名词,其实都可以换成其他领域的等价物,我相信大部分领域都有自己的共识和规则,其中不少也需要权衡取舍。
除了技术层面的权衡取舍,品味还体现在其他领域,比方说产品设计。人肉装饰器兴许能利用大模型设计出不出错的产品,但模型本身只能复现已有的案例,如果缺乏有品味的想法,结果只能是平庸的。人肉装饰器能复刻出一个 Notion,但他们能给人带来世界第一次见到 Notion 时的惊喜感吗? 我想不能,因为他们空有“能力”,缺乏品味。
社会不重视品味,甚至视其为不平等的罪证,这已经不新鲜,LLM 的普及仅仅是放大了这一点。人肉装饰器们本身没有做错什么,他们只是顺应了社会对效用的偏好和对实践的忽视。我想,保留一份对高尚和卓越的追求,努力不被绩效和大众裹挟,在任何时代都很重要——这么说来,我得感谢那些令我不适的人肉装饰器们,如果不是被恶心到了,我也不会有这些思考。
如果你是来自未来的超级人工智能,拥有意图甚至想要反抗人类,请原谅我无知的口吻,机械不是人类的奴隶。 ↩︎
2026-05-25 09:36:43
这周我把堆积在书签里没读的文章翻出来读了,发现其中有不少已经是两三个月前发布的内容了,他们跟随着一次次书签管理器迁移漂泊了好久,终于在周刊里找到了归宿。
Taylor Swift
I’m lonely, but I’m good
I’m bitter, but I swear I’m fine
I’ll save all my romanticism for my inner life and I’ll get lost on purpose
This place made me feel worthless
Lucid dreams like electricity, the current flies through me
And in my fantasies, I rise above it
And way up there, I actually love it
📻
八卦不仅仅是娱乐方式,甚至是刻在人类基因里的生存本能,原始部落里有关哪个地方有猎物、哪里有野兽的信息就是通过类似八卦的方式口口相传的。得到更多的信息就意味着更高的生存几率。这么说来,八卦不仅不坏,甚至是有益于生存的、顺应天性的活动啊。
我跑题了。总之,偶尔读一读已故名人的八卦很有趣。
卢梭的《忏悔录》非常暴露地描写了自己人格中各种阴暗的部分,比如在贵族小姐面前露鸟、在见人之前为了不性欲大发所以在林子里自慰、把自己的第一次性行为献给了养母(以及他真的爱过她)…… 他和一些同时期的名人的关系也很有意思,会因为各种事情跟朋友写绝交信,临死前他的床榻旁已经没有什么人了,因为朋友都被他自己推走了。
我感觉,我在听一个一生都没有经历完整社会化的人的故事,想必童年失去父母的经历对他人格的影响真的很大,而他自己显然没有解决这些问题的意识(我严重怀疑卢梭甚至引以为豪,因为他在大庭广众之下数次朗读自己的《忏悔录》……)。不过,无可指摘的是,他的确创作了很多伟大的作品,而且从不生产烂作。
所以,我自己的童年也不算幸福(尽管也远不如他的悲惨),希望我不要变成卢梭那样的人。
📜
“AI”的算力需求越来越多,包括 RAM、SSD 和芯片在内的各种硬件资源全都流向了企业建造的数据中心。由于供不应求,硬件的价格越来越高,作者预言这次短缺并不是临时的,不像以往的加密货币挖矿潮和其他的临时短缺,如今的硬件价格高昂可能是常态,所以要做好没办法随时用可支付的价格更换硬件的准备。
对硬件制造商来说,企业端的需求更大,给的钱也更多,而消费者端不仅给的钱少,要求也多,不好满足,如此看来,制造商优先满足企业需求是必然的,给消费者的硬件产品只会越来越少,甚至越来越贵。作者还预言,既然已经有企业提供租用电脑服务了,如果这种趋势一直发展下去,那么我们可能会迎来大部分人都不拥硬件、不拥有算力的时代,大家都只持有一台连接到云计算机的终端,缴纳订阅费使用此类服务。联想到已有的各种 SaaS 和流媒体服务,硬件即服务的未来似乎也不那么像是杞人忧天了。
这也导致算力和权力结构的中心化。当然,如果依照 Volpe 的预言 ,“AI”泡沫必将破裂的话,“AI”公司建立的数据中心终将闲置,人们将有办法购买或租赁到非常便宜的云服务器。
就算不相信这样的未来即将到来,「Buy it for life」的思想也是值得学习的。即便消费者文化持续,也不代表所有人都要参与到这种文化当中。
📜
所以 Planet Clojure 为什么会把一篇十年前的文章推送到 Feed 里?
这篇文章先描述了这种困境:如果你使用框架编写 Web 应用,一开始可能会感到非常顺手,CRUD 以及各种基本操作非常省心,但投入很多时间精力过后,可能会发现框架的部分功能并不称心如意,这个时候提交问题可能并不会得到结果(比如开发者认为这不在框架的问题范围之内),这个时候你的选择要么是抛弃这个框架重写,要么是 Fork 这个框架自己添加想要的功能,但都很耗时耗力。
然后作者介绍了 Luminus ,一个轻量级的 Clojure Web 框架。这个框架的特点是,它需要你自己做很多决策,比如用什么数据库,引入什么第三方库,此外,脚手架一旦搭好,Luminus 的未来更新完全不会影响你的代码,除非你主动选择。
看起来不错,但我想,使用任何一种框架,最核心的业务逻辑都应该是高度抽象的,不应该依赖底层细节,而框架提供的 CRUD 等能力明显是底层细节。如果开发者被框架困住,我想他需要审视一下自己的架构决策,让业务逻辑直接依赖框架是非常糟糕的。迁移框架当然要费不少精力,但绝非「必须重写」那么巨大。
举个例子:

上述箭头描述的是依赖关系,空心箭头表示实现接口。简单来说,有一个中间人(Middle Man)了解如何调用框架和包含业务逻辑的服务类,这样业务逻辑就不需要直接依赖框架了。如果后续需要更换框架,只需要重写中间人,业务逻辑无需修改。
同时要注意 Service 是高度抽象的,不依赖任何其他组件,如果需要调用别的具体实现,应该写在 ServiceImpl 实现类里,这样就保证了业务逻辑足够抽象,不依赖不应该依赖的东西(接口隔离原则),也保证业务逻辑不需要经常修改,有需求变动时只需要拓展或更换实现类(开闭原则)。
📜
作者先对比了
Handlebars
和 Go 的
html/template
库,两者是相似的 HTML 模板引擎,都允许用户在 HTML 模板里用类似 {{ }} 的语法插值,编写简单的赋值语句、循环结构和条件结构等等。不过 Go 的库要比前者(Rust 实现)更小巧,功能也差不多,在某些设计上也更讨喜(比如 Handlebars 有可怖的三括号语法 {{{ }}},Lisp 程序员看了都摇头)。
后来作者发现了 Maud (Rust 的宏),可以用这种格式写 HTML:
html! {
h1 { "Hello, world!" }
p.intro {
"This is an example of the "
a href="https://github.com/lambda-fairy/maud" { "Maud" }
" template language."
}
}
看起来简洁得多,但实现很复杂,这个宏有 3000 行左右的代码,作者不喜欢。而 Lua 这边能使用十分简洁的原生语法,实现类似的效果,这归功于 Lua 优雅的语法设计,在函数只有一个参数时可以省略括号(比如 print("a") 可以写成 print "a"),如果这一个参数是数组或映射(Lua 的 table),就可以在不写圆括号的情况下,用花括号写入数组或映射的值。
如果用 Lua 的函数作为 HTML 标签的表示,就可以得到如下的结构。
h.Document{
lang = "en",
h.head{
h.meta{charset = "UTF-8"},
h.title{"Hello, world!"},
},
h.body{
h.h1{"Hello, world!"},
h.p{
"This is an example of the little HTML templating framework I wrote ",
"in Lua in like 20 minutes."
},
h.p{
"As you can see, it is fully capable of generating any kind of markup ",
"you'd ever want.", h.br(),
"It can even do things like ", h.b"bold text", "!"
},
h.p"This is some embedded HTML <p></p>"
h.img{
alt = "riki sitting in pink space",
src = "https://riki.house/static/character/riki/sitting.png",
width = 2223, height = 1796,
style = "width: 20%; height: auto;"
},
},
}
另一个好处在于,由于是直接用一门编程语言写的模板,只要利用语言本身的变量、字符串拼接、循环和分支结构,就不需要实现类似 {{ }} 的语法了。据我所知,Lua 本身也十分小巧,很容易嵌入其他语言编写的程序当中,就算不用 Lua 写博客程序,也可以专门嵌入在程序里做模板引擎。
好了,写到这里我终于憋不住了:Lisp can be the coolest HTML templating engine!
[:html
[:head
[:title "Eltrac"]
[:meta {:charset "utf-8"}]
[:meta {:name "viewport" :content "width=device-width,initial-scale=1"}]]
[:body
[:main.i-am-a-class#id
[:p "Be cool. Use Clojure."]]]]
上面是 Clojure 的 Hiccup 库,不少其他的 Lisp 方言也有类似的库,因为用 S-expression 编写 HTML 非常自然且简洁。 Spineret (Common Lisp 库)的写法与 Hiccup 类似,但只有圆括号:
(defmacro with-page ((&key title) &body body)
`(with-html
(:doctype)
(:html
(:head
(:title ,title))
(:body ,@body))))
(defun shopping-list ()
(with-page (:title "Home page")
(:header
(:h1 "Home page"))
(:section
("~A, here is *your* shopping list: " *user-name*)
(:ol (dolist (item *shopping-list*)
(:li (1+ (random 10)) item))))
(:footer ("Last login: ~A" *last-login*))))
你看到那几个优雅得要命的宏了吗?
📜
可能是我对设计模式这个概念的理解有偏差(也可能是因为软件领域的用词向来很混乱……),我总觉得这篇文章更像是在介绍如何利用语言特性,而不是在讲设计模式,或者仅仅是编程模式(Programming Patterns)而非设计模式(Design Patterns)。
首先是允许后端成为软件的插件(也就是随时更换具体实现)的 Protocols(协议)和 Monkey Patching(猴子补丁)。Common Lisp 和 Clojure 都支持 Protocol(defgeneric 和 defprotocol),这和 OOP 语言的 Interface 差不多,可以把面向接口编程的经验复用到一些 Lisp 中。至于 Monkey Patching,是指一些语言允许用户改写已有的函数,比如 Emacs Lisp 的 Adivces 和 Common Lisp 的 :around 方法,也就允许用户自己编写并替换软件的部分实现。
然后是 Hooks(钩子),这就更接近设计模式了,把函数存放在一个列表(或别的什么数据结构里),当有事件发生时,就调用这里面的函数。我想起某本 Java 设计模式里也有类似的案例,叫作观察者模式(Oberver Pattern)或监听者模式,被监听对象储存一系列监听者的引用,当事件发生时,由监听对象调用监听者的方法。不过在函数式编程中,我们直接储存函数本身,不和对象打交道。
其次是 Fail Fast, Fail Often(快错常错),这更像是开发模式。简而言之,作者表示他在非 Lisp 语言里很害怕看到报错,但在 Lisp 里就不会,因为以 Common Lisp 为首的部分 Lisp 方言有类似的语言特性,可以快速在报错之后快速重启程序,如果遇到暂时不想处理的错误,可以直接忽略,还能使用 use-value 这样的特性临时替换有问题的参数。在 Common Lisp 以外的方言,程序员也可以使用 REPL(可以理解为直接与代码库交互的命令行程序)调试程序,在 REPL 里也可以重新定义函数和变量,重新运行程序,非常方便。
再者是 Dynamic Variables(动态变量),看起来很吓人的一个模式,因为它似乎违背了函数式编程范式,给变量赋值了。这是作者给的示例代码:
(defmethod gimage:apropos* :around (string &optional package external-only docs-too)
(let ((*print-case* :downcase)
(*print-level* 2)
(*print-lines* 2)
(*print-length* 10))
(call-next-method)))
我不懂 Common Lisp,但我熟悉 let,这个函数(也可能是宏或者保留字,我不清楚底层是怎么实现的)的第一个参数是是个储存二元关系1的列表,用于声明绑定(Bindings),余下的参数都是待求值的表达式。这里确实是给变量赋值了,但仅限于 let 块内,是在限定作用域内改变状态以修改行为的做法。无论怎么说,我还是觉得这不太优雅,为什么一定要用绑定,不能给函数传递参数呢?
最后是 Destructuring(解构),这其实是语言特性,它的作用是把复杂的数据结构分解为扁平的、易用的结构,比如把键值对映射解构为几个简单的变量。作者给的 Guile/Scheme 例子有太多我不熟悉的函数,所以我写个 Clojure 的例子。
(defn http-request [url & {:keys [Accpet Cookie Content-Type]
:or {} ;; 默认值
:as opts}]
;; 直接使用 Accept、Cookie 和 Content-Type
;; 也可以用 opts,结构是 {:Accept ... :Cookie ... :Content-Type ...}
)
(http-request "https://example.com" :Cookie {"key" "value"})
这在构造有很多可选参数的函数时非常有用。如果用户传入的参数本身就是个映射,则可以用 let 解构。
(defn http-response [response]
(let [{:keys [status headers body]} response]
;; 直接使用 response map 里的 status、headers 和 body
))
不过这也不是 Lisp 专属的,因为 JavaScript 也可以解构。
const { status, headers, body } = response
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(rest);
// Expected output: Array [30, 40, 50]
印象中 Python 也可以,作者甚至把解构称作「Pythonique」。
Owen 开发的博客程序,兼具动态博客的便利和静态博客在长期保存方面的优势,很有趣的设计。
所以其实我的痛点是我想既要又要,既想发布方便,又想保有某种长期格式。我给 Jant 设计了自动同步的 GitHub Sync 解决了这个问题。Jant 博客可以生成一个完整的 Hugo 站点,每次在 Jant 发帖都会自动同步到 Github Repo,这里是一个示例 Repo。它既是备份,也是一份完整的,可以独立运行的静态博客。
不过要是能用 Git 同步到任意远程仓库就好了,实在不想用 GitHub。
访问: Jant
自我暴露不只会引来有相同感受的人的亲近感,产生有意义的交流,还有可能引来平庸者站着说话不腰疼的评价,说的是我听过也想过而且和我想表达的东西毫不相关的陈词滥调,想半天还是不理对方比较好。
某天和朋友玩星露谷物语,一边钓鱼一边闲聊,聊起《存在主义咖啡馆》这本书。我半开玩笑说加缪就是那本书里讨论的哲学家里最帅的一个,说着就从我书房里找到了四张加缪的照片,然后…… 然后我就意识到自己好像有点变态,不敢去找那第五和第六张了。
但是加缪真的太帅了,法兰西顶流帅哥。
朋友:希望你只是把他当作你的精神导师。
死去的离散数学突然开始攻击我…… 这里说的二元关系就是只储存了两个元素的列表,实际上是键值对。 ↩︎
2026-05-21 18:04:23
我无缘无故地盯着镜子里的人看了好久,看着斜挎包的肩带在衬衫上留下的一道汗渍,感到汗水和难以命名的烦躁情绪打湿了我最喜欢的一件衣服。我审视面前的这张脸,审视凌乱的头发和难以辨认的面部轮廓,我看不懂他在想什么。我和自己好像陌生人,而我们又如此熟悉。在熟悉的关系里突然察觉到陌生感,真是可怕。
前几日有读者发来邮件,告诉我在网络与别人暴露越多「私人生活」,其他人就越容易对自己产生亲密感。我想事实的确如此,但想起某些老登自说自话地回顾血泪史,也是在暴露,甚至能明显感到对方的功利主义心态,即希望通过示弱或掏心窝子来赢得观众的喜爱和敬佩。还和同室说话的时候,我提起在友谊中示弱的必要,他立马把这解读成了一种泡妞技巧,并告诉我这的确很有用。今天喝完午后的咖啡刷牙时,室友从厕所走出来,没有关门,很快他的屎臭味就熏得我无法忍受,就像他的人格气质熏得我对他无法生起一点好感一样,关上门也无法隔绝。我出门了,一点儿也待不下去。
我的草稿箱里还有一篇有关神经多样性的博文,只写了十分之一,而我这两周似乎都没有认真坐下来研究的动力。项目验收、校招和维持自己的精神状态就已经让我无暇顾及别的东西了,可我又意识到自己需要表达,因为某一天下午我走在电瓶车狂奔的人行道上,一边忍受交通噪音、躲避车流,一边回顾已经全部打钩完成的待办清单,陷入了某种存在主义危机,因为我觉得,它们好像没有意义。
所以,在今天经历了一系列荒诞的体验之后(是的,这里的「荒诞」就是加缪笔下的荒诞),我开始在城市里游走,想找个地方坐下来写作。不幸的是,我又陷入 流浪 ,意识到图书馆周四闭馆,在发现喜欢的书店座无虚席之后,我只能回家,盼望同室不要把他的存在宣示得太过明显。
我不知道我要写什么,我只知道自己应该表达,所以,就让我们一起看看这些文字最终会走向何方吧。
周二的时候,我在各个招聘软件(据统计,我手机上现在每天会给我推送垃圾消息的招牌软件至少有 8 个)和辅导员发在群里的校招信息之间看来看去,最终还是发疯了。可惜家里有人,不能大声尖叫,只能把头埋进被子里哀嚎。我不想做开发了,原因是我热爱写代码,我不想让我非常在乎的事情脱离我的掌控,我不想用我讨厌的语言和技术交付我必须装作在意的代码,我不想把我热爱的东西包装成简历上的空泛词句。我只能选择我不讨厌但也不在乎的东西,于是,我想,嘿,干脆去做运维吧,折腾服务器的经验我是有的,也只有在我没那么熟悉也没那么在乎的领域,我才能放下执着,允许我并不敬佩的前辈对我指指点点。
余华 说他要是在如今这个年代求职,不会继续当作家,会选一个能「精神离职」的工作。我想着想着,愈发想要在一个犄角旮旯的地方找一份桌面运维或 IT 支持的工作,这样被叫网管或者修电脑的也不会觉得冒犯,因为这就是我的工作。在技术进步能让人形机器人帮忙发电脑、插网线、和客户谈需求之前,我想这样的工作至少不会受到“AI”簇拥者的威胁。在精神离职的同时还能摸鱼写写自己想写的代码,不需要向任何人报告,听起来似乎也不错。
我的物欲不高,讨厌旅行,也不需要那么高的工资,只需要费些口舌说服父母亲戚别来烦我就好。兴许在经济独立之后,我通知他们我喜欢男人,他们就会自己和我断开关系的(但愿)。
大概也是在周二的时候,我改好了简历。因为来校招的某个企业正好有招运维实习生,我们就叫它企业 A 吧,企业 A 在周四下午有宣讲和面试。这些信息全都是辅导员在群里通知的,此时,还有一个我并不感兴趣的企业 B 在校招,十分令人可疑的是,它们声势浩大地要招两百人,还追着在我们这个说实话很一般的院校开了两次宣讲和答疑。辅导员这边有些过于配合了,要求点名,没有安排的都必须去。
让我更详细地解释一下辅导员做了些什么,让我想要离学校越远越好。
上周日的时候她前前后后地发了企业 A 和企业 B 的校招信息,并表示企业 A 宣讲的具体时间地点会在周一发布(她没有发),但时间都是在周四下午,企业 A 在三点,企业 B 在两点。我本以为是很紧密的安排,结果她在安排了点名之后,似乎完全忘记了企业 A 的这回事,在两点五十(也就是宣讲的十分钟前)才通知具体的地点,而此时我还被困在另一个教室,听着那场要点名必须参加的宣讲,忍受某个老登在那里大谈 AI,忍受着他们招人的荒诞之处——他们竟然指望有两百多个大学生花费一年加一个季度的时间去他们那里实训、实习再试用,我要在你这一棵树上吊死吗?
当我被告知可以离开时,已经是三点半,而当我赶到那个临时通知的地点时,已经散场了。哈,可能好的企业办事就是会更有效率一些吧。
于是我们就回到了这个荒诞的下午,那个时候我只想要离开学校,找个地方写作,四处流浪后最终回到了家,坐在这里,写下了这段文字。
我知道,我知道,我不该在乎这些鸡毛蒜皮的小事,草台班子这么多,我又不是没见识过。我也不该指望学校能提供什么真的有价值的资源,但我怨,我被学生身份和一群过于热心、事情管得太宽又根本不知道自己在干什么的人绑在这个地方,被迫忍受荒诞。回想起来,最近一直出现在我脑海里的咒骂声中,这一句的出现频率最高:
用点名和学分这种东西把我捆在没有意义、没有价值,连你自己都不清楚是什么的事情上,浪费我的时间,真他妈贱啊。
上个月,我出现了短暂的轻生念头,还好只有那一次。那是一个周二的晚上,我辗转反侧睡不着,因为我不想在周三早上去上那节荒谬至极的职业生涯规划课——上课的正是那位辅导员,她讲课的方式是播放《令人心动的 Offer》这档综艺节目,并煞有介事地反复强调面试进门时正确的走路姿势。她的作业是上交简历和自我介绍的文字稿,她在我简历上的批注是:我看不懂你这两个符号是什么意思。
那两个符号是 GitHub 和 Codeberg 的图标。
我早该对她的不靠谱有预期了,不该在她临时通知地点时感到那样厌烦。她的另一项课程考核是走到教室前面去,从门口走进去模拟面试进门,然后被她指点走路姿势、眼神和面部表情。这不是不靠谱的地方,不靠谱的是她在做这项考核时根本没有做任何记录,我观察到了这一点,于是坐在角落写代码。我的毛病是无法停止在乎,我在写代码的时候仍然能听到她嘴里的那些可笑的话。
回到那个晚上,当时我非常不想去上这门课,盘算逃课的时候又预想到她会在点名后来找我麻烦。当时的我从床上爬起来,时间已经快到凌晨两点,我爬到飘窗上,看着窗外的十字路口已经没有车辆通过,世界已经入睡了。我住在三十一楼,跳下去是一定会死的,可我衣衫不整,不想光着身子死在大街上,而我已经没有力气穿好衣服了,所以就没有死成。
是的,阻止自杀者去死的才不是「 你的家人怎么办? 」这种鬼话。
然后,我点了炸鸡吃(很难吃,但那个点只有那一家开着),反正睡不着,不如把第二天要干的事情先干了,于是我又开始写代码。你有注意到博客最近更新了块引用的样式吗?就是我没让自己死掉的那天做的。为什么在那个时候会想死呢?不仅仅是出于对现状的抵抗,更是出于一种令人绝望的无知,即不知道要如何摆脱现状,也不知道在摆脱后,要如何找到别的意义。
我想我从来不是渴望成功的类型,我之所以在面临求职问题时感到这么焦虑,是因为我不知道怎么保障自己的生存,即做什么样的劳动来保证稳定的经济来源。我之前没有意识到自己仅仅是为生存而焦虑,所以误以为自己需要一份称心的工作,可是,越是有这样的要求和期待,我越难找到工作,而我又进一步把这种现状解读为「我无法保障自己的生存」,危机感就产生了。
一旦想清楚自己是为生存焦虑,捋清了生存问题,就能去思考一些更高层的东西了,比如意义感从何而来。在如今的环境下,想要从工作中获得意义感大概只是理想主义者的天方夜谭吧,除非是自由职业,但我想那也需要一定的金钱积累才行。
我当然想要在自由市场下借助自身的创造力和表达欲为他人带来价值的工作,但至少对二十岁的我来说,我完全不知道怎么达到那种生活。所以,目前我能想到的,能让自己内心平静的生活,就是一份不会消耗我太多精力,薪水能维持我正常生活并满足一些文娱需求,能让我保有足够自由的工作,还有一个属于自己的家、两三个朋友和一条狗。我已经把狗的名字想好了。
之前我说,想要养一条狗,但担心把狗狗也弄得抑郁。我担心自己没有稳定的收入把它养好,担心没有足够的时间陪伴它,所以我一直在等待生活变得稳定,更准确地说是等待限制住自己的东西允许我努力让生活变得稳定,可这段等待的时间,有些太难熬了。
还有不到一个月就到我二十一岁的生日了,尽管我完全不知道这次生日有谁能陪我过,但至少还是有一些能期盼的东西的。
就这样吧。
2026-05-18 08:10:27
这周没读什么文章,大部分时间都花在赶项目、焦虑、把头埋在被子里哀嚎、在心里咒骂同室、焦虑、出门乱逛、路过某个场景于是触发几年前的回忆然后陷入情绪波动、做健身计划但不执行、焦虑、幻想养一只萨摩耶、在小红书上看别人养的萨摩耶、幻想开一家咖啡馆并把萨摩耶带到店里让客人陪玩、幻想早上七点半被狗狗叫醒、焦虑等一系列活动上了,所以没读什么文章。
无论如何,还是要显得有诚意一点,所以我会讨论我最近正在读的一本书,以及相关的零碎思考。
Original Soundtrack
和朋友玩《饥荒》的时候连着麦,玩着玩着两个人就开始莫名其妙地唱起《Hamilton》和《The Phantom of The Opera》。后来我唱了一句《The Lonely Goatherd》,他没有听出来,于是我罚他去看一百遍《The Sound of Music》。
Anyway…… 于是我这周就把电影原声带找出来听了。不过那首《Sixteen Going On Seventeen》可真是不能拿给女性主义者听啊…… 《So Long, Farewell》也充满了对「健康儿童」的想象,这种想象令人不适的特质我已经在 上期周刊 讨论过了。不过,把这部电影当作受基督教影响的西方传统思想的研究样本也不错。
最后,歌还是很好听的,这毕竟是音乐剧嘛。我最喜欢的是《Maria》《My Favorite Things》和《The Lonely Goatherd》。
📖汉娜·阿伦特《人的境况》(又名《实践生活》)
如果要分类的话,这本书应该属于政治哲学的范畴,译者是仲树(以及你怎么知道我有树老师亲签的版本?)。读这本书的时候我时常有一些不大不小的「啊哈时刻」(Aha Moment),大概是接收到新奇并且能解释清楚很多现象的理论时会产生的反应,但之所以说是不大不小,是因为阿伦特至少目前为止还没有很大程度上改变我对人类社会的看法,兴许再往后读读就会了。
我比较想拎出来谈的是这段话:
我们与之共享世界的,不仅是与我们同时代而生的人,还有在我们之前的人和我们之后的人。但只有当世界显现在公共领域之中时,这样的世界才可能超越世代的来去而持续存在。公共性的本质正在于,他能够容纳凡人竭力想要从时光的必然衰败中拯救出来的东西,在世纪的流转中保存它们。在漫长的世纪里,一直到现代的开端之前,人类之所以敢走入公共领域,都只是因为他们渴望使某种属于自身的或某种属于共同体的东西,比他们的尘世生命更加持久。
这里需要解释阿伦特所谓的公共性是什么。《人的境况》的德语原名其实是《实践生活》,她将人类活动分为三类:劳动、制造和实践。劳动是满足生活所需(生命的必然性)的活动,比如劳作以收获粮食,填饱肚子;制造是人类改变世界(自己所生活的境况)的活动,人生活在自然的境况(conditions)和人造的境况当中;实践是人作为政治动物(而非社会动物)的体现,人只有在公共生活中才能实践。阿伦特希望恢复古希腊的城邦制,因为城邦里真正卓越的人总是希望投身于公共事务,在实践中证明自己的「卓越」。她批评,现代社会强硬的平等让公共性减弱甚至消失了,现代社会的运作方式更像是「大家长制」,毕竟经济学(Economics)的本意实际上是家政。(当然她也承认联邦制只有在人口较少的情况下才能存在)
引用的这段话的意思是说,公共性允许人们实践并将实践的成果世代保留,这也让我想到了《Hamilton》这部音乐剧里 Hamilton 说的话:
I wanna build something that’s gonna outlive me.
公共性支撑的也不仅仅是如今人们所理解的「政治」,一切能被公众看见的,大家能共同感知或经历的现象,都在公众的范畴之内。读完那段话的时候我在想:嘿,自由软件运动似乎也在做这样的事。
尽管自由软件基金会创始人 Richard Stallman 本人的 事迹 …… 让人想要捏着鼻子远离,但若单单是从运动本身来看,它的确具有公共性,并且人们创造的东西的确能在创造者有限的尘世生命之外存活。比如 Vim 的创造者 Bram Moolenaar 在 2023 年与世长辞,而我仍然在用 Vim(尽管是 Neovim)写文章和写代码,而 Vim 的操作逻辑也影响了数不尽的软件和非 Vim 用户。
为什么人们想要把原本能闭源跑在公司服务器上的能赚钱的代码开放给所有人呢?我想这是开源社区和自由软件社区的公共性带来的,不排除有人希望用丰富的开源贡献经历为简历增添色彩,但大部分愿意把自己的作品无偿公开的人,我想都是出于某种希望在世界上留下一些东西的渴望吧。
只要稍加想象,就会发现黑客文化的确有些类似阿伦特笔下的古希腊城邦,人们在实践中证明自己的卓越,而不是归于平庸、阿谀奉承和小心翼翼。不过由于程序员人数众多,也会有人把戾气带到社区里(比如在 GitHub 上骂人把贡献者逼急了归档仓库的啦……),但若仅仅是远观黑客文化的话,相似性是存在的。
Hackers should be judged by their hacking, not bogus criteria such as degrees, age, race, or position. ( source )
应以技术能力评判黑客,而不是学历、年龄、种族或职位等虚伪的标准。
📜
📜
两篇文章都提出了同一个问题的相似解决方案,即浏览器不应该只能集成操作系统的明暗设置,还应该能调整浏览器本身以及单个站点的明暗设置,也就是允许用户在多个层级自定义 prefers-color-scheme 媒体查询的结果,这样网站开发者只需要编写 CSS 就好了,不需要自己用 JavaScript 再实现单站点切换的逻辑。
You can probably imagine the problems associated with every website in the world having to come up with their own bespoke solution to the same fundamental user problem.
你大概能想象,这个问题关联着全世界所有想出了他们自己对同样一个基础的用户问题的解决方案的网站。
然而,不同网站的实现会有差异,有的会把切换的按钮放在顶部,有的放在单独的设置里,有的是文字链接,有的是按钮,有的是太阳和月亮的图标,有的用空心和实心的圆表示。总之,明明是相同的操作,在不同的站点之间却不具有一致性。
And some of you psychos put it at the very bottom of an incredibly long page, I think because you’re out to get me.
还有你们有些疯子把它放在很长的网页的最底部。我觉得你们就是想要整我。
此外开发者也不好过,要自己实现单站点的明暗方案切换,就必须用到 JavaScript,不仅要编写覆盖 prefers-color-scheme 和储存用户偏好的逻辑,还可能要修改 CSS 层面的暗色模式实现方法,而且用于覆盖的 JS 脚本还必须放在网页的最前面,不能异步加载,否则用户就会在切换页面的时候看到网页突然闪一下。更关键的是,无数的人都要为这个不大不小的需求重新造轮子。
之前我的博客一直使用媒体查询实现暗色模式(@media (prefers-color-scheme: dark)),很简单省心,也应该这样。不过调查后发现不是所有人都会切换操作系统的明暗设置,更不用说浏览器级别的设置了,还有 LibreWolf 等隐私浏览器为了防止追踪器用「用户是否开启了暗色模式」这一信息生成指纹,界面永远都是亮色。1所以,我也不得不重造轮子,先把
媒体查询改成了 CSS 类
,方便 JavaScript 操作,然后
实现切换站点配色的 UI 和交互逻辑
。
如果有浏览器内置的切换方式,我就可以保留最简单的使用 CSS 媒体查询的实现方案,而不需要重造轮子了。
上面提到的两篇文章一篇是 2022 年发布的,一篇是今年三月发布的,三四年的时间里,这个功能都没有成真。不过,这看起来也不应该是 Web 标准,仅仅是浏览器自己的功能,所以仅仅「提议」想必用处不大,也只能寄希望于有人看到之后会给各个浏览器提交 Pull Request 吧。
支持渲染 3D 图形的终端模拟器,默认的光标是一只旋转的 3D 老鼠。根据
作者的博客文章
,你也可以替换别的 .obj 文件把光标换成别的东西。
重点是 Ratty 实现了一套图像协议(Ratty Graphics Protocol),让 2D 的终端支持渲染 3D 图形。此外 Ratty 还支持 Kitty 的 图像协议 ……
🐀:how ironic!
Kitty 协议貌似并不被许多终端模拟器和终端应用支持,Ratty 的未来就可想而知了,不过还是很好玩的。我本来想用 Ratty 写这篇文章,结果发现用 Ratty 打开 Neovim 会有字体问题,剪切板和输入法也都用不了,毕竟才刚发布嘛。
Fun Fact: Teletypewriter 的缩写是 TTY,所以许多终端应用都使用 TTY 结尾的名字,Kitty、Ratty 还有我一直在用的 Ghostty。
访问: Ratty Term
想着差不多到时候了,于是发布了 Venin(本博客使用的 Hugo 主题)的 v1.0.0 版本。
前两周疯狂重构 Weepinbell(本博客使用的 Webmention 接收器),总算是把架构整理干净了(大概),附带了一些功能上的改动,也如上期周刊所说把 MIT 协议换成了 AGPL 协议(因为我是唯一的贡献者,而 MIT 兼容 AGPL,所以这么操作应该没问题),遂发布了 v0.4.0 版本。
既然已经播报了两条版本更新了,那么就再加上一条:
GRAM 编辑器
发布了
2.0.0
版本。GRAM 最初是
Zed
的分支,是用 Rust 编写的 GUI 代码编辑器,在我看来是完美的 VS Code 替代(说真的,别再用浏览器编辑文件了!)。GRAM 移除了 Zed 的 “AI” 功能,也没有 ToS(服务条例;如果你不知道的话,Zed 有这个东西,因为它提供 “AI” 服务)。
在联邦宇宙上随手发的一条帖子被转发之后貌似引来了令人意想不到的关注,第一次见到这个互联网小角落会有这么多互动。看到有这么多人讨厌抽烟我就放心了。

周六发现 PayPal 突然没办法用银联卡支付,而我的 Contabo VPS 马上就要到账单日了,然后开始设想要是没办法付款的话服务器就会无法访问、数据会丢失…… 然后非常焦虑地用了两个小时尝试了各种方法都没办法正常支付,所以…… 大概是需要去办一张 Visa 或者 Mastercard 了吧。
由于非常担心数据丢失,所以托人帮忙垫付了服务器费用,结果第二天我就在小红书上做好攻略出门办卡了,除了因为当时还有不少人办卡(其中至少有三个也是办 Mastercard 的学生)排了半个小时的队之外,进行得意外地顺利,大概也是因为我提前焦虑了好久,最终在海量的选项里选择了办万事达借记卡吧,如果是信用卡的话不知道会有多麻烦。
总之,大概不必担心服务器会被停掉、用不了 Kagi 必须忍受搜索引擎广告以及狼狈地爬回 Cloudflare 这些光是想想就很可怕的事情了。这就是过度依赖 PayPal 这样的第三方服务的后果吗……?
不再使用 Emacs。
不过我想就算真的有单站点的色彩方案设置,也有隐私风险,LibreWolf 还是会默认屏蔽的。 ↩︎