.. Kenneth Lee 版权所有 2022
:Authors: Kenneth Lee :Version: 0.1 :Date: 2022-06-12 :Status: Draft
:dtag:架构设计定义
什么是架构设计V4
最近在引导一个涉及软硬件协同设计的项目,收集了一组经验,再次重建一下我的架构设 计理论模型。(这个版本还没有整理完,先写着)
又写一个版本的架构设计定义。
构架设计本质上是控制名称空间。为此我们需要理解一下名和道的关系。世界万物,存在 在那里就存在在那里了,对它的任何一种所谓“描述”,本质上是我们脑子里制造的一个“数 字孪生”,我们希望用这个数字孪生在一定程度上预测现实世界的现实。但这个“数字孪生” 从来不是现实世界本身。
在《道德经》中,这里提到的世界万物,就是“道”,而我们在脑子中,语言间,对道的描 述,就是“名”。所以,实际上,我们现在说的“世界”,“万物”,“数字孪生”,这些名字, 都是“名”,这个名确实在说那个“道”,但它们并非就是那个道。它们只是道的其中一个抽 象,一个投影,一个角度。
我们必须用名去描述这个世界,因为我们的脑容量是有限的,我们没有能力用道的所有信 息去讨论世界。一个班60个人的成绩我们都只能用平均分,中位数,最高分……这些概念去 讨论它,不要说研究一个几十万,几百万,几千万行的软件。所以,道曰大,大曰逝,逝 曰远。道到了我们的脑子中,就会丢失细节,变成一个名。
我们用名去描述我们看到的世界,所以我们总有种错觉,觉得我们的名描述的是唯一的, 真实的那个世界,或者至少可以说是这个世界的一部分。但其实我们描述的只是世界某个 部分的一个抽象。我们的抽象和别人的抽象也是不同的。
但我们判断我们如何走向下一步,是基于我们制造的这个抽象来进行的,我们的抽象控制 不了这个世界,但它控制了我们如何改造这个世界。所以,我们如何命名我们的世界,决 定了我们如何改造这个世界,从而一定程度上控制着相关的“世界”未来的那个样子。
不少人会产生一个误解,觉得信息都在里面了,只要不断补充信息,就能够得到一个未来 的系统。这就是为什么很多人宁愿马上编码,再去补设计文档,而不用用一个设计去控制 它们的编码。因为他们觉得这样“务实”,他们认为高层设计只是编码的重复,只是为了让 某些“领导”明白他们干了什么才需要的东西,他们那些细节的if...else...while才是“专 业”的东西。有了那些东西,才有“抽象”。
举一个例子,我们曾经设计一个指令,比如叫compress,它对指定的寄存器中的数据进行 一个压缩的操作,这条指令需要的数据很多,靠固定长度的指令是肯定不行的,为此我们 需要延长它的长度。但我们的指令解码器只能解定长的32位指令。这时我们有两种方法解 释这条指令,一种是如果指令解码器解到一个32位的compress指令,我们认为之后的96位 都是这个指令的一部分。第二种方法是解码器认为自己解了4条指令,第一条表示启动解码 ,后面的表示设定参数。
如果我们认为能运行就好,两种方法对我们来说其实都无所谓。但其实后者的构架代价是 很高的,因为架构是个穷举的,发展性的问题,指令发射是原子的,指令每次读32个自己 ,全部读完才会发射出去,这条指令和其他指令的取值直接,是没有穿插关系的,互相是 原子的。但把指令分成启动压缩和设置参数两个行为,两者之间是可以插入无数其他指令 的,如果描述这个状态机?这就是高层建模。如果我们不控制这一层,程序确实也能在一 些流程下正常运行,但一旦出问题,这个系统到底还行不行,你是不知道的。
在这个过程中,我们加入了额外的劳动,建立了一个高层逻辑,然后在高层逻辑中控制了 我们代码的行为,从而让我们的系统在高层呈现了特定的规律,这样我们的程序就可以控 制了。
所以有图纸我们可以把大楼改几十层,没有图纸就堆土,你三层都不一定能盖起来。难道 图纸是钢筋混凝土的一部分吗?它只是改变了钢筋混凝土的组织形式而已。
你甚至无法问:我堆的土,为什么就盖不了几十层楼高?这个问题无法回答,因为你的系 统不呈现规律,而“名”的系统,就只能说那些有规律的东西,没有规律的东西你连说都说 不了(所谓名可名,非常名),你个闹嚷嚷的课堂,有学生在抽烟,有学生在谈恋爱,有 学生在放爆竹,你问这些学生正在做什么,是否有人能考100分,这没法回答,因为没有可 以回答的条件。
同样,你的代码收到一个要打印的需求就打印,收到一个要写文件的需求就写文件,收到 一个要排序的功能就排序,然后你问这个软件能否实现一个迁移的功能——对不起,没人知 道,因为我们不知道它有什么规律。我们甚至不能说它一定不行。
想像一下,一个精巧的算法,各种可能性都考虑到了,写了下来,有100万行的代码,现在 其中有一个地方出现一个内存越界,可能随机把其中一个变量的值修改了,你怎么把它找 出来?或者你的CPU出了问题了,某个加法的结果,随机可能是一个随机值,你有什么办法 把这个问题找出来?
系统一旦失去了让我们进行数字孪生判断的依据,我们就失去了对它的控制。所以,架构 设计是控制我们如何定义控制这个系统的名称系统,我们如何命名一个系统,决定如何抽 象它,是架构设计的全部。架构设计不是任何一行代码,架构设计表示所有的代码。这就 是架构设计角度的名和道的关系。
而在实践上,架构设计是人的意图,编码和细节设计是机器的意图。这两个边界很模糊, 但在模糊的角度上,这个分界线清晰存在。
我们又举一个例子。最近遇到一个问题,有人做一个原子操作的测试方案,他在一组线程 里面,用原子函数设置同一个变量,然后读出来,判断变量是否被原子更新了。为了让这 个变量的读写互相之间没有影响,他又用了一个spinlock,把这两个原子操作保护起来。
这就很奇怪了,明明测试的是原子操作的行为,你用spinlock把它保护起来,那这个被测 试的函数无论是否完成了原子操作,不都是成功的吗?
这种情况很常见,“测试原子操作是否符合预期”,这是我们人的意图。而先“调用 atomic_set(), 再调用atomic_get(),为了可以判断atomic_set和atomic_get()是一样的 ,需要把两者保护起来……”这是机器的意图。如果你抛开人的意图,钻到机器的意图中了, 失去人的意图。
我举这个例子的时候,为了让你明白,在描述的时候已经建立了一个名称空间,把问题按 我的名字分类给你说出来,所以你会觉得这很明白啊,很简单啊,怎么会分辨不出来?但 一旦你自己去面对那个复杂的局面的时候,你就很可能分辨不了了。
你做一个复杂系统,比如用qemu模拟一个CPU的运行,qemu翻译程序,把Guest的代码翻译 程序执行代码,这是一个角度,被翻译的代码更新被模拟的CPU的执行,这是第二个维度, 被模拟的CPU运行操作系统的调度代码,这是第三个维度,被调度的代码从一个线程切换到 另一个线程,这是第四个维度……这些不同的角度,描述的是同一个事实(“道”)。
现在你告诉我“运行Guest中的switch_to函数”,在这些不同的维度中,分别是什么意思?
这就是架构设计中,分解不同的概念空间,在概念上保证同一件事情,在所有维度中,概 念都是自恰的作用,只有我们保证了概念的自恰,我们在每个空间上的逻辑都是可以发展 的,这样,这个软件的高楼,就有机会一层层往上盖,否则就必然盖到第二层就倒下来。
而他们甚至无法告诉你,为啥这东西会倒下来。
todo:具体的方法。