“优秀架构设计”

今天有人找我设计一个课程,叫“业界经典架构赏析”,我回应说,“设置这样的课程就是不懂架构”。

这种说法很欠揍,趁着现在开的会都是别人在互通基本问题,我插不上话,我偷个空把这个说法解释一下。

“经典架构赏析”,就意味着,我们可以总结出某个架构的某些“特征”,说明它做得好,“经典”,“值得学习”。

但如果我们这样提取架构,我们能提取的特征就会只有:“好多人用”,“卖了好多钱”,“还在发展”。这东西没有什么可“赏析”的,只能用来“膜拜”。

每个架构选择,都是一个“约束”,一个“两难”的选择,我们只是两相其害取其轻而已。每个“成功”的架构选择背后,都种入一个“失败”的种子。所谓的成功,是每个选择都买到了一个足够的利益,而失败还没有积累到拖跨这个系统而已。

没有值得欣赏的架构,因为“好”的架构是它所有的选择都没有做死做到把它自己拖垮而已。Linux的VFS很值得欣赏吗?Page Cache在NVMEM上一点用没有,inode里面放那么多namespace这样的数据结构就是作死。它能不能从传统存储向内存存储跳过去?难说得很,跳不过去就是“垃圾架构”,跳过去了,就继续是“经典架构”。VFS是它是“优秀”架构的特征吗?远得很呐。

Android用了Java所以跨平台特别好吗?GC性能问题天天被人吊着打呢。iOS用Object C就行了?就自己一家能用,孤家寡人,市场份额以肉眼可见的方式萎缩呢,一旦创新不能延续,就一定能活得很好?

甚至像很多人说的,到处都是全局变量的飞机控制系统,你就能说人家架构不好?没有分层?没有抽象。人家还能维护下去,人家的投资模型和你不同,人家就是好架构,只要它控制得住,你都没有任何理由说人家这个架构不好。

每个架构不过是避免作死,卑微地活下来,然后就有一些文人雅士给你解释,这个东西多么多么好,放个屁都是香的。一个不好没有混下去了,这些人又会跳出来给你解释,这个东西多么多么不堪。其实都是火烧不到肉的胡说八道,根本抓不到要点。

一个“业界经典架构赏析”的课程,就是对架构这个工作的误判。我们可以找到“架构做死大全”(但这个会得罪人,至少这个架构没有死绝,就会有文人雅士出来咬你),因为明显的错误我们都是可以看到的,但所谓“赏识经典架构”,就是认为架构只是处理一个特征,而不是处理所有细节的全集。让听众去听这样一个主题,这个主题本身就是误导。

我们有办法谈每个具体情形下,某个特定的架构选择哪个好,但我们“赏析”不了什么“好架构”。


再补充一个逻辑:虽然我们认为好的架构不能“赏析”,但我们又不能不做架构设计的。我用今天我开会评审的一个设计作为例子来讨论这个问题。

我们今天在讨论做一款硬件(假定叫A吧),A以前有过一个版本,我们姑且叫A1,现在要做的是一个新的版本A2。A2提供比A1更好的带宽和时延,为了达成这个目的,A2要求软件提供比A1更多hint,但它还要考虑过去用于A1的软件可以直接用于A2。

但硬件工程师定义这个设计的时候,上来就开始谈新的硬件内部模块怎么分布的,算法是什么,十几个初始化步骤,硬件和软件交互时这个字节那个位的关系,等等等等。

我对这个设计的评价就是:没有架构设计。

问曰:什么是架构设计?

我的答复是:你在最前面给我说,你的A2硬件接口对A1的接口完全兼容,这就是架构设计。总体上抽象一个逻辑:在A2发出一个请求前,需要先构建一个hint,让硬件可以提前准备数据,这个逻辑的定义本身,这也是架构设计。

对曰:我是兼容的啊,我有hint啊。

我说:兼容你写出来啊,有hint,这个hint的原理给出来啊。

对曰:我都写得这么详细了,为什么还要写这个?

你看,这里就是架构设计和细节设计的区别,所有设计都不是最终的的产品,我们也不可能人人去检查每个RTL逻辑和最终的网表是否能满足要求,但我们要保证你在某个层次上的设计目标。你写一万个位如何如何,只要有一个位和A1的接口不一样,这个“A1软件可以用于A2硬件”的目标都不会达成。没有这一层控制(或者说承诺),A2只要有一点小差错,我们这个提供给用户的目的都不会达成。

“决定A1的软件可以完全不修改用于A2硬件”这是架构设计。

“决定A1的软件不经修改不能用于A2硬件”,这也是架构设计。

这两个定义,改变我的软件行为,比如用一个驱动支持两者,还是两个驱动调整两者。也决定我如何给用户承诺。这些提前的判断可以决定很多细节设计是否正确。如果你保证不了A1的软件可以不修改用于A2硬件,你做的接口兼容设计就是多余的,因为兼容了也没用,浪费设计成本,增加了没有意义的设计限制。

你的Hint方案说不通,比如你要求软件告诉你下一个请求要多久才会给出来,软件根本给不出你这个。你在硬件设计细节上自high,做一堆的设计,都是浪费时间,这层逻辑的设计,就是架构设计。

架构设计是一个“简单”设计。它的简单,是因为要让系统“可控”。一个系统“可控”的原因就是“简单”。你不能跟用户说:要计算你们班的平均分,你要按如下步骤操作:如下省略100000字的操作步骤……然后你就可以得到这个平均分了。——这需要用你的系统?用户拿笔出来自己算就可以了。没有这个简单化的过程和承诺,这种东西根本卖不出去。信息系统的作用就是用复杂的逻辑控制,去保证给使用者呈现一个简单的控制能力。

同样,你做一个A,要给用户提供一组功能。用户要能用,就需要简单的逻辑。你内部各种逻辑细节就必须被一个高层的逻辑所控制,没有这个控制,你给出多少细节都是对用户的污染。你对着我可以唧唧歪歪解释,拿着这里一个句子说“我这个有”,那里一副图说“我这个地址你没看到吧”……你到市场上看有没有人听你扯蛋?

但架构设计追求的简单做起来也可以呈现为非常复杂。还是说这个A,它有一个功能,要求一次通过MMIO写入32个字节的内容到设备中。作者一开始就没有考虑这个写入不是原子的,在我质疑后,就开始说各种先写哪个字节,再写哪个字节的时候,它的行为是怎么样的。但这个系统在我眼中还是不安全的。因为还可以发生我先写了一个字节,然后我执行其他操作会如何(比如我复位,或者修改一个配置),这一定可靠吗?这个地方没有推演过,没有人(包括作者)能保证它没有问题。这种情况,我就会要求有状态机推演。状态机推演这个行为,也是架构设计。状态机推演的工作量比一般设计大得多,所以,呈现为一个“复杂”的工作。但最后呈现给用户,其实就是“简单”:无论你怎么玩,这个系统不会玩脱,不会给你一堆要求:这不行,那不能……

这就是有架构设计和没有架构设计的区别。你说架构设计有什么样子看?有什么规律?它都是就事论事的。没有架构设计系统就是个混沌模型,有架构设计,就会形成很多的硬限制,这些限制能否被保证并成为细节落地,我们都不敢说,任何一个预判或者操作失误,结果都是“架构不好”。架构师没法“表演”,都在想着怎么活命呢,哪里有心思想着形象好不好看啊?

编辑于 05-29

文章被以下专栏收录