《我的架构思想:基本模型、理论与原则》编二——架构是过程,而非结果

架构师的能力结构

组织视角下的架构师角色

架构作为一个实施对象,是有明确的实作和理论上的好坏的,并且它必将作用于一个以现实系统为对象或需求的架构目标。而架构师是以组织整体及其决策过程为背景的、实施活动中的角色之一,因而首先是以组织行为为核心的,其次才是将“架构”作为目标的优劣判别。

因此决策过程具有两个方向上的问题,其一是以架构目标为对象的,其二是以组织行为为对象的。因为架构目标的特点不同,所以这两个方向并非恒等。

如果架构可以由“一个人”来做,那么由架构意图驱动的架构决策过程将会相当完美。而这个“架构师个体”也必因上述的原因,只需要在架构与其相关领域中有丰富的经验与技术能力即可完成这一过程。事实上,这是软件产品开发中的常态:一名架构师决定整个的系统分析、架构与设计过程,并负责在这一软件的后续产品阶段中对这些原始决策加以修正

这时,架构师的个体能力往往决定了一个产品实施过程的推进。这一模式可以应用于大多数的软件产品开发过程中。

架构师的能力模型

作为一个“规模”的用词,系统是一个“领域集”;即使将这一领域聚焦到“数据+算法”这样的软件开发本质工作中,(在大型系统中)也被具体分成多个领域了。一旦在系统中出现跨领域和领域细分,也或者说这样的背景就是我们将“系统”作为一个规模设定的本质,那么架构也就通常是一个人无法完成的了。

因此,在这个系统的解决方案——某个具体的项目中,团队中需要一个架构团队来处理架构方面的具体实作:实施与推进

p-8.png

  • 领悟,主要包括架构思维的三个核心能力:“概念抽象能力、概念表达能力和基于概念的逻辑表达能力。”
  • 领域,是架构师在目标系统中的背景知识。架构师需要相当的背景知识,才“能够”对目标系统进行恰当的概念抽象,也才“能够”准确把握系统的内在动律与整体动向。
  • 领袖,是架构师在领域内和团队内的影响力。领袖能力与领导能力略有区别。后者(即领导能力)主要是在组织视角下对管理者(manager)这样的角色,在其职能、责权与实施能力上的说明;尤其重要的是,就组织的必要性来说,是希望限制领导角色的影响力范围的,跨责权范围的影响力是对领导职权的一个质问。而前者,这里讨论的领袖并非是一个组织角色,而是指架构角色所形成的、超出组织结构的影响力,其主要表达为方向、决策和对团队向心力的把握。

这一模型由思维知识行动三个方向的能力构成。总的来说,个人能力的不同取向决定了他在组织中的职业倾向,而架构师所需的是在三者中相对平衡的一种整体能力。

p-9.png

当从领域专家这一方向上衡量时,在领域方面的背景知识(一定程度上)反映了他可以应对的架构的规模——之所以选择从领域方面进行考察,是因为“领域”是在架构师团队中进行分工的一般标准

p-10.png

三个方向上的能力在整体上是平衡的,如果架构师偏向于强化领悟能力而弱化其他,则由于在领域能力上的缺失,其架构思维趋向于理想化,偏于学术;又由于领袖能力的缺失,导致他在决策过程中丧失发言权,或有言无行,疏于实作。类似的,片面强调领域能力,则与工程师无异;片面强调领袖能力,则必将碌碌而难有所为。

p-11.png

当“架构”被作为计算机系统的一个领域时,该领域也必然具有自己特定的知识,也必然具有自身的系统性需求。因此,“架构整体”作为一个系统性的目标,仍然是存在自身在“目标、规模与实现”三方面的需求,仍然需要架构角色。

架构决策

“架构整体”的决策涉及团队管理中的几个问题:

  • 对架构师团队与技术团队的评估;
  • 适时地中止讨论并形成架构决议;
  • 对实施过程有效跟踪并适时发起调整过程。

参考格拉斯问题解决模型,整个架构推进过程还涉及两个时间方面的决策:

  • 何时能确定架构解决了系统的核心问题并可以进入实施推进环节;
  • 一旦实施中发生变更,确定该变更应当在何时予以满足。

p-12.png

该模型应用于一个开发实施场景中的具体架构决策过程

p-13.png

这一复杂的决策过程是由多个架构师角色参与的,但其决策者必是其中“以架构整体为目标”的架构师。

有价值的决策是对意图的响应

所讨论的系统的规模已经扩展到多个领域,因此需要由架构师团队来处理它的架构需求。进而地,多个领域之间的——系统本身的——问题作为一个独立领域仍然有自身的架构需求,因此我们提出了系统架构师或平台架构师等规模来应对之,并(根据其领袖能力、可能性地)赋予其一定的组织责权,例如“首席架构师”或“主架构师”。

这一架构角色面对的并非上述系统各个独立领域内部的问题,而是“架构整体”的问题。

架构有两个效果方面的考量,即它对时间需求空间需求的响应与收益。

  • 其一,若架构不谈时间需求与空间需求,而只谈目标需求,那么“架构整体”就必将等效于“各种架构的全集”。然而,若这个全集的元素之间没有关系,也就无法构成整体,进而“全集”这一观念构成了对架构整体性的破坏。
  • 其二,如前所论,架构是可以通过解决问题来实现需求的,而非单纯对需求的响应。若架构本身只谈上述全集的“目标需求”,那么也就无法触及其背后的“问题”;而时间需求与空间需求背后的问题是清晰的,即系统的规模与复杂性。
  • 其三,架构本身的价值在于:在保持方向的同时控制成本。而架构在时间需求与空间需求上的考量,构成了“架构全集”到“架构整体”的价值提升。它使得架构可以通过在时间与空间上的分解——一般表达为架构阶段(以及对应的实施阶段)的迭代——来解决架构规模问题与复杂性问题,进而达到成本控制。

团队模式下的决策与个体决策有很大的不同。团队决策考虑的对象有两点,

  • 其一是对架构整体的把握,
  • 其二是对团队整体的把握。对前者的思考,仍然可以归于架构意图,是由领悟能力驱动的;而后者则可以视为对架构意图的效果的保障,是由领袖能力所驱动的。

系统架构与决策

系统架构的提出

针对系统架构的架构意图,我们仍然可以提出如下设问:

  • 其一般过程是什么?
  • 其可能的演化方向是什么?
  • 该系统对于客户战略作何种响应?
  • 什么是系统的本质问题?
  • 能不能不做?

形成论:参考模型 M0 以及可参照的示例

任何系统架构必存在其外部实现内部实现的过程。所谓外部实现,即是指架构师团队用以形成与演化架构的过程,所谓内部实现,即是架构以及其部件的内部关系得以构建与维护的过程

p-14.png

这张图已经表达了一般过程中的限制条件与流转关系,但仍然需要强调两点:其一,在“实现架构”与“开发架构”中,分别只列举出了其中最重要的两个组成部分,这并非其全部;其二,在“实现架构”中只列出了运行架构与集成架构,其原因是它们对部署与开发的约束作用最为明显。

一个架构的有效性、正确性应当表达为:

  • 如何确保宏观规划层对需求映射层的约束,以及确保功能架构对开发架构的约束;
  • 如何确保在将能力架构映射为实现架构时不丢失功能设计;
  • 如何确保开发实现的结果能够被应用于预设的交付环境。

参考模型 M0:细解各部分的形成过程与关系

p-15.png

框架是一种动态的运行架构(dynamic view of process architecture)。运行架构被框架层和服务层分为了动态与静态两个部分,这取决于你以何种视角来观察这些部件。

p-16.png

“通过什么来影响什么”作为一般过程是可行的,但不完备

p-17.png

  • 功能架构:它是实现架构中的组成部分,把由能力架构映射而来的能力分割为基本独立的功能块,基本映射了用户的原始需求,并约束了开发架构中的功能模块。
  • 运行架构(静态部分):将这些功能包装并发布成服务,用以约束开发架构中的包的组织与接口的设计。
  • 运行架构(动态部分):选择或实现可运行框架来驱动服务与功能,基本约束了开发架构中可选的第三方应用服务器,以及应当自主开发的、系统中的关键联接件,如事务服务框架等。
  • 集成架构:以产品来封装和交付可运行框架,基本约束了部署架构可用的部件,以及部件之间的组合、依赖等关系。

系统架构的一般过程:

p-18.png

平台与框架的极致是“做到看不见”

一个架构总是对它的构成部件在边界与联接件两个方面的设定。所谓设定,即是明确边界的范围,或明确联接的方法。然而,架构的主体——系统本身,却是动态地基于现实系统而演进的。

就“系统架构”这个领域出现的本质来看,它就应当具有两点特性:

  • 它能反映系统长期演化中的不变性,以在演化过程中持续用于对系统的讨论;
  • 它不能是系统阶段实现的负担。

显然,系统架构的作用与其方向上构成了一对矛盾。但是在我们的实践中,这个矛盾是有解的,亦即所谓平台(platform)框架(framework)。

这两个解,也是对系统架构中的“体系架构”的两个抽象。首先,架构的支撑性应当以数据为核心,也就是说,平台通常是围绕数据的位置、功用、生存周期或其分布特性来规划的,例如常提到的三层结构在本质上就有平台化的倾向,因为它明确了交互数据、应用数据与系统数据在三个层次上的位置,以及相互间的产生、转化过程。其次,架构的调度性应当以逻辑为核心,也就是说,框架应当追寻架构对象——系统——的一般过程,并将它实现为架构的核心调度逻辑。

若系统架构以平台为方向,则应当力求“大到看不见”;若系统架构以框架为方向,则应当力求“小到看不见”。所谓“看不见”,就是指该架构的存在不应当对系统的其他部件(例如对应于不同的领域的子系统)的实现构成影响。

无论是做平台,还是做框架,最终的目标都是让系统基于它或使用它,而又无视它

层次结构是架构的一种平台化表现方法,而非架构本身

平台是用于整合资源的,这是由平台本身“面向数据”这一特性而决定的。平台的核心在于支撑,这意味着平台(或平台中的层次)对数据的持有是独占的——在同一平台中对数据的理解是一致的。如果不具有这种特性,那么应当增加一层数据抽象,并在该层次上再构建新的平台。

三层或更多层,并不是平台化。层次是平台化的一种表现方法,而非平台——作为架构意图的本身,也并不是平台在应对战略问题中的核心关注点。

形成论的另一种求解:架构规划

“系统”的本质是领域集。若以现实系统为各个领域的目标,那么系统只需实现目标需求即可,亦即本质问题将是“能或不能实现”的问题。但是这将会得到一个“死的”系统:从系统被完成的第一时间开始它就不再增删任何东西;也没有任何对外的接口,因为它不面向新的领域。这样的系统并非不存在,事实上它大量存在着,并且是“高可靠系统”的主要开发方式。这样的系统的一个主要特点是它在架构上的确定性,与之对应而又匹配的,则是其领域集中的运作模式也相对确定。但我们是在讨论复合领域集的问题。尤其其关键核心在于:由领域集构成的业务模式(犹如产业链等)是可能变化的,甚至是变化频繁的。

当我们将当前系统的目标与上述规划对应时,就很容易锁定我们“应有的”架构意图,并且能够通过阶段规划,来促使当前的架构意图契合业务方向对架构的要求。

“从架构的体系性上来考虑,即使在最初阶段的架构中,也不能缺少对后续架构阶段的设定。这至少包括两个方面:其一,后续架构阶段的启动条件;其二,后续架构过程“在当前架构中的”入手点。”

架构意图在各个阶段的不同变化,意味着我们可以用“有规划的变化”来讨论整体的架构意图。

架构的表达与逻辑

从暗示、隐喻,到抽象概念的表达

架构过程中存在大量的背景知识和推定事实,并且信息表现得可能会模糊而含混。这是因为架构过程本身就是对目标系统中一些不太明晰的概念(边界、联接关系等)渐次清晰的过程,所以架构过程中的模糊信息是必然存在的,否则根本不必去架构它。

但是这并不妨碍我们要求对架构的表达必须清晰准确。因为实施过程必将依赖架构的结果,亦即是架构的最终表达与决策。架构表达是在架构过程的阶段性成果的基础上所进行的、尽可能准确而清晰的叙述。如果它不能尽量准确地反映架构过程的阶段性成果,那么它也就不能作为下一个阶段(无论是实施还是新的架构迭代)的有效依据。换言之,如果对架构结果的表达是模糊的,则该结果是无意义的。

理解线与线框

在架构图中出现了一条线,通常都意味着它将一个整体划分成了两个部分。习惯性地,我们用纵向的线来表明领域的划分,而用横向的线来表明层次的划分

p-19.png

对系统或其构件的不变性的表达:平台、框架与库

用一个方框来表示领域,并且把一个方框分成两个(或多个)以表明领域之间没有关系或仅有殊少关系,

p-20.png

如何降低或至少不增加系统整体的复杂性来说,一种可选的分类依据是:如何隔离变化。

系统的复杂性有很大一部分是由其可变性导致的 4。但既有其可变处,也必有其不变处。以上述三种结构的表达方式来看:

  • 如果一个系统的公共部分是不变的,那么它适合用层次结构来表示;
  • 如果一个系统的总量是不变的,那么它适合用并列结构来表示;
  • 如果一个系统的核心是不变的,那么它适合用嵌套结构来表示。

以层次结构来论,如果我们能从系统中捕捉到那些不变的公共部分,我们就可以将它表达在底层,反之将“目前看起来可变”的部分表达在上层。如此,在一系列的架构活动结束之后,我们总是能保证系统的基底部分是无需变化的,亦即它是稳定的;相对于系统整体来说,它带来的复杂度应是衡为“1”的;它决定了系统整体的性状是不变的。

就“系统架构”的整体表达来看,层次结构适宜构建平台(platform)的过程,其基础领域倾向于不变;并列结构适宜构建库(library)的过程 7,其领域总量倾向于不变;嵌套结构适宜构建框架(framework)的过程,其核心领域(或核心过程)是倾向于不变的。

系统总量不变,其本质是复杂性的不变

多个方框放在一起的时候,它们(所表达的领域)之间是没有关系或仅有殊少关系的。其中,当使用并列结构时,它通常表明系统总量不变——系统的复杂性不因为拆分而增加。这事实上也约束了并列结构之间是不应有相互关系的。

当并列结构之间不存在关系并且它所表明的系统总量不变时,并列(的所有域)是可以被视为一个整体的。

p-21.png

嵌套结构所谓的“核心”,是指所有除核心之外的其他领域必然与该核心发生关系,亦即它必然可以表达为图 32 所示形式的结构。

p-22.png

p-23.png

就系统架构整体来说,我们必须关注三点:

  • 其一,应通过层次系统来隔离可变性,并尽量增大其中不变的部分;
  • 其二,可变部分影响系统的形态,但不影响系统的性状(亦即是指系统的边界与联接件);
  • 其三,如何理解“不变部分的关系”决定了系统的性状,也决定了“不变部分的复杂度是 1”的单位大小。

化繁为简:控制架构的复杂性

若 A 需要 B 的数据资源,我们称为数据依赖;若 A 需要 B 的计算资源,我们称为逻辑依赖;若将 A 和 B 都视为逻辑(亦即是可计算的资源),并讨论二者之间的关系,那么我们就会看到(逻辑或数据的)时序依赖。

p-24.png

p-25.png

即 A 和 B 间存在相互的数据时序依赖关系。若 A 和 B 是各自依赖了不同的数据而导致这种关系,则可以将 A 中的数据抽离至 B,如:

p-26.png

如果 A 和 B 间存在相互的逻辑时序依赖关系,那么我们总是可以通过添加一层数据抽象,来将向上的逻辑时序依赖变成“数据的”时序依赖,如:

p-27.png

系统确定性是界面原则的核心

通过讨论领域间的组成与关系,我们可以尽量将系统的可变性隔离在较晚实现的域中。因此,这意味着先期建设的系统总是不变的、稳定的、可重用的。这是组成论视角对系统架构的主要贡献。但从系统演进的趋势来说,任何系统的组成部分都必然面临我们持续开发行为将会带来的影响。

而界面(interface)——就提出这一概念的本意来说——就是通过对系统确定性加以规格化,从而来避免上述影响,如果一个界面(以及其规格细节)是确切而有效的,那么它应当完全满足如下条件:

  • 准确——合适的知识与表达,至少能让交流双方通过某种形式沟通;
  • 有用——完全明白的意图,至少与系统架构的意图不违背;
  • 可见——执行的效果显而易见,至少在领域或层次上的数据与逻辑流向明确;
  • 可能——应当存在实现的手段,至少可以立即着手开始尝试。”

在架构的表达上,由于纵向分开的并列部分之间是没有关系的,因此它们之间也就没有规格化的需求。而横向的层次之间,仅有向下依赖是确定的,因此界面必是由下层来规格化的。这应当包括(上层所需的)数据规格与(调用的)逻辑规格两个部分。

三类界面原则的示例:Erlang 的一些实践性原则:

p-28.png