.. Kenneth Lee 版权所有 2019-2020
:Authors: Kenneth Lee :Version: 1.0
软件构架设计的入题角度问题
本文探讨软件架构设计在操作上如何着眼的问题。
最近评审了一个非常原始架构设计。这里说原始,是说设计的对象还没有现存的实现,十 划都没一撇,有非常高的自由度。这种设计特别凸显架构设计的重要性,更利于我们突出 软件架构的特征。我们从这样的设计谈这个着眼的问题。
我评审的这个设计给我一个非常古怪的感觉,就这么看过去呢,我总觉得哪看哪不舒服, 但具体讨论每个设计细节呢,你很难说它有什么不对。我需要先丢开一些细节,从一个整 体上讨论这个问题。
架构设计就是设计,它和我们接触更多的一般意义的设计的核心区别,仅仅就是:它离实 现很远。比如详细设计,你设计了有多少个.c, .go,.py,设计了这些文件之间的接口, 甚至你设计了一个函数的执行过程,这些“设计”,写成文字,图表等等,你很容易联想到 具体的那些代码会是什么样的。架构设计不同,架构设计离实现更远,而且道路很多,走 不同的道路,细节会完全不同。比如你选择用C还是Golang来实现一个功能,实现时面对的 细节就是完全不同的。更不要说你选择某个部件外购还是自研,基于已有的代码自研,还 是从头开始自研。这最后就完全是两个故事。
所以,我们选择从哪个角度来切入设计,维持什么利益逻辑链,这是架构设计要关心的核 心问题,我们不讨论某个具体的设计是否可行,因为陷入到这种细节上,我们的架构设计 就失败了。如果我们要写100万行代码,架构设计就写了100万行文字,那我们还做什么架 构设计呢?不如直接写代码。所以,我们就只能写比如5千行文字(只是类比),我们必须 在这5千行文字中描述最重要的东西,否则当然是失败了。所以,我们必须让整个架构设计 聚焦在端到端的逻辑链设计上,而不是某个具体的细节是否合理。细节合理不表示架构设 计合理。
架构设计关注的是道路本身是否正确的问题,而不是已经选择了道路然后以这个道路为前 提来讨论走快点和走慢点的问题。就算是对一个方向推演细节,目的也不是得到那个细节 ,而是证明这个道路是正确的而已。
确定道路的方法是维护利益链。而维护利益链,“端到端”这一点就显得很重要,通常我们 有两个办法保证它,第一是从最终用户观感直接向下推演,比如你设计一个鼠标,我们从 用户如何移动和点击鼠标,从而实现屏幕上的什么效果,后面对应上这个效果,逻辑链就 是(比较)可靠的。第二是镜像映射到一个被广泛接受的抽象层。比如你做一个水晶球, 模拟为一个鼠标,左右手点击水晶球,就是鼠标左右键,在水晶球上一定高度凌空挥动手 指,带动屏幕上的光标运动……这个输入法且不论靠不靠谱,只要用户可以接受,这个也是 端到端的,因为由于我们对鼠标的行为有可靠的认知,它在我们(这群设计和实现的人) 都可信的情况下,建立了一个可接受的端到端的关联。
其他比如实现了UEFI/ACPI接口,提供标准的指令集支持,我们认为基本上我们的PC就可以 支持Windows了,这也可以算是广泛接受的抽象层。但定义一个链表,和一个传感器事件的 格式,然后你说你这个支持鼠标了,这就很难认为是可信的了。
无论是哪种方法,我们都需要围绕利益链建一个可靠的概念空间。前面这个水晶球方案, 我们很容易联想:PC市场主要是Windows和Mac,它们都能支持开发鼠标驱动,只要保证水 晶球的硬件接口可以输入鼠标一样的传感器数据,这个逻辑就通了。但如果你这个设备还 需要修改Windows和Mac的调度方法,这就完全不同了。这样,我们就会要求你先定义你说 的“OS”到底指什么?你有这个依赖,但你的逻辑链不谈这个问题,这个逻辑链就怎么看怎 么不对劲。因为我们抓不住这中间还有多少破绽。
很多这些概念是需要细节的,比如这里定义OS,大部分时候,你是不能用教科书的定义的 ,因为架构设计说到底是个工程问题,你要支持Windows和Mac,说起来Windows好像是一个 对象,但实现的时候其实你要为Windows 7,Windows10,Windows 98提供不同的驱动的。 所以你到底是做某个子集的Windows的驱动?还是提供一个你自己定制的Windows?这大幅 改变整个工程的工作量和可行性。所以,要不你知道你的方法是可以跨不同的版本,要不 你就要细化这个定义,否则这个地方就会“不对劲”。说你不对,好像还是对的,说你对呢 ,其实背后有巨大的工作量没有被考虑到。架构设计阶段错过了对某个巨大的工作量的判 断,这个架构设计就不成功了。
找到正确的利益源头,确定了名称空间,我们剩下的问题就是如何一直把自己保持在利益 链上,避免引入没有意义的逻辑。还是这个水晶球的例子,你定义对这个水晶球鼠标驱动 的要求,你推演传感器的硬件接口,推演使用一个独立线程去收集,training数据,然后 转化为鼠标动作,这个合理,在利益链上。但你突然定义一个rule:每个事件的格式必须 是TLV结构。这就不对劲了——你引入这个限制是为了什么呢?太多这样的东西,读者就失去 原来那条端到端的逻辑链了,这个架构设计也失败了。因为我们做架构设计就是为了不断 选路和比较有没有更好的路的,你引入额外的限制,这个限制不在利益链上,我们不知道 它的是否不可违背的了。
——每个例子都需要用隐喻,累死老子了。但要看的人应该是看得懂的,先这样吧。