怎么确定道¶
最近给两个新来兄弟辅导设计方法,突然对慈,俭,不为天下先有了一个直观的解释,我 把它整理在这个文档中。
这个文档是针对开发人员写的,但基础逻辑基本上是种哲学性质的推演,我尽量在前面表 达得通用一些,把程序相关的讨论放在后面,以便对不写程序的人也有一点参考价值。
之前的博文已经讨论过了,道是现实发生的逻辑路径,它具有三个特性:
- 多面性,我们只能获得它其中一个侧面。球进了球门,你可以关注球在门内的事实,也 可以关注是张三踢进去的,也可以关注不是门柱弹了一下它也进不去,也可以关注球是 第三运动器材厂的产品。所以,没有“关注点(妙)”,无所谓道。至少不是可以谈的道
- 部分道已经发生,不可改变。(已道)
- 部分道还未发生,这是我们关心道的核心,我们希望确定这个道,顺着这个道走,我们 就可以达成目标。(未道)
本文要讨论的问题就是确定这里第三点的策略是什么,说明为什么“慈”,“俭”,“不为天下 先”这三点是确定“道”的重要原则。
我们现在有一个位置,我们心中有一个目标,这是两个点,如果我们用一个平面坐标轴来 做比喻,它是这样的:
如果我们不考虑任何障碍,最好的路径是在这两个点之间连一条直线,这就是最优的“道” ,它包含的概念最少,描述这个“道”,只需要起点和终点的坐标:
这里只有两个名。如果用现实来类比,好比我要从小吃店里去巷尾上公共厕所,店员告诉 我“道”怎么走:
你从这里顺着巷子往前走,一直走到头,看见门口挂着“公共厕所”牌子的就是了
中间经过一间杂货店和一个半人马雕像这种事,不在你,也不在他的关注点中,这都是“无 ”(视之不见,名曰夷;听之不闻,名曰希;搏之不得,名曰微。)。
这两个东西,在整个表述,或者你的思考中,都看不见。你急着上厕所,什么杂货铺打折 ,半人马巧夺天工这种事,都和你无关,这就是叫五色令人目盲,五音令人耳聋。我们聚 焦在一个妙(interesting)上,就不会关心其他角度了。
什么时候你会关心它们呢?——你遇到障碍的时候。
巷子中间施工,挖了一个大坑。你要绕过它:
你道(未道)可能就变成这样了:
从这里顺着巷子往前走,遇到一个杂货铺的时候,进去,从后门出来,左拐,继续走,遇到一个半人马雕像的时候,左拐,一直走到头,看见门口挂着“公共厕所”牌子的就是了
这里你就引入了两个新的“名”。我们优化“未道”这个逻辑链,第一个基本原则:不增加不 影响“道”方向的名。这就叫不为天下先。在道德经中,这个原则是针对领导者来说的,所 以,有一个额外的含义:不要引入额外的需求。但还是那句话,我们现在聚焦”设计“这个 主题,其他东西到我们需要的时候再去推广。
好了,基本原则我们有了,现在核心的问题是,在我们没有走过去的时候,我们怎么知道 那里有没有障碍。这就是”知不知“这个问题的策略了:我们需要去调查,确定哪里有障碍 。但调查本身呢,也是一种投入,直接去做也是投入,调查也是投入,如何平衡两者的关 系?最好当然是“做本身就是一种调查”,调查完了,该做的也已经做了。但很多时候我们 做不到,所以,我们尽量聚焦到和“道”转弯有关的核心问题上。也就是说,在我现在要走 的那条路最相关的信息,是我优先调查的位置,调查到什么程度,是架构师,领导者的本 身对问题的认识问题。但至少,在基础方法逻辑上,我们得聚焦在“道”上。所以,我们的 基础方法是:把所有的“知”先标记出来,把“不知”也标记出来:
![]()
其中红色的是知其可行,透明度表示它的置信度,黑色表示知其不可行,白色表 示未知
有一副这样的图,我们要判断下一步是调查还是执行,就是一件很自然的事情了。这样我 们很容易理解什么叫“慈”和“俭”了。不硬冲就是慈;不绕路,就是俭:
所以,慈故能勇,能避开的都已经避开了,剩下的就没有什么可以纠结的,硬冲就是了。 围城必缺;抗兵相加,哀者胜之。没得选的,总是比有得选的更勇。
绝学无忧,对于求道者(求目标达成者),没空跟你讨论和道无关的逻辑。所有的逻辑都 是聚焦到“选择”上面的,没得选择的时候就是“事善能”,那个时候拼的是“勇”,更不跟你 谈逻辑。所以我们不求头头是道,我们求“最优选择”。
好了,哲学说完,我们谈谈怎么做设计的问题了。设计是代码的“道”,最终的代码是我们 的目标,但如果我们前期不对我们实现整个代码的“道”有一个正确的认识,我们选择的可 能就不是最优路径,只会碰得头破血流。比如你选择一个不支持多线程的库来作为你的编 码器,然后就开始基于这个库创建会话,分配内存,进入这样的细节,你的资源消耗大半 的时候,你发现性能不够,就好像走了遥远的路了,目标在一座万丈高山的后面,近在咫 尺,你也只能看着了。
所以,对于设计,我第一反对的是你没有设计,没有设计就表示我必须把一切都寄望在最 后。特别是那种三个月,半年才交货的代码,没有设计我都害怕得要命,要知道,做这种 判断,可不是在你交货的时候开始的,而是在你应用的时候才发生的。比如你做一个SAS控 制器,某些新插盘进来的时候需要重新扫描整个阵列,结果libsas根本不支持,你想改, 但libsas现在连维护者都没有了,什么都改不进去,你自己的驱动从一开始就没打算弄…… 这种问题,验收都发现不了,都是到了用户的场合才知道的,你前期不推演,到应用的时 候你跟我说改,改条毛噢。(严格来说,这个没有需求支撑推演也不一定推演得出来,但 就这个问题来说,因为是个状态机问题,进行逻辑推演是可以捕获的)
所以,设计没有你想的那么复杂,你有5个需求,每个需求大概怎么做?你打算放几个.c, 几个.py,里面还有几个.go?他们怎么发生关联,从而那个功能可以被实现?你有多少个 版本要合?这些版本编译成多少个二进制?这些二进制部署在Docker/LCX中,VM中,还是 Host Kernel中?这些都是说说而已(不是代码,也没有用代码校验过),但我们都有经验 ,知道这样弄,成功的可能性有多大,这就是很简单的事情。但你不想用这个心,在过程 中怕批评,怕接受别人的意见,不断把你的描述说的头头是道,无懈可击(所以很多人才 会到代码写完才肯交设计),你最后就到不了你想达到的那个道。这种心态,弄来弄去, 最终一辈子都活在“解释”中,永远都体会不了“成功”的快感。
始终有一张图景,我们就不断有办法判断我们下一步是“写一部分程序”,还是“做一个代码 验证”,还是“调查一下某个未知的情形”。这我们就会离成功近很多。而不是,上来就开始 写代码,遇到障碍就来给理由,文档写得技巧十足,道理满满,无懈可击,遇到质疑就解 释,背后抱一个“没有功劳也有苦劳”的心理支撑。对于这种,我老实说,我的策略是“不代 司杀者杀”,我该帮已经帮了,你自己要掉下去,这我可帮不了。
没有这种图景,我们想慈也慈不了,想俭也俭不了。但另一方面,我们建这个图景,是为 了能改变路径,避开不知和障碍。但其出弥远,其知弥少。我们不是为建这个图景而建这 个图景的。所以很多设计文档,缺乏对这个图景的聚焦,那也是没有用的。比如,很多人 会拷贝完整的代码作为设计文档,把写验证代码做的数据结构,原封不动地拷贝上来,显 得专业,复杂,但这种复杂度,对你提前发现设计逻辑中的问题毫无帮助。我问你“为什么 要在设计中强调device_group有一个lock和一个rb_tree”呢?你告诉我“因为访问 device_group需要上锁才能访问啊,device是个稀疏阵啊。”,我靠,这句话真有道理,我 简直无言以对。你说的都是对的,但和我们正在讨论的大的设计,分多少个模块,主要功 能是否可以实现,关联度有多高呢?
所以,设计这种东西,不同层面有不同的取舍,取决于我们最后要做的决策是什么,架构 也可以有非常细致的设计的。我的博客里经常有人问我为什么文字有相当多的定语重句, 老天,我这也叫多,你们要知道我每天对着,或者自己写着,是什么样的鬼话。我拉这个 典型的给你看看:
A read or write operation is single-copy atomic only if itmeets the following conditions:1. For a single-copy atomic store, if the store overlapsanother single-copy atomic store, then all of the writesfrom one of the stores are inserted into the Coherenceorder of each overlapping byte before any of the writesof the other store are inserted into the Coherence ordersof the overlapping bytes.2. If a single-copy atomic load overlaps a single-copyatomic store and for any of the overlapping bytes theload returns the data written by the write insertedinto the Coherence order of that byte by the single-copyatomic store then the load must return data from a pointin the Coherence order no earlier than the writes insertedinto the Coherence order by the single-copy atomic storeof all of the overlapping bytes.
这段描述来自ARMv8的构架定义。你看,构架也可以有构架的“细节”的,但每个这样的细节 ,都是支持构架这一级的逻辑链的。你看看人家这个构架文档怎么说的:
The ARM architecture described in this ArchitectureReference Manual defines the behavior of an abstractmachine,referred to as a processing element, oftenabbreviated to PE. Implementations compliant withthe ARM architecturemust conform to the describedbehavior of the processing element. It is not intendedto describe how to build animplementation of the PE,nor to limit the scope of such implementations beyondthe defined behaviors.
注意最后那个强调,它是精准来源于缩小范围,聚焦要解决的范围的,而不是什么都有的 。
我的设计大部分都不能公开,这里有一个难得是公开的,可以作为参考:
我这里喋喋不休地描述iommu_group的原始定位,vfio_group的设计意图,竭尽所能要描述 出现各个势力在这个问题上的预期图景。这些观点,我不认为他们对,也不认为他们错, 但我需要把它们摆出来,都是为了形成前面说的这个图景。只有有了这样的图形,只有我 对他们有正确的认识了,我才能避开所有的障碍点,找到一个满足我的要求,最容易切进 去的点。
在我写本文的时候,那个文档已经是第5个版本了,每个版本都是有一个设计者提出不同意 见后进行根本上的修改然后才重新整理出来的。
写这种东西,说到底就是聚焦(决策逻辑链),确切(无二义性),反而正确性是放在第 二位的,因为本来我就是无法彻底正确所以才写出来取得共识,你要面子,避开这种有可 能的错误,不如不写。另一方面,你们看看那个描述的逻辑的复杂度,我能把脑子控制住 所有的要点就不错了,我还有空关心你的情商,文笔之类的东西?我首先要保证的是我的“ 正确认识”,然后才是别人的正确理解,最后才是什么情商,文笔这些字节。加花是主干稳 了以后的事,主干都没有稳就讨论什么“这样描述更好”,“这个概念不是这样定义的”之类 的,基本上都是腐儒之见,你们不过是在讨论自己的面子和名声,根本就没有关心那件事 本身啊。
要满足我的特性,最终我肯定是要修改别人的模块的,比如现在那个上面的决策是要修改 type1驱动对mdev的特殊处理的。但所有的路径都考虑过了,能躲开的都躲开了,那就是个 所有力量聚焦要突破的地方,那有什么好想的?我们就不会再犹豫了,就是一个冲字。这 就是慈所以能勇。
其实说来说去,这些东西可能很多工程师不是不知道,可能还是有“怕露怯”的心态。而且 这种心态是根植在骨子里的,如果不主动去露怯,把心思全部放在求道上,根本自己都不 知道(自己在求名),可能永远都走不出来。
怕漏怯的另一面就是装逼成狂,明明已经弄清楚的判断,非要向外拉逻辑:关于这个 iommu_group你们不知道吧?这个可是当初我和某某某谈笑风生决定的……这里面还有一个故 事……要不就是知乎式的“这种大路货的知识也敢拿出来显,你懂XXX,YYYY,ZZZZZ吗?”
天之道,高者抑之,下者举之。要准,不是要“牛”,名字露出来就已经“不牛”了。
最终的结果始终就是我给你谈道,你来给我谈情商,谈面子,谈站在我这一边。对这种, 我还是这句话,我无能为力,我不代司杀者杀。但你如果认为“常”没有“司杀者杀”,我没 有什么可说的。
(对了,我的表述和任何真实事件无关,就是想讨论一个逻辑,所有的情绪表达,不过是 为了行文生动。还是那句话,如果你不关心这个道,而关心扯是扯非,我是帮不了你的)