仓库源文

.. Kenneth Lee 版权所有 2018-2020

:Authors: Kenneth Lee :Version: 1.0

把什么放入架构设计


昨天讨论一个架构设计的时候,为一个主题争论( [1]_ )了有一个多小时,最后对方有没 有真的接受我的观点我也不能确定。这个问题非常有趣,我在这里整理一下思路:

.. [1] 我这里说争论纯粹是指技术上的真理探讨,不是不少人喜欢想的各种意气之争

这个问题是:到底什么要放在架构设计中,什么不用。

我之前的博文中也讨论过这个问题,在那些地方,我经常耍“架构师眼中的设计就是架构设 计”之类的嘴皮子。

但在这个实际的讨论中,大家都是架构师,那么“我觉得这个东西应该放到架构设计中”,“ 你觉得这个东西不应该放到架构设计中”,那么,我们听哪个架构师的?这里有什么原则吗 ?

对于这个问题,首先我们可以达成一个前置的共同认识,就是架构设计永远都不可能完全 规定代码是怎么写的,因为真正可以完整说明代码是怎么写的方法是把代码写出来。否则 必然是不严谨的。这个问题的详细讨论我在这里也讨论过一次了:有没有人能画出《三体 》里太阳系被二维化的概念图?。所以,追究谁写得更严格这个问题没有意义,我们追究 谁的选择更好。

每个架构师有不同的方法来选定需要约束的特征,这些特征哪个更重要一点,见仁见智。 它又不是百分百控制了后续发展的所有逻辑,你说谁的可能性会高一点,能证明这东西的 成本大部分时候都比等这个事情直接发生的成本还高。所以,如果最终两个架构师有分歧 ,那就只能是谁官大谁说话,或者一起找上级或者技术委员会之类的来决策喽。

但丢开这些管理性的逻辑,就从理智上,或者像在这里说的《:doc:诚其意 》的那样, 就自己和自己比,自己要决定把一个东西放到架构设计中和不放到架构设计中,我们选择 的依据是什么?这个问题我也没有严格的定义作出判断。

比如我们昨天讨论的问题是:代码必须开源,这个约束,应该放到架构设计的约束中,还 是不应该放在架构设计的约束中?

有一方持的观点是“必须放”,我持的观点是:你要放也可以放,但我觉得“没有必要放,放 了也是多余的”。(当然,我们的重点不是为了讨论这个问题,而是用这个问题引出其他更 多的约束是否需要放进来)

对方的论据是:代码需要开源,这是不是个要求?答案是“是”。既然是“是”,为什么不明 确提出来?不提出来执行的人怎么知道?

我的论据是:代码用C写的时候,写完必须链接,这个是不是要求?答案也是“是”。既然是 “是”,为什么你写“开源”这个约束,而不写“C写完以后必须链接”这个约束?

你不要跟我说这是天然的,因为我完全可以源代码交付。比如Nvidia的Linux显卡驱动就是 用的时候再编译的。

什么才是我们必须引入的约束?为了讨论这个问题,我选择一个更容易有共识的例子来讨 论:比如我们打算去一趟省城,我们如果要提前准备,我们会在我们的记事本上记上什么 东西呢?我猜大部分时候在这个问题上我们会这样记录:

去省城的车7点发车,必须赶上11点前最后一班车才能保证到省车站还有公共汽车。到了省 车站以后坐5路公交可以到目的地。目的地是一栋蓝色的30层高楼,从公交站台对着高楼方 向直走,穿过两条马路就可以到。

我们应该不会选择记录这些事情:

去省城需要坐长途汽车长途汽车每天发3趟车公共汽车上有座就坐着,没有座就站着……

后者也都是事实,或者需要执行,但我们的记事本上不记这些东西。那么这里我们选择的 依据是什么呢?

我觉得有两个:

这是一个动态的信息,比如选择坐几点出发的车,到细节执行的时候再考虑具体坐几点的 车,就没有决策依据了。这个信息是构架设计过程产生的。( [2]_ )这个信息在细节执行 中有需要。我们记事本上的那个推演,计算几点出发才能保证到达后还有公交可以坐,但 这个车要走多久,这个信息在执行的时候是不需要的,这个就不在我们的记事本中。

.. [2] 关于这一点,可以参考这里:计算进化史 (豆瓣),其中提到了康德的先天判断和 后天判断的区别。 构架设计产生“后天推理”的结果。

另一方承认这一点,并由此得到这样一个结论:他认为我提出的是一个“设计”的要求,而 不是构架的要求。所以我们这个产品的“开源”是“架构描述”的一部分,而不是“架构设计” 的一部分。

考量这个描述,看起来我们的分歧看来是这样的:

对方认为的架构设计的信息是一层层的,每层都应该是下一层的全集:

    .. figure:: _static/fullset_req.png

他也不见得排斥高层设计只是部分的约束,但他认为每层设备应该把本层增加的约束和之 前的约束的无损转化全部交给下一层。换句话说,架构设计(或者他定义的构架描述)任 何时候都是我们所掌握的信息的一个全集,包括架构设计产生的后天信息和原来直接收集 到的所有先天信息。

而我的观点是这没有必要,已经在原始约束中的东西,下层设计直接去拿就可以了:

    .. figure:: _static/partset_req.png

这还真说不上谁对谁错,但在实际操作上,对于大型产品,团队复杂,合作众多的产品, 前一种方式,我觉得是过于理想化了。作为学院派的描述可以,但用来做产品,可能成本 高企,最终落实不下去。因为我们从原始需求上拿到的是一个粗糙的描述,要确认这个描 述,在下层设计的过程中,我们还需要进一步的和需求提出者的互动。如果我们认为高层 设计可以取代这个互动,这是人为制造信息流动的瓶颈,这对最终的产品竞争力是不利的 。

所以,我会认为构架设计并非把需求作为一个全集收录进这个设计步骤,然后给一个全盘 的约束给下一层设计,而是一个独立的设计逻辑,它引入一个高层的的需求,然后对这个 高层抽象进行设计,从而对下层设计引入额外的保障逻辑。这也是4+1视图希望达成的目标 。大家可以看到4+1视图中,任何一个视图,都没有包含需求信息的全集,而仅仅是控制其 中一个“抽象”。

讨论区不少人关心这个问题的具象,而不是我讨论的抽象。那我就把我们的具象说得更深 入一些吧。构架上选择用开源,这当然需要在设计中表述出来。对于我们这个产品,主线 开源这个战略甚至是我6年前一手确定,并且手把手操作出来的,第一波的上传代码也是我 写的。但我今天做它的构架设计,我却不认为“开源”是构架设计的一部分,你想这是为什 么?

因为我们这个产品今天开源是市场销售逻辑的一部分,而且不但要求主线的开源代码支持 这些硬件和特性,同时也要求在各种商业的OS中支持这些硬件和特性。这个产品的部署已 经展开,在各个客户场景上应用。这些应用场景会有很多非常细节的要求,比如在某某商 业版本上支持某某特性,在开源某某版本中实现某某功能。这么多软件的开发由一个非常 大,而且多部门协同的团队来完成。如果我们要求所有这些需求都经过一个统一的架构组 来审核,这个架构组就会成为整个开发和市场响应的瓶颈。这就是为什么我上面更认可第 二种架构管理的方式:我们的目标是让架构组可以聚焦到一大群打仗的开发团队忽略掉的 ,长远来说非常重要的逻辑上,给开发团队在满足需求市场一线不断发生的需求的前提下 ,引入额外的约束,从而制造长远的竞争力。这种情况下,你告诉我,简单的“开源”这个 需求是否还应该成为架构约束的一部分?

其实我还想说,我并不认为这些补充对本文是必要的。你要看懂架构设计,就应该学会单 纯站在已知的信息上推演逻辑链,要在抽象上思考问题,而不是看到一两个特征,就认为 和你身边的某见事情一致,然后就有种种的结论了。对于本文的逻辑,我们只看到“开源” 这个名字“没有设计逻辑链”,我们不关心对于你身边某个特定的产品,“开源”也可以是构 架逻辑链的一部分。不能用这种“所描述的约束范围”思考问题,抽象永远都会被你做成具 象,然后你就没有所谓的架构抽象了。我过去批判《弟子规》,批判唯《编程规范》论, 批判部分芯片设计师完成一个设计就说“软件不就是这样那样,肯定能搞定” ( [3]_ )……都 是在批判这个问题:你要具体问题具体分析,不要看到一个逻辑就觉得这只有唯一的推论 。看到开源就是必须是构架要求,看到goto就必须禁止,看到《编程规范》就要求整个组 织所有人都执行……他么动不动脑,调不调查具体问题啊?

.. [3] 对,夏工,这句话就是给你看的哈:),没有对逻辑空间做过建模,没有建立从需 求到实现的逻辑链,我做软件的都不敢说某个方案是可行的,你就敢跟我说,这个 问题肯定能搞定?你知道吧,每次听到这种表达,都不知道你们的自信是从什么地 方来的。