仓库源文

.. Kenneth Lee 版权所有 2018-2020

:Authors: Kenneth Lee :Version: 1.0

自然,守弱和Plan B


本文继续细化这个讨论:“道法自然”和守弱。

在前面这个讨论中,有人提到,道法自然是顺势而为,而顺势而为是提前应对或者Plan B 。而这恰恰是我反对的东西。所以我独立写一个文档讨论这个问题。

思考都是建立逻辑链的过程。设计也是个逻辑链,编码也是逻辑链。都是“如果XX,就YY, 如果ZZ,就KK”。引申一点,就心来说,战术也是逻辑判断,战略也是逻辑判断。在“脑力” 的投入上,两者没有什么不同。而一个人的脑力是有限的,无论在战略上还是战术上都要 省着用,要平衡两者的投资。战术会直接产生结果,战略可以降低战术的成本。所以不做 设计的结果是大量的代码重写,过度设计的结果是一直都在设计,产生不了代码。设计和 代码有一个“自然”的位置,这个位置和这个事情的“内部应力”有关,和各个参与方的“度” 有关。它可以摸出来,但无法“预设计”出来。

所以,首先顺势而为不是Plan B,顺势而为是删除战略逻辑链中“不需要投入自己的战术精 力”就可以实现的依赖,从而降低整个工作的成本。而Plan B的逻辑是增加风险管理计划来 提高战略逻辑链的可靠性。这两者是并列的两个策略。更重要的,这两者都不是万能的, 因为它们仍有可能过了那个“度”,无法咬到“道”真正会断的位置。两者都是有主动性在里 面,而不是让“自然”自己去发生。

道法自然本身有两个意象:

第一,道和个人欲望或者定义是偏离的,道不以意志而转移,它是共同作用的结果

第二,道可道。道确实是有规律的,不是不可捉摸的(否则就没有“法”这个概念了),但 你不能去控制它,你只能去利用它。你不一定定义它的位置,但你可以“预期”它的范围, 或者在发展过程中跟随它。简单说,你不能提前画出一只猫的运动路线,但这不表示你在 实际操作中不能跟着猫跑。

不能“控制”,却可以“利用”,这个逻辑的应用价值是什么呢?我们拿一个设计例子来深入 探讨一下这个结论。

前段时间,我们芯片开发组开发了一个特性,其中有一个寄存器是128位的,有底层开发经 验的读者应该明白,这样的IO寄存器处理起来是很麻烦的,因为一般的64位平台,一次可 以发起的地址最多64位。一次发出一个128位的地址,需要比较特殊的SIMD指令才能搞定。 我评审这个接口的时候就顺口说了一句:“这种接口得在驱动里面放汇编,又得跟社区撕逼 了”。那位设计师就担心起来了,立即说,“那我们把这个接口改成64位的。”,要说,他把 这个接口改成64位,软件部分肯定是容易处理多了。但我猜,既然他当初设计成128位的, 显然是为了解决原子性的问题,换成64位的,软件不会变得更简单,因为可能得在过程中 加锁,加了锁,软件就和线程库发生关系,和线程库发生关系,转化为用户态驱动就会再 增加一堆的困难,说不定最终还得不偿失呢?

作为一个软件设计师或者一个硬件设计师,如果在面对问题的时候,有无数的解决方案, 他反而会很难受。做事容易,选择艰难。本质上,人在面对“设计”的时候,都是BDSM受虐 狂,他们喜欢“限制”。正如那句话说的:钱的问题最好解决了——要不有钱,要不没钱!

“没得选择”为什么成为大部分人的追求?核心问题不就是我前面提到的“脑力成本”嘛。

这个位长的例子中,接口上有很多的选择,但每个选择都有成本,无论你做多么细节的设 计和推演,做多少个Plan B,你的预期都可能出错。关键问题是,选择产生的执行成本, 和你计较Plan B,Plan C,Plan D的成本,都是一样的成本。

比如128位的API,实际上Cavium已经在社区推writeo()接口,准备对这个汇编进行统一了 。你可能觉得你可以赌这个“道”是最终128位IO会成为一种标准的平台功能。但这个补丁还 没有被接受呢!它是不是一定被接受?你在ARMv8上当然可以很容易做stp/ldp,在其他人 的平台上是不是那么容易被接受?再说了,为了让其他人接受,这个实现也已经在退缩了 ,你看看这个讨论:[PATCH RFC 0/3] API for 128-bit IO access,作者已经说了,这个 操作可以不是原子的。那么前面这个例子中,我们根本就不可以依赖这个API,因为我们整 个目标就是通过这个操作来实现原子性。原子性才是我们的“弱”,“统一的128位IO API”不 是。

所以,道法自然的核心在什么地方呢?道法自然的核心在于,人心是控制不了“自然”的复 杂度的,你无法千般计较,但它又确确实实有“规律”存在,你在一定程度上可以跟随(而 不是控制)。

所以,守弱才这么重要,因为守在弱上,你面对变化的时候才有余地,守在强上,只会增 加额外的成本。

具体在这个例子上,我们首先应该抱最粗的一条大腿(也是我们的目标)进行设计,这个 大腿显然是:客户需求。客户要求这个功能成立,而且性能最高,他换一个选择的唯一依 据是有人提供更好的解决方案,否则道就会向着我的方向走。这是最基础的逻辑。

然后我们就可以基于我们认识的最初步认识,综合软硬件的设计,用功能和高性能作为丈 量做出一个,“最好”的,但“没有经过那些没有被‘计较’的其他因素洗礼”的,接口。接口 做成这样,然后双方进行沟通,背后软件和硬件在自身约束上的考量可以表达出来,双方 对对方的“弱”是有所了解的,比如芯片的约束可能会是:

  1. IO的总线宽度是128位的,这个是已有的实现,不太可能修改成其他位长了

  2. IO的IO地址空间只分配了128M,要支持64个VF,无法扩大范围了

  3. IO对内存的访问都经过IOMMU单元,对内存访问的原子性是守IOMMU的行为控制的,不可 能越过等等

软件的约束可能会是:

  1. 软件需要同时支持x86和ARM,增加128位原子操作不是不可能,但有额外成本

  2. 软件要支持用户态进程不经过系统调用直接使用VF,不能和其他VF实现互斥

  3. 软件需要支持1万个以上的进程共享使用这个IO,所以必须支持功能隔离和快速动态重 新分配

  4. 等等

这些东西让你列出来根本就列不完(我刚接手芯片软件工作的时候,芯片的同事最喜欢让 我列出“软件的所有要求”了:)),我们需要做的是完全按自己的期望把自己模块的期望 表达出来,包括自己错误的“认识”,不用计较那么多(比如,“我就是提供128位的地址”, “我认为芯片实现这个判断逻辑成本不高”),但交流的时候心中是守着这些真正的“弱”的 ,这样在一番交流后,真正的约束就暴露出来了,双方对对方的底线就清楚了。这样就会 越加地贴近“道”。这些,在交流前是不能预期的,在未来的执行中,也是无法预期的,但 它存在你的心里,并一定程度扩散到接口的相关方那里。如果你一开始就是弱,既无法设 计,也无法交流,实现不了真正“弱”的配合。但反过来,如果你守在强上,动不动就“不可 更改”,“我的设计,怎么可能错”,“你不懂软件”,“你不懂芯片”……那你终究只会失道。甚 至,更常见的情况,你怕漏怯,干脆避开那些明明是你的关键判断,但你没有把握的东西 ,你在对外交流中故意隐藏了你的关键依赖,“交流和合作”这件事本身在关键依赖上就帮 助不了你,道最终就会backfire到你的头上。求名失道,求道失名!

所以,“守弱”,既要强调守,也要强调弱。

哦,对了,还有一句在交流中我最讨厌听到的:“这个功能对软件/芯片不可见”,这句话用 在封装性上是没有问题的,但很多人是用在莫名的优越感上的:“你们这些外行不懂,这些 问题不用管,用我告诉你的接口就可以了”。fuck you。你这么牛,自己把功能就搞定好了 ,还来讨论条毛啊?

——令人高兴的是,至少我身边这样的越来越少了:)

p.s. 其实就着这个问题,还可以讨论到开源战略上。很多公司为了占便宜,总觉得“我不 用参与开源社区的活动,我把别人做得好的部分拿回家,我自己做得好的部分不用告诉他 们”,他们觉得这样简直就把自己置于不败之地。他们的决策层总是认为参与开源活动完全 是参与“慈善活动”,是“社会责任”,却从来都不明白,把自己包起来——已经在限制自己的 能力了。

千般计较,不过是作茧自缚,不理解自然之道,人终究会以为人力的计较可以胜天,却不 知道,天道以无有入无间,你能封闭“有”,你是封闭不了“无有”的。