几天前,我和朋友在小红书发布了我们的新项目——Coding Witch · 织码女巫的第一条内容,我们说,希望在冷硬的技术之墙里打开一条缝,让日常、身体、性别、情绪这些词语能够进入技术话语之中。我们说代码不仅可以被写来解决问题,也可以被写来表达困惑、传递感受、建立连接。
很快就出现了许多评论。有善意的,也有不怎么善意的。除开那些明显的人身攻击和阴阳怪气,有一类看似中立的评论引起了我的注意。它们的语气是如出一辙的斩钉截铁,仿佛在重复某种久经训练的共识:“感性是产品层面要考虑的事情,代码是纯理性的。”“代码是0和1,0和1还分性别吗?”
我在许多年里,在许多地方,许多次地看到过这样的表达:代码是理性的,技术是中立的。我意识到,这不只是一种观点,而是一种信仰。
妥协是coding的一部分
我在TFLM(TensorFlow Lite Micro,一个在微处理器上运行神经网络的轻量级框架)的源码中曾经看到过一句让我忍不住发朋友圈的注释。它被写在一个用于进行单元测试的宏定义前面,作者想在测试开始前执行一条命令,结束后再执行一条命令。他没有写成两段逻辑,而是把整个结构巧妙地塞进了一个 for 循环(for-loop)里。利用 for (init; condition; update) 的语法,把前置命令塞进 init,后置命令放进 update。
这不是优雅的代码,也不易读。但它能运行,结构上成立。更重要的是,它在语法允许的范围内,偷了一个恰到好处的懒。在这段代码之前,作者留下了一句注释:
//TODO(petewarden): I'm going to hell for what I'm doing to this poor for loop.
我看见这句话时觉得好笑。但随即意识到,这不仅仅是一种幽默或者炫技。这是一次权衡后留下的东西。这是一个程序员在明知这段写法违反“理性美学”的前提下,仍然选择写下它,并为后来的人标注“这里不是错误,而是选择”。这段 for 循环不是真正的循环,它是非理性的。它不是清晰、对称、逻辑优美的。它是人写的,是被工具限制、被时间催促、被经验引导下写出来的一个决策。
更让我笑出声来的是,git log显示,这行代码的最后一次修改时间是4年前,看来没有人打算从地狱里把这位作者捞出来。
我们称这些代码为“技术债”或“屎山”。我们都见过各种各样的陈年TODO,永远未完成,永远不完美。但这些都不是例外,它们是大多数系统赖以维系的基础。不只是“理性”的补丁,而是系统的一部分。
技术的身体性
我是做语音识别的,我们常用梅尔滤波器(Mel Filter Bank)来提取声音的特征,它是一种非常基础的音频处理方法,常被用在神经网络输入的前处理中。
但梅尔滤波器的设计逻辑并不来全然来自于数学。它的基本原则是:模仿人耳对不同频率的感知能力。人耳对低频更敏感,对高频更迟钝,因此滤波器在低频划分得更密,高频则更稀疏。
这是技术结构具身性的典型案例,它从一开始就不是基于“物理真实”,而是基于人类感知经验。它并不是去还原声音本身的结构,而是去还原“我们听到的声音”。事实上,谁又能说人类的感知不是物理规律的一种呢?
我又想到另一个语音处理的常用概念:等响曲线。等响曲线是一系列通过主观测量得出的人耳在不同频率下感知为相同主观感量的声压曲线,它反映了一个声学和音频处理上的基础常识:不同频率下,人耳听到“同样音量”的声音,实际所需的声压(或许可以理解为某种绝对响度)是不同的。

临床上的听力图(audiogram),就是以这条曲线为基准回执的,0dB HL,不是物理意义上的无声,而是指“平均人耳刚好能听见的最低响度”。这条曲线被作为标准,而所有偏离这条曲线的感知,都被定义为听力损失。
但当我尝试把我(一名中高频受损比较严重的听障者)的听力图的纵坐标转换为绝对声压之后,我发现了一件奇妙的事:
我的耳朵在不同频率上,听到的绝对声压几乎是一致的。
也就是说,从“物理”的角度来看,我的听力感知反而更线性,更对称,更统一。但它被定义为“残缺”。
这不是感知的问题,这是范式的问题。我们如何决定一种感知是“正常的”?谁来规定“标准人类耳朵”应该听得像什么样?我们把无规则的曲线画成了直线,然后说它是中立客观的,“因为它是笔直的啊”。
梅尔滤波器不是例外,等响曲线不是例外。程序的语法、结构、算法,都是围绕一个被建模的人类建立的。而这个“人类”,从来都不是没有身体的。他可能是听力正常的;可能是右手操作键盘的;可能是视觉清晰、神经稳定、注意力集中、熟悉英语语境的;他甚至可能是白人男性,在西方工程文化中成长,并且拥有持续参与开发的权力。
代码作为一种沟通语言
在最初学习编程时我经常想到一个问题:代码的语言到底是谁的语言?
几乎所有编程语言都是以英语为基础的。这一点我们已经习以为常,从变量命名到函数调用(承认你宁可花5分钟反复查词典也不好意思用拼音给变量命名吧),从 if 到 while,从 public 到 try,从 API 的文档到库的调用方式——我们在学习编程时,其实也是在学习英语结构。而这套结构,从来就不是中立的。
你可以说,这是为了“通用”。但谁定义了通用?你可以说,计算机早期在英语世界发展,所以继承了语言结构。但这正是问题所在:不是我们选择了英语,而是英语选择了我们。
不是所有人都用英语长大,但几乎所有程序员都必须用英语写代码。你以为自己在学习技术,其实你是在进入一个语言上已经被规定了“谁是原住民”的空间。
语言是一种权力,而代码就是语言的一种。 更讽刺的是,代码经常被当作脱离语言、文化、身体经验的“纯结构”来看待,仿佛它只是 0 和 1 的逻辑表达。但事实正好相反:代码的书写方式、命名方式、阅读方式、调试方式,甚至你是否理解一段注释,都和你是否是这个语言系统的母语者有关。
再说回那段 TFLM 的注释:
//TODO(petewarden): I'm going to hell for what I'm doing to this poor for loop.
它不仅是个幽默,它也是一种沟通行为,它在传达一个非常具体的信息:“这段代码不常见,但是我故意为之,请你理解这个结构。”这条信息的重要性不低于那段代码本身。
我们太习惯把“代码是沟通”这件事局限在“人与机器”之间。但在真实世界里,代码更多时候是人与人之间的沟通,是跨时间的写信,是传递经验的手势。这并不只是一种隐喻。代码并不干净。它有注释,有命名,有猜测,有语义不明的 flag,有无意义但“别动”的逻辑。它被使用、被修补、被妥协、被遗忘。
那么...
我们都知道技术被应用在不平等的地方,就会为不平等添砖加瓦,但我们常常会忽略技术本身就诞生于不平等的世界,它从诞生之初就带着不平等的血统。事实上,我想说的并不只是“代码并不理性”,我想说的是:我们以为的那种中立的、纯粹的理性,它从未存在过。
