承诺理论——它是什么?
在过去的 20 年里,对于管理 IT 系统的“命令和控制”模型,人们的不足感日益增强。多年来对着电视遥控器的经历,使我们很难想到其他让机器为我们工作的方式。但是,事实是,当您尝试管理大量事物的行为时,点击式操作、命令式脚本编写和远程执行的效果并不理想。
IT 设施在数据中心中规模庞大,外部管理器进行远程命令和控制的想法难以跟上步伐,因为它本质上是以人为中心的活动。值得庆幸的是,2005 年有人提出了摆脱这种困境的一种简单方法,并且在计算和网络领域获得了越来越多的追随者。这涉及到利用自主分布式代理。
从强加到获取假设我们想要实现一个软件设计或制定一个业务流程。出于文化原因,我们的第一个想法是希望向所有相关部件发出指令列表,以执行某种算法,但这在规模上可能不是最佳选择。算法只是我们告诉自己关于我们如何在头脑中设想过程的故事。通常,我们尝试以流程图或脚本语言的形式,将同一个故事告诉计算机或团队。这是描述、构建或处理设计的一种方式。该算法可能涉及很多细节,并采用逐步指令的形式,但其他方法使用并行或非线性故事来更有效地布置工作。在任何一种情况下,指导者都假定所有相关部件都会完全按照指示执行。唉,事实并非一定如此。系统的远程部件可能无法遵守这些指令,甚至可能不愿意遵守,这取决于它们的性质和环境。
这种命令和控制模型在计算机科学中被称为义务模型。它有很多问题。其中一个问题是,它将意图与实现分离,造成结果的不确定性。确定指令的地方不是必须执行指令的地方,因此指导者没有关于需要在本地执行工作的条件的信息。如果两个不同的指导者开始向同一组部件发出冲突的指令,则会开始冲突,系统的任何部件都无法解决该冲突,因为没有一个部件会在一个地方拥有信息:意图不在行动点本地。指导者甚至可能没有意识到彼此的存在,从而无法解决冲突。

图 1. 义务模型与承诺理论
幸运的是,有一种互补的设计方法可以解决这些缺陷,不是从义务的角度,而是从承诺的角度。
在基于承诺的设计中,每个部件仅根据其对他人的承诺行事。我们不是从外部获取指令,而是从内部获得承诺的行为。由于承诺是由“自我”(人类自我或机器自我)做出的,这意味着决策始终是在了解实施将发生的相同情况下做出的。此外,如果两个承诺彼此冲突,则代理拥有关于这些情况和冲突意图的完整信息,以便能够在无需外部帮助的情况下解决它们。
面向承诺的视图有点像服务视图。与其尝试用绳索和杠杆远程控制事物,不如利用承诺服务的生态系统,这些服务宣传意图并提供关于其行为方式的基本程度的确定性。承诺是关于期望管理,以及了解服务及其属性,这将有助于我们构建一个工作系统。我们如何让系统中的组件做出我们需要的承诺,这并不重要——这是一个单独的问题。
电子产品就是以这种方式构建的,管道和其他商品化的建造方法也是如此。您购买承诺某些属性(电阻、电容、电压-电流关系)的组件(从合适的供应商处),并根据这些期望将它们组合成一个电路,该电路保持更大的承诺(例如成为无线电发射器或计算机)。
示例—CSS为了提供面向承诺的语言的示例,请考虑 Web 上的 HTML 和级联样式表。可以将网页分解为标记的对象,如标题和段落、表格和图像等。这些中的每一个都可以用特定的身份标记,只是一种类型(如标题、段落、链接等)。在承诺理论模型中,这些区域可以被视为“自主代理”,它们通过 CSS 就它们将用于最初和随时间推移呈现其内容的颜色、字体和间距做出承诺。HTML 文件具有以下形式的区域
<h1>Title...</h1>
<p>Text....</p>
尽管这些是文本文件的区域,但这与磁盘上的文件没有本质区别。它只是容器的集合。CSS 承诺看起来像这样
h1.main {color: red; font-size: 12px; }
p.main {text-align:justify;}
也就是说,section “main” 中的标题 h1 将是红色并使用 12 磅文本。将其与文件进行比较。用于构建和维护计算机的配置工具 CFEngine 允许我们保持关于系统资源将具有哪些属性的承诺。例如,文件可以承诺具有某些权限、内容和名称,而不是颜色和字体。可以这样写
files:
debian::
"/etc/passwd"
perms => mo("root", "644");
该语言表面上看起来不同,但它基本上是对象模式与它们承诺的内容之间相同类型的声明性关联。区域自己做出的承诺是它将在所有时间呈现的承诺,直到承诺发生变化。因此,这不是一次性的按钮式命令,而是要持续维护的状态的描述。在 CFEngine 风格中,我们可以编写 HTML 样式表的这种替代形式
html:
main::
"h1"
font_size => "12px",
color => "red";
"p"
text_align => "justify";
从承诺理论中,我们看到这些模式基本上是相同的;因此,可以说 CFEngine 在这种意义上是一种“服务器样式表”。
承诺的组合承诺理论处理如何以这种方式思考更广泛的问题。它由我自己于 2005 年提出,作为一种形式化 UNIX 配置引擎 CFEngine 如何直观地解决管理分布式基础设施问题的方法。这种形式化模型在计算机科学中对于证明正确性非常重要。此后,它由我和 Jan Bergstra 开发,并且正被越来越多的人采用。
这种互补的非命令式思维方式在基础设施的背景下对我们来说似乎不自然,但在网页的背景下更常见。它的优点在于它同样适用于人类和机器系统,并且它强制执行一种纪律,即记录实施设计为承诺所必需和充分的信息。它实际上是可操作的(可执行的)文档。可以通过更改轻松转换为互补的承诺视图
"YOU MUST (NOT)..." ---> "I PROMISE TO (NOT) ..."
记录目的的必要和充分条件的一个副作用是,人们将设计的所有可能的故障模式都视为承诺枚举出来:“如果该承诺没有兑现怎么办?” 自主性保证没有隐藏的假设。
这种观点面临的主要挑战是如何从这些承诺中看到期望的效果出现。我们如何讲述关于系统的故事?在命令式编程语言中,线性故事就是代码本身。但是,在承诺语言中,人类故事仅隐含在一组启用承诺中。我们必须以不同的方式讲述发生的事情的故事。对于某些人来说,这是一个艰难的转变,秉承了 Prolog 和 Lisp 以及其他函数式语言的崇高传统。但是,在规模和复杂性方面,人类故事已经很难讲述,以至于承诺方法变得必要。
配置管理我们在承诺理论中看待世界的方式是将世界视为代理或事物的嵌套容器的集合,这些容器可以保持承诺。这些容器可以是
-
文件的一部分。
-
文件。
-
目录(文件目录)。
-
分区(目录分区)。
-
容器(或逻辑分区)。
-
虚拟机(或逻辑机器)。
-
局域网(机器局域网)等。
具有这种思维方式的参考软件仍然是 CFEngine(版本 3),因为它是在此模型中显式设计的,尽管有几个软件系统以隐式的面向承诺的方式工作。承诺思维也渗透到网络世界,其中自主性内置于设备的运行模式中。向用户做出承诺的其他示例包括接口和 API、微服务或面向服务的架构 (SOA)。
面向知识的服务设计承诺通过将注意力从变化的内容(或要执行的算法)转移到组件之间存在的接口以及它们保持的承诺及其原因,将设计和配置转变为知识管理的一种形式。亚马逊和 Netflix 成名的面向服务的编程风格使用这种方法来实现可扩展性(不仅是机器可扩展性,而且是人类所有权的可扩展性)。它被誉为设计系统的云友好方法,但承诺理论也告诉我们,这是实现超大规模的途径。应用程序必须通过协作来扩展(有时称为通过并行性进行横向扩展,而不是通过蛮力进行纵向扩展)。像 Cassandra 这样的数据库说明了如何处理规模、冗余和相对性问题。
有趣的是,生物学选择了冗余服务作为其扩展基于组织的生物体的模型。这为我们提供了强烈的线索,表明我们走在正确的轨道上。避免强依赖性是避免瓶颈的一种方法,因此这显示了可扩展性的途径。
自主性和独立思考似乎与我们通常学习的编程知识背道而驰——即共享资源,但这不一定是真的。安全性和可扩展性都在自主性下蓬勃发展,当部件之间的依赖关系被消除并且所有控制都来自内部时,复杂性就会消失。移动和嵌入式设备的近未来世界将无法容忍远程控制的管理模式,云服务器后端的蔓延将迫使我们分散 3D 打印的微型数据中心,就像今天的电力变电站一样。在这个世界中,我认为我们可以期望看到更多的自主思维渗透到社会中。