智能 · 随笔

曲高和寡。

两千三百年前,一位大臣向国王解释,为什么没人跟着他最爱的那支曲子唱。这个故事后来变成一个成语,讲高雅与它的孤独。它通常被读成一种等级。放到一个满是控制台、字节转储与防火墙规则的周末里重读,它讲的其实是另一件事:两种知识。一种写不下来,一种在写下来之前毫无用处。

三条经典,一个周末 肌肉:文档里没有的事实 思维:事故写不出的闸门 交接发生了四次

BG1SB  ·   ·  约 13 分钟

本文只主张一件事。雅的知识与俗的知识不是同一种东西的两个档次。它们是两种不同的东西。工程两样都要,而且要按特定顺序,经过特定的一次交接。下面写的每一次失败,都源于只有其中一样。

TL;DR — 五条主张

  • 立论宋玉那两支歌不是等级。它们是两种知识。一种只属于在场的人,无法传递。另一种可以远行,但没有第一种就得不到。
  • 事实这四十八小时里,每一个决定性事实都由肌肉产出。一次配置文件的逐字节转储。一次指纹比对。一份防火墙规则清单。一张控制台截图。没有一条能从文档推出来。
  • 事实每一个不必重做的修复,都由思维产出。一个被命名的缺陷类。四条闸门测试。一处判据从快照改成时间戳比对。每一条消灭的是一个类别,不是一个实例。
  • 推断全部难度都在交接上。留在终端里的事实,是别人永远不会有的事实。没有事实支撑的闸门是装饰。两天里这个环闭合了四次,其余尝试都散了。
  • 已排除本文不是在讲人,也不是在讲模型。两种活是同一双手干的,有时相隔不到一小时。这条界线穿过工作本身,不穿过做事的人。

是其曲弥高,其和弥寡

原始那则故事不是在抱怨品味。它是一份关于传递的报告。

战国时,宋玉回答一位听多了他坏话的楚王。他说,都城里有个唱歌的人。唱下里巴人时,城里跟着唱的有几千人。唱到阳春白雪,能跟上的不过数十人。宋玉的结论是活下来的那句:曲弥高,和弥寡。

客有歌於郢中者,其始曰下里巴人,國中屬而和者數千人……其為陽春白雪,國中屬而和者不過數十人。是其曲彌高,其和彌寡。

A guest was singing in the capital. When he began with the village songs, thousands joined in. When he sang the refined pieces, no more than a few dozen could follow. So the higher the tune, the fewer who can sing with it.

宋玉《对楚王问》(战国)

两千年的引用把这句话变成了一句自夸。人们拿它来说自己的东西太好,观众配不上。但这句话是描述性的,不是辩护性的。宋玉在报告材料的一种性质。雅的曲子难跟,因为跟它需要听众多手上没有的东西。这里没有暗示听众的价值,也没有证明曲子的高下。它证明的是一道传递上的落差。

这道落差正是本文的题目,因为它在一个工程周末里反复发生。有一类事实,只有和机器待在同一间屋子里的人才拿得到。还有一类结构,可以传到以后每一间屋子,但前提是有人把它写成一种能大声失败的形式。前者是下里巴人。后者是阳春白雪。两者不分高下。它们干的是不同的活。把任何一样当成够用,工作就散架。

立论 · 这条界线讲的是传递,不是质量

俗的知识是绑在一个在场性上的知识:这台控制台,这台机器,这个钟点。它随会话结束而死,除非被转换。雅的知识是已经转换过的知识,转换成了能活得比会话久的形式:一个被命名的类别,一条测试,一处判据。雅的形式并不更聪明。它只是可以携带。而可携带,就是偏爱它的全部理由。

七件事,一件一件对回去

下面每一条都可核对。这里没有披着案例外衣的寓言。

一套远程电台系统在两天里从设计文档走到了线上服务。沿途发生的事:一次整机迁移,七个发布版本,四个完成登记的实例,以及一个装完软件看到黑屏的客户。活是两条会话并行做的,那部分另有专文。本文讲的是其中出现的两种知。

时刻定案靠的是什么类别
隧道客户端拒绝自己的配置文件,卡了三小时 把文件按字节打印出来。引号串里的反斜杠开启转义,于是一条 Windows 路径变成了非法的 Unicode 转义 肌肉
入口回 502,而每一处看着都健康 把正在服务的证书与磁盘上那张比对。两者不同,说明进程早于登记就起来了 肌肉
一个被认为被云厂商挡住的端口 列出主机自己的防火墙规则。面板是清白的,机器不是 肌肉
客户的黑屏 一张控制台截图,上面四条警告,每条都指向一个只存在于构建机上的默认值 肌肉
四个这样的默认值,被分开修了四次 给这个类起了名字,并写下一条测试:任何可写默认值落进程序目录就失败。它第一次运行就咬出第五个 思维
一个在某种顺序下报错答案的重启提示 把快照比对换成两个时间戳:这个文件是不是在本进程启动之后写的 思维
谁也收不到的重建包 写下升级通道比较的是版本串,所以已发布的号不能再被复用 思维
事实 · 这个分布是不平衡的

每一个决定性事实都出自肌肉。每一个不必重做的修复都出自思维。这不是这个周末的巧合,这就是两者各自的用途。在场产生事实。转换产生覆盖。只有其中一样的团队,要么反复撞同一面墙,要么反复发布一套没人用得上的规矩。

得之于手而应于心,口不能言

庄子为此准备了两个匠人。两个都在讲一种活不过被写下来的知识。

有个厨师解了十九年牛,刀还像新磨的,因为他从缝隙里走,不从骨头上砍。问他怎么做到的,他说要紧的不是技术。

臣之所好者道也,進乎技矣。……以神遇而不以目視,官知止而神欲行。

What I care about is the Way, which has advanced past technique. I meet it with the spirit and do not look with the eyes; the senses stop and the spirit moves where it wants.

《庄子·养生主》(约公元前 300 年)

这段通常被读成玄谈。当作对专业能力的记述来读,它非常准确。厨师已经不在执行一套流程。他直接感知结构,然后动手。而这份感知,他没法当成一串步骤交给任何人。那十九年不是用来积累规则的。那是用到规则不再是媒介为止的时间。

庄子用另一个匠人把同一件事说得更直白。轮扁看着他的君主读书,然后告诉他,那些书是古人的糟粕。

斲輪,徐則甘而不固,疾則苦而不入。不徐不疾,得之於手而應於心,口不能言,有數存焉於其間。

In cutting a wheel, too slow and it is smooth but not firm; too fast and it bites but will not go in. Neither slow nor fast, it is got in the hand and answered in the heart. The mouth cannot speak it. There is a knack in between.

《庄子·天道》(约公元前 300 年)

要紧的是中间那句。得之于手,应于心,而口不能言。这是对每一种值得拥有的诊断直觉的描述。知道该去转储字节,而不是把文件再读一遍。知道日志路径上的权限错误不是日志问题。知道一个什么都没返回的探测,说明探测本身写错了,不是服务有问题。

它摸得到什么

与现实接触。编码造成的损坏。文件系统权限。杀毒软件的行为。一台没人记得的防火墙。一份解析器缓存。一个活过了父进程的子进程。这些东西不在任何文档里。而它们决定系统能不能用。

它带不走什么

它到不了下一个人手里。那次破解三小时谜团的字节转储,只有一个观察者在一个小时里看懂过。换任何人都得从零再来一遍。不转换,它是一份私有资产,寿命等于一次会话。

它的失手处

把代理信号误当成与现实的接触。一个退出码。一行说编译成功的日志。一个在构建之前就写好的版本文件。这些东西感觉像测量,其实不是。停止接触实物的肌肉,会退化成仪式。

推断 · 为什么口不能言

不是因为这份知识原则上不可言说,而是因为它是按情境索引的。轮扁的手艺,是一张从手感阻力到调整力度的映射表,而这张表的定义域是他此生要削的每一个轮子。任何有限的描述都会丢掉定义域。这也是清单为什么有用却永远不够:清单带的是已经遇到过的情形,而那正好是不再需要手艺的那一部分。

不以规矩,不能成方圆

可携带不是优雅。它是能在你不在场时抵达下一间屋子的能力。

轮扁的结论是书乃糟粕。关于书,他错了。关于他要对比的那样东西,他对了。书带不走手艺。但书能带走一样手艺永远带不走的东西:一条能约束不在场者的规定。

这两天里它取了四种形式。一个缺陷类的名字,于是下一次出现时可被认出,而不是当作新事物。一条会在该类再现时失败的测试,这是唯一能自我执行的规矩。一处判据被改写成两个时间戳的比较,从此去掉了一种会给出错误答案的顺序。以及一句关于升级通道如何决定去取哪个包的说明,它改掉了半个已经做出的发布决定。

给它一个名

四个缺陷被逐个修掉之后,才有人说出那句能盖住四个的话:只在构建机上成立的默认值。命名没有修好任何东西。它让第五个变得可寻。而第五个是被一条测试找到的,不是被客户找到的。

给它一道闸

写在文档里的规矩是一个请求。写在测试里的规矩是一条关于什么能被合入的事实。差别不在语气,而在于没人想着它的时候它还能不能生效。而那样的时刻,是全部时刻。

给它一处判据

这张证书要不要重启才生效。第一个答案比对导入时的快照,于是每当进程先于文件变化就给出错误结果。第二个答案比对两个时间戳,无法被顺序迷惑。

给它一条机制

升级通道比较版本串。一句话,没有代码。它阻止了一次重建被挂在一个已经发过的号上,而那会让修复对恰恰需要它的机器完全不可达。

立论 · 雅是为传递所做的压缩

高雅的曲子难跟,不是因为它更好,而是它为了另一个目的被压缩过:为了能被带到别处还活着。一条闸门测试,是一个周末的调试被压缩成几行断言。这就是为什么没经历过那个周末的人觉得它抽象。也是为什么他们跟不上不构成对他们的评判。那是压缩的代价。而压缩正是它对任何人都可用的原因。

灯灯相续,靠的不是记性

两种知识都有,是常见的。把一种转成另一种,是稀有的。

这个转换有方向,也有期限。一个事实要在被发现的当天就变成一道闸门,否则它不再是事实,而变成一则轶事。轶事是事故之后人们讲的东西。闸门是挡住下一次的东西。两者的差别在于,有没有写下什么能够失败。

两天里这个环闭合了四次。一次字节转储,变成一条关于配置文件转义的规矩。一次证书指纹不符,变成一处时间戳比较。四个构建机默认值,变成一条关于可写路径的测试。一个客户找不到输入框,变成一条关于哪个面板必须含有它的结构断言。每一次,这堂课的成本从一次事故降到了零。

更多时候这个环没有闭合。原因值得写出来,因为它们都很平庸。时间压力。一种认为症状停了就算修好了的信念。一个假定发现者会记住的默认。还有一个当代的变种:一条会话给自己写下三条规则,反复复述了几次,然后违反十四次。因为规则是文字,而文字在它被破坏时不会拒绝继续。

不以規矩,不能成方圓。

Without the compass and the square, one cannot make a circle or a square.

《孟子·离娄上》(约公元前 300 年)

这句话常被引来讲抽象的自律。它的字面内容更有用:出形状的是工具,不是意图。一个想做方形的匠人,手上没有矩,做出来的就是别的东西。一个想验证构建的团队,手上没有一条能拒绝坏产物的判据,照样会把坏产物发出去,而且意图完好无损。

不转换转换
发现它的人能再解一次,而且更快 任何人都能,包括没见过这套系统的人
这堂课的寿命等于那个人的记忆或在场 这堂课的寿命等于测试套件运行的时间
重复事故每次都要付一次完整诊断 重复事故在出厂之前就被挡住
质量取决于谁还醒着 质量有一条不依赖任何人的下限
推断 · 为什么期限是当天

不是出于情怀。转换需要那个事实还鲜活:是哪条命令产出的,当时错误的预期是什么,哪一层在撒谎。这些细节在几小时之内就衰减掉。没有它们,闸门会写得足够松,让下一个实例照样溜过去。这套系统里当天写下的闸门,全都咬到过东西。晚些写的那些是装饰。

曲高非贵,和寡非失

周末被忘掉之后,还值得留下的那部分。

宋玉那句话常被引去安慰一个作品不被欣赏的人。那是误用,而且是昂贵的误用,因为它把一句关于传递的陈述,换成了一句关于价值的陈述。曲高不是因为更好。是因为可得性更低。这算不算损失,完全取决于有没有人把它带回下面来。

于是留下这个周末学到的两条规矩,按学会的顺序。

给手的那条

不要拿一个信号顶替一次测量。版本号。带年份的时间戳。一个与上一版不同的哈希。然后真的把它跑起来。下里巴人只在唱的是你脚下这间屋子时才值得唱。

给头脑的那条

每一个用硬办法换来的事实,当天变成一道闸门。不是一条笔记,不是一份文档,不是一个以后仔细的打算。而是一样会拒绝继续的东西。阳春白雪只有当别人最终也能跟着唱,才对得起它的难度。

那两天里出现的分工从不是计划出来的,也从不对称。一边写设计记录、预防性守卫,以及关于机制的判断。另一边活在字节、控制台、防火墙,和客户能双击的脚本里。谁也不比谁资深。谁也单独做不出那个结果:没有那些事故,守卫会是空想;没有那些守卫,事故会一直重演。

让系统变好的,不是任何一种活。而是那个时刻,发生了四次:一个来自控制台的事实,变成测试套件里的一道闸门。每一次都消灭了一整类未来的失败,而不是它的一个实例。每一次的成本,比只修那个 bug 多花大约十分钟。

立论 · 收束

雅的和者寡,因为它为了远行而被压缩过。俗的和者众,因为它从来就没打算离开那间屋子。工程两样都要,而且要它们耦合在一起:一个能摸到机器的在场,和一个能活得比摸过它的人更久的形式。曲弥高,和弥寡。而如果没有人把它写下来,那份寡就是纯损失。