仓库源文

.. Kenneth Lee 版权所有 2021

:Authors: Kenneth Lee :Version: 1.0 :Date: 2021-07-05 :Status: Release

:dtag:架构设计案例

一个架构评审案例


介绍

本文是一个真实的架构评审意见,是我为某个具体的架构设计文档写了。它的问题很典型 ,有利于我们更清楚架构设计的重点,所以做了一些概念的替换,以隐去和产品和具体技 术细节,记录在这里充实我的架构设计案例库。

评审原始意见记录

在提具体的意见前,我们先解决一个思路上的问题:很多人对于增量开发,特别是基于开 源软件的增量开发,完全不知道怎么做架构。这是对架构和逻辑的本质没有清晰的理解导 致的。

设计本质就是逻辑组合,就是:"这里要这样,那里遇到某某情况就要那样,所以,最终你 就在那里得到那样。”这样的逻辑链的组合。无论是软件的设计,还是硬件的设计,甚至是 生意的设计,都是这么个套路。从其中一个输入条件的视角来看这个问题,设计就好像一 个弹珠子机,条件就是那个珠子,每个障碍物就是逻辑链上的一个转折,最后珠子在哪里 出来,就看我们怎么部署这些转折。比如你输入一个字符串,如果这个字符串有%x,字符 串这个部分会变成一个值,然后这个字符串碰到locales数据库,最终映射出另一个国际化 的字符串,然后它们被字库处理,变成一组矢量,然后交给渲染模块,又变成offscreen上 的一组点阵……

这个过程,你用硬件做还是软件做,在一个节点上做,还是在多个节点上做,可以完全没 有关系。转折的量是设计的规模,我常常把它称为一个设计的信息熵。

现在回到增量开发的问题,你拿到一个开源软件,如果你什么都不做,这个软件本身就具 有一组转折,包含大量的信息熵。但这个事情和你无关,这是人家干的活。但你在上面加 东西,你也会产生新的转折,你也有你的逻辑,你的逻辑也会有自己的发展特征,这时, 你就会有你的设计。所以,当我们说一个增量开发的构架设计,我们谈的是我们增加的逻 辑是怎么被控制的,而不是原来的开源代码的构架是什么样的。

当然,增量设计的构架和基础系统的构架息息相关,这让它的架构设计会和非增量开发的 架构相比有很多独特的技巧和特征。为了理解这一点,我们要简单谈一下什么是架构。

架构是高层设计。我们刚才说了,设计其实是一组逻辑的组合,那么架构就是其中稳定性 最高的逻辑的组合。比如你建一个房子,你本质上不是在建房子,你其实是在码砖,上浆 ,打地基,磨大理石……如果没有一个统领这些行为的逻辑定义,你直接就天天码砖,最终 这个房子能成吗?这时你就需要一组统领逻辑(也就是我们在架构设计中说的“高层逻辑” )来指导你每个具体设计\ 什么不能做,什么时候才开始做,做到什么程度可以停止 等等。

所以,架构设计不是有人告诉你一组规矩,然后你按着规矩写上一些图表,说一些正确的 话,就叫架构设计的。这是把架构设计当细节设计了,在等着别人告诉你 什么不能做,什么时候开始做,做到什么程度可以停止\ 。 这样写出来的架构设计,完全不包含有效的信息熵,和没有写一样。

架构设计的目的是在高层上建立一个“\ :doc:逻辑闭包<逻辑闭包>\ ”,定义你的目标, 然后我们看看,这些目标是不是我们的核心目标,有没有逻辑余地可以节省,有没有冲突 需要权衡。然后我们定义其他的控制要点,保证这些要点被控制了,目标就能得到保证。 这样就完成一次“\ :doc:综合<综合>\ ”,我们用这种方法扫清这个逻辑角度上的逻辑冲 突,这样我们等待细节的时候再犯错误的机会就大大降低了。所以,架构设计从来不是“样 子”,而是清楚地展现这个“逻辑闭包”,让我们可以在这个空间中反复权衡,指导我们的细 节设计。所以,架构设计没有“这样写行不行,对不对”这种说法的,架构设计问的是“这样 一个逻辑,考虑周全了吗?根据经验,这几个控制点足以控制目标得到实现了吗?”

对于增量设计,你是在原来的转折上加转折,你有可能把转折嵌入到原来的转折中,有可 能依赖原来的转折设计一套独立的转折,甚至基于变化的原转折设计动态的转折。这些转 折的维度也是千变万化的,但一个很重要的设计可能是:你如何控制原来的逻辑的变化逻 辑。比如你基于Linux内核实现了一个操作系统,但Linux内核也在变化,那么,你的逻辑 和Linux变化的逻辑是什么关系?这个动态的关系,就是增量开发要面对的第一个问题。但 如果你从逻辑(转折)的角度来想这个问题,这种逻辑也是逻辑。你设计的转折要响应 Linux内核的变化,和用户在屏幕上输入不同的序列产生的变化,本质没有没有区别。所以 ,控制增量设计的逻辑细节变化,使用的手法和非增量设计,本质是一样的。只要你总从 逻辑转折的角度来看待整个设计,就不会被这种表面的不同迷糊了眼睛。

好了,我们现在可以回到XXXXX Linux产品这个构架设计本身了。首先我们看目标,它这样 说的:

我先不看别的,这个集合首先就缺了一个基本的东西:这是一个Linux发行版吗?这个 Linux发行版里面有什么?你看,这不是你的目标集合中,最最基本的东西吗?它是个什么 都不知道,可信?可信什么呀?什么东西可信啊?是不是如果某个功能做不到可信,我就 可以把那个功能干掉啊?

当然,我也不是说你应该把Linux的全部功能都列出来,但你应该先用一个抽象把这基本的 东西把它覆盖了再说对不对?丢掉这个最大的需求,你的“逻辑闭包”里面的逻辑怎么会稳 ?就好像你的战略沙盘上插满了旗子,但连地形都没有,那你怎么会想得清楚这个仗应该 怎么打呢?

有了这样的需求,我们才会想这么一个基本的下级约束:我们要做一个服务器Linux,这个 Linux怎么开发出来?一开始你可以从Debian clone,但clone之后呢?Debian每天升级, 你升级吗?你怎么升级?Debian每年投入人力去维护旧特性和新特性,这些投入对我们是 多余的吗?无论是不是多余的,你的高层逻辑是不是要把这件事情分析一遍,把多余的理 由给出来,然后不多余的部分,你要给个应对策略?

你看,背上这个大包袱,你那些可信,高性能的目标才是真正的挑战,否则一个死的 Debian的可信,这有什么难的?这里我们就看到了“逻辑闭包”的重要性了。你提一部分, 不提一部分,看起来设计还头头是道。只有定义一个全集,你才有可能从中挖出没有提的 概念,这才是高层设计,否则编码就行了,高层啥呢?

“逻辑闭包”从目标开始确定了每个条件的约束力,如果我们通过要求每年Rebase Debian保 证我们的竞争力对标Debian,后面我们由于其他条件进来了,做不到这一点,我们要移动 这一点,我们就可以知道我们要重新定义会改变哪个目标。这样我们就可以比较两个冲突 的目标哪个更重要,从而做出正确的取舍。从这个角度来看,你看看你的“假设和约束”:

这些约束的条件在哪里?我不反对为了简化做一些无条件的直接约束的,这是一种权衡, 但你这里明显不是那种“某个问题对设计影响很大,而我又没有时间去进一步确认,所以还 是先硬定一下吧”的问题,那么加这些约束其实就是做样子:既然让我写假设,我就写几个 需求上去呗。这是充样子,离开设计了。

后面的“版本定义”,“通用架构原则”等章节,全是这样的,全是这种我称为 “\ :doc:铁锁横江<三个锦囊>\ ”的要求: “没有理由,我感觉这样挺好,我从别人那里也看到有这种规定了,所以我也写一个”。这 种要求没法权衡。这就怨不得很多架构师根本没有信誉,反正执行者信你也执行不了,所 以你架构设计就随便吹,具体编码该啥样就啥样。这种架构设计也是样子货。其实,我甚 至不反对你定义这样的要求:“监管结构XXX对可信有一套官样文章,我们在代码合入前必 须由安全专员对代码进行Lint,保证符合该Check List”。这个Check List可能其实没有什 么用,但它仍是一个我们必须执行的约束。

然后我们看你的“上下文模型”,硬件和OS间有IF_NET_PORT,IF_HARD_DISK接口?那为什么 没有IF_USB_PORT接口?

请注意我在强调什么:架构设计永远不是信息的全部,我并不认为你可以表述所有的接口 ,但你突出一个接口,就是为了支持某个逻辑链的“分类”,是为了说明白:如果是这种情 况,我们就如何如何,如果不是,那就另外再如何如何。但你这个上下文这样抽取接口的 抽象,对后面的逻辑链有什么帮助吗?实际上,我就没有看见你后面再提起和这个分类有 关的逻辑了,你说这是不是样子货?

再看用例图,用例图是4+1视图中真正的上下文图,是为了说明什么功能(还记得吗?就是 我们前面提到的转折)算谁的。你这个Use Case图,连边界都没有画呀,而且你这个也不 构成逻辑闭包(还记得吗?逻辑闭包是我们针对某个目标,给出实现这个目标的全集), 你没有在描述:“我要达成某个目标,所以我做了一个什么东西,这个东西必须放在系统的 这个位置,它里面有A, B, C这些功能(Use Case),它要发挥作用,要和用户,环境和其 他实体(里面也有Use Case)互相协作,所以我才有了这个东西。”

后面的设计我就不一一指出了,你的设计,都是写一些“像架构设计”的东西,话说得很多 ,但实现每个具体功能的人根本不看。glibc依赖IF_FILE_MANAGER,这个东西要告诉谁? glibc要依赖什么,是你可以改变的吗?libm-wayca加进来和你的定义一致吗?你定义了一 组“现在好像反映现实”,其实根本经不起变化,对具体设计没有任何指导价值的东西,有 这功夫,不如直接去在glibc里面加个memcpy优化,浪费这时间干什么?

最后,我想提醒一句:你还记得你一开始提出了那些可信的目标了吗?实现这些目标的逻 辑链在哪里?这些目标是靠做什么动作达成的?然后你再来告诉我:你定义这些目标的时 候,是认真的吗?

实际上,这个设计发给我的时候已经是第十四个版本了,可以想见,设计者花了很大的功 夫,但方向错了,这些设计其实没有什么意义。这一点,也恰恰表明了架构设计有多么重 要,因为你是指导别人前进的眼睛和大脑,一旦你看错了,大量的资源就被浪费了。我是 建议,我们做架构设计,要为自己做,不是用来给领导好看。