我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)

阅读数:22 2019 年 10 月 12 日 17:05

我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)

我们还没有讨论过关系的复杂性 m。这一论题的重要性在于:如果它是确定的,则我们上述讨论的“除层次的可变部分之外的”其他所有部分——无论它是何种结构形式,都必然确定;否则“(层次结构的)不变部分的复杂度是 1”将成为伪命题,而层次结构也必然无法降低系统的复杂性。

所幸,这些可被讨论的关系是有限的。这在《程序原本》一书“第 18 章 系统”中就曾经提出过10:任意领域的系统对“当前系统”的需要只有两个,亦即寻求计算资源,或寻求数据资源。回顾此前的讨论,若 A 需要 B 的数据资源,我们称为数据依赖;若 A 需要 B 的计算资源,我们称为逻辑依赖;若将 A 和 B 都视为逻辑(亦即是可计算的资源),并讨论二者之间的关系,那么我们就会看到(逻辑或数据的)时序依赖

10 参见《程序原本》第“18.4 聚焦领域之于系统的主要需求:维护状态或接受消息”小节。

这些“有限的关系”的复杂性 m 如何呢?

首先,并列结构之间是不应存在关系的——这与我们此前设定的并列结构的表达原则有关。如果它们所表达的领域之间的确存在依赖(如图 36a 所示),那么事实上可以将被依赖域下沉为一个独立层次(图 36b),并使其他域基于该层以使整体表达为层间(向下)依赖关系(图 36c)。

图 36 并列结构之间的依赖

我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)

层次结构中会存在向下的关系,这可能来自于两个方面:其一是上述因领域到层次的转置而导致的,其二则是层次结构的内在属性。后者缘于层次结构形成的时序性(参考图 35):其上层的“层次(可变部分)”总是晚于“层次(不变部分)”而形成的,因为它们总是“目前看起来可变(的那些部分)”的一个集合。那么,就其形成逻辑而言,若未知部分不与已知部分发生——任何可能发生的——关系,则未知部分必然可以不属于系统整体,也必不对系统整体确定性构成影响11

11 可以理解为:向系统追加逻辑,而它们不依赖底层系统时,这些新的逻辑只对系统规模构成影响,而不影响原有系统整体的稳定性——例如我们可以将新的逻辑独立于原系统部署。

因此对于未知部分,若它确是层次结构整体的某个部分,则必然有向下的关系。然而反之,在层次整体的“可变部分与不变部分”之间,向上的依赖是不应当存在的。因为若存在可变对不变的依赖,那么它事实上就等义于已知对未知的依赖——这与“已知”这一概念正好相悖,也必是不确定的12

12 进而也会破坏由确定性带来的稳定性,持续性等架构特性。

在“层次(不变部分)”内的各个层次间,(同样是基于时序性,)向下的依赖关系也是必然的。但是反之,向上的依赖关系则不一定。因为无论如何,既然这些层都是确定的、不变的,那么它们之间的关系——若存有相互的依赖——也必是确定的、不变的。所以就其时序性来说,层次的内在性质是容许向上依赖的。

但是,向上依赖并不会因为层次的时序性而产生——以如上的讨论来看,层次的形成时序与确定性需求构成了一个(严谨而完整的)逻辑,这导致层次间只会存在向下的依赖。我们之所以必须讨论向上依赖,是因为它可能会来自于一种相互依赖关系13:我们“同时”识别到两个领域,这两个领域确实相互依赖。这种情况下,我们如果试图将领域转置为层次,那么层次间也就必然有两个方向上的依赖关系了,如图 37 所示。

13 我们讨论的是“如果确实具有这样的关系”,那么如何在层次中予以处理的问题,而非鼓励这样的关系。

图 37 将领域转置为层次带来的依赖关系

我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)

我们先讨论两种时序依赖关系之一14,即 A 和 B 间存在相互的数据时序依赖关系。若 A 和 B 是各自依赖了不同的数据而导致这种关系,则可以将 A 中的数据抽离至 B15,如图 38 所示;或将 A 和 B 的数据都抽离出来并因这些数据已知而置于底层 Z,则可以避免上述依赖16。若 A 和 B 依赖于同一数据在不同时间的值,那么事实上它们是依赖了某个(相同的、底层的)数据层次并且 A 和 B 存在时序的逻辑依赖。

14 注意我们并没有讨论“同时发生相互依赖”的情况,若 A 和 B 间不存在时序性,则似乎它们并不应当被拆分。以咬合的齿轮为例,若分离二者则齿轮之间的互动性全无;仅当视它们是一体时,才会存在“同时相互依赖”的逻辑。

15 由于向下的关系是系统中既存的,因此不必讨论从 B 抽离至 A 的情况。

16 方案的选择取决于成本,例如考虑网络开销或数据重构与存储的开销。

图 38 层间依赖:对数据时序依赖关系的分析与解构

我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)

接下来我们讨论第二种时序依赖关系。如果 A 和 B 间存在相互的逻辑时序依赖关系,那么我们总是可以通过添加一层数据抽象,来将向上的逻辑时序依赖变成“数据的”时序依赖17。由此将只剩下一个向下的逻辑时序依赖(并添加了两个向下的数据依赖),如图 39 所示。

17 参见《程序原本》一书“第 16 章 依赖”。

图 39 层间依赖:对逻辑时序依赖关系的分析与解构

我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)

可见这两种情况(图 38a 与图 39a)中产生的向上依赖 mx 都是可以被消化掉的。并且,对于图 39b 中的逻辑依赖 m1,依然可以通过再添加抽象数据层次来变成数据依赖,如图 40a 所示。并且这样一来,我们会看到一个结果:A 与 B 之间不再有依赖关系,且 Z 与 Zn 之间也不再有依赖关系。那对于这些并列的层次 / 域,也是可以归并在同一个层次之中的(如图 40b 所示)。

图 40 层间依赖:归并

我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)

由此得出的进一步的推论是,上层对下层“可以”仅有确定的数据依赖关系:下层对上层的调用,总是可以通过数据的下沉来避免;多层之间向下的调用,可以通过公共数据层来避免。这是一种理想状况18,也是“逻辑-数据层”这种两层基本结构的由来。

18 绝对的数据与逻辑分离可能导致数据规划、迁移和转送的成本失控。同时,也会导致逻辑间需要维护更多的状态或消息,这一定程度上增大了复杂性(尽管仍然是确定的)。因此,在现实的多个层次之间,通常是既允许向下的数据依赖,也允许向下的逻辑依赖的。

然而还有最后一种情况,会对这种理想化的层次结构设计造成一定的冲击。这种情况发生在将嵌套结构转化为层次结构时,其“核心部分”必然位于底层——因为它是可确定的、可预先确知的。如此一来,在这一层中必然存在底层向上层的关系,如图 41a 所示。

但这个关系 m2 究竟是什么关系呢?如果我们将 D…Z 都视为逻辑,而 A’(作为包含内部关系的核心过程)就必然会发生 A’ 到 D_Z 的逻辑依赖。但是,我们也可以将 D…Z 都视为数据19,这也就意味着 A’ 依赖于“未确定的或动态增减的数据”。这是容许的,因为这只需要一个注册过程,以便将数据动态地置放到底层即可,如图 41b 所示。

19 注意,这里是将它们“视作数据”,而非“通过抽取数据层来消除逻辑依赖”。所谓“视作数据”,是抽象概念上的重新定义,请参阅《程序原本》一书“第 3 章 抽象”。

图 41 层间依赖:对嵌套结构转化为层次结构的处理

我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)我的架构思想(三十四):架构是过程,而非结果——架构的表达与逻辑(化繁为简:控制架构的复杂性)

这样一来,向上的逻辑依赖 m2 就变成了 A’对Z(动态数据)的、向下的数据依赖 m0。对于 A’来说,**Z(注册逻辑)是确定的,并且 A…C 与Z(注册逻辑)** 之间的关系确定,因此 A’的整体也是确定的20

20 事实上还必须讨论 A…C 与动态数据之间的关系,这取决于“引擎 / 框架”等具体方案。一般来说,这一关系也是确定的,例如调度关系,又例如设计模式中的策略、命令等。除了 Z(注册逻辑)之外,在对动态数据 D…Z 的使用上,还应当考虑安全性、稳定性等因素,但这些都取决于“框架”的详细设计,并非这里讨论的架构层次规划的问题。

评论

发布