你无法购买集成
商业集成工具已经存在了几十年,但很少有关于何时以及如何使用它们的总体架构原则。在本文中,我论证了“购买”决策机制导致我们夸大了此类工具的价值主张,这往往导致使用特定集成工具而不是通用语言的强制性要求。我认为,此类工具在一个将集成主要视为连接系统的世界中蓬勃发展,但数字组织已经重新构想集成,使其主要成为在数字能力之前放置干净的接口,强调能力而不是系统。最后,我列出了一些现代集成视图背后的关键原则,并声称它们最好用通用语言来管理,将商业集成工具的主要价值主张重新定位为简化战术实现问题。
2021 年 12 月 14 日
在计算的早期,供应商将软件(包括编译器和操作系统)作为其运行的硬件的一部分出售。这种情况在 1974 年发生了改变,当时美国版权作品新技术用途委员会 (CONTU) 决定计算机程序受版权保护,从而为最初被称为“程序产品”的东西创造了一个市场。尽管自由软件基金会和开源的抵抗运动,但商业软件产品确实存在,而且仍然存在市场。“构建与购买”决策如今无处不在,而且理所当然。构建软件风险高且成本高昂,而软件产品公司可以将这种风险和成本分摊到多个客户身上。
但是,正如你可能从本文标题中猜到的那样,此类决策并不适用于所有情况。
你无法购买集成
尽管有各种旨在简化系统连接的工具,但你无法购买集成。
你可以购买编程语言。在 1974 年 CONTU 裁决之后,为编译器付费变得很常见。比尔·盖茨著名的致业余爱好者的公开信是社区为 Micro-Soft 的 Altair BASIC 解释器付费的号召(他们在后来的几年中删除了连字符)。自由软件基金会的 GCC 编译器为编程语言的商品化打开了大门,但为开发人员工具留下了商业市场。例如,我很乐意使用 Java 进行编程——现在可以免费使用——但我不会对在 vi 或 Notepad 中使用它感到兴奋。
集成软件产品——ESB、ETL 工具、API 平台和云集成服务——不是直接解决业务问题的产品。例如,它们不属于欺诈检测产品、分析产品或 CRM 的类别。它们是编程语言,捆绑了工具链和运行时以支持编译过程。当你购买集成产品时,你同意使用商业编程语言构建集成本身。
集成工具几乎总是低代码平台,这意味着它们旨在通过提供一个图形设计调色板来简化开发工作,你可以在其上拖放集成工作流程。源代码通常以标记语言保存,该语言可以由运行时解释。你可能会将一些工作流程拖放到调色板上,但在幕后,平台将源代码保存为 JSON 或 XML,并将一个知道如何将标记解释为实际机器代码的运行时嵌入其中,这与 Micro-Soft 的早期编译器知道如何在 Altair 平台上将 BASIC 代码转换为机器代码的方式相同。例如,以下是 AWS 编排引擎 Step Functions 的“Hello, World”源代码
图 1:Step Functions 使用 JSON 和图形设计调色板来表示工作流程
许多集成工具,包括 AWS Step Functions,都允许你使用图形调色板或直接使用标记语言进行编程。虽然调色板通常更受欢迎,原因是任何读过查尔斯·佩措德著名的关于 CSAML 的愚人节笑话的人都能理解,但在调色板上配置集成步骤的复杂性意味着,在实践中,有能力的开发人员会对底层标记语言本身有一定的了解。实际上,从图形调色板到标记语言存在双向映射,这样更改一个就可以立即反映在另一个中。如果我正确理解了数学术语,那就是所谓的同构,因此我将由此产生的结构称为“源代码-图同构”,其中调色板和标记语言都代表源代码,并且可以无缝地相互转换。当然,这代表了以开发人员为中心的观点;运行时本身只关心标记语言。
这与大多数软件编程截然不同,在大多数软件编程中,开发人员直接编辑源代码,没有图形调色板,这种做法我称之为“源代码自同构”,尽管你也可以称之为“正常”如果更容易记住。当然,有一些工具可以可视化 Java 中的类图,甚至可能允许你进行更改并将其反映回源代码中,但 Java 开发人员的通常活动是在 IDE 中直接编辑 Java 源代码。
提供图形设计调色板的优势在于它提供了一种组织思想的方式,一种用于集成问题的领域特定语言 (DSL),使你能够专注于连接系统的狭窄问题,而无需额外的复杂性。Java 可能更擅长解决通用问题,但设计调色板和声明性标记语言的约束声称可以更优雅地解决集成和工作流程问题,就像 Excel 函数让你比编写自定义 Java 代码更优雅地解决预算问题一样。同样,在许多情况下,我更喜欢 iPhone 上的计算器,而不是功能强大的HP 50g 图形计算器,它支持逆波兰表示法和科学计算。
图 2:好的 DSL 通过专注于核心问题来消除复杂性
当你购买集成工具时,你同意构建实际的集成本身。你购买的是一个承诺,即集成可以比使用通用语言更有效率、更简单地解决。然后,架构师的工作就变成了理解在哪些情况下该承诺很可能成立,并避免将“购买”决策转换为在这些情况之外使用该工具的强制性要求,以证明其投资回报率的合理性。
一些集成 DSL 是问题空间的更简单的投影,就像我的 iPhone 计算器一样。另一些确实图灵完备,这意味着,从理论上讲,它们具有与通用语言相同的算法能力。虽然这是真的,但关于可计算性的学术讨论没有考虑到软件工程,一群谷歌工程师将其定义为“随着时间的推移进行编程”。如果编程需要使用抽象,那么随着时间的推移进行编程意味着在一个复杂的生态系统中随着环境的变化而演化这些抽象,并且需要积极考虑团队协议、质量实践和交付机制。我们将在稍后更详细地研究随着时间的推移进行编程的关注点如何影响集成,以及它们如何告知低代码集成工具的适当上下文。但是,首先,我想挑战一下将集成的主要目标视为连接系统的想法,因为我相信更广泛的定义使我们能够更好地将生态系统中简化抽象促进编程的部分与随着时间的推移进行编程的额外复杂性需要通用编程语言的部分区分开来,我将在稍后为这一主张辩护。
将大部分精力投入构建干净的接口
对于大多数人来说,“集成”一词会让人联想到将系统连接在一起,即共享数据以使系统保持同步。我认为,这种对集成的定义不足以满足现代数字业务的需求,并且集成做得好的真正目标是在能力之间创建干净的接口。
当我们的主要关注点是连接系统时,我们可以通过将新系统连接到现有技术资产的速度来衡量集成方法的成功程度。系统成为该资产中主要的价值驱动因素,而集成成为使系统正常运行的必要之恶。当我们转而将主要关注点转移到在数字能力之上创建干净的接口时,我们通过随着时间的推移提高数字敏捷性来衡量成功,而这些数字能力成为主要的价值驱动因素,可以说甚至比系统本身更重要。在这一差异中有很多东西需要解释,首先是强调接口而不是实现。
数字组织将集成的主要关注点从系统转移到能力,强调在这些能力之上创建干净的接口。
简化接口是创建成功产品和在复杂生态系统中扩展的关键要素之一。例如,我对键盘的机械-电气实现几乎一无所知,或者输入系统驱动程序或操作系统中断是如何神奇地将我正在键入的键显示在我的屏幕上的。有人必须弄清楚这一切——更可能的是许多人,因为键盘、系统驱动程序、操作系统、显示器和应用程序都是独立的“产品”——但我所要担心的只是在正确的时间按下正确的键,将我大脑中的想法整合到屏幕上的文字中。
当然,这有一个有趣的推论:简化接口的关键(双关语)是接受更复杂的实现。
当我们想到与市场竞争的数字产品时,这句话并没有什么争议。例如,谷歌搜索在幕后极其复杂,但即使是数字技术不精通的用户也难以置信地易于使用。我们也接受它适用于面向业务用户的数字产品。对引入 Salesforce 感到兴奋的销售团队肯定明白,虽然用户界面可能比旧的 CRM 更直观地满足他们的需求,但维护和演化产品本身需要大量的努力,这就是为什么订阅费用感觉合理的理由。然而,我们对集成采取了不同的态度。直觉上,我们明白,我们架构图上的二维方框可能隐藏着相当大的复杂性,但我们期望一维线在某种程度上有所不同。
(它们在某一方面确实不同。你可以购买方框,但你无法购买线条,因为你无法购买集成。)
虽然我们历来围绕方框——我们正在引入的数字产品——制定项目计划和成本,但线条是隐藏的,而且往往是组织技术债务的主要驱动因素。它们是为什么现在事情比以前需要更长时间的原因。
图 3:我们从应用程序引入的角度考虑项目,但这些应用程序之间的线条随着时间的推移成为关键的成本驱动因素
简化粘合代码无疑是一项崇高的努力,集成工具可以提供帮助,但不能以牺牲构建干净的接口为代价。重要的是,只有实际使用接口的人才能有效地判断接口是否易于使用。例如,谷歌本可以向我们索取更多信息来简化他们的搜索实现,例如地理位置、最近度和流行度信息,但他们只提供了一个文本框供用户输入搜索内容,并不得不学习如何在他们的算法中应用这些因素。同样的问题也适用于 API 设计(我将 API 设计定义为广义上的同步调用和异步事件)。
干净的接口隐藏了实现细节,而集成环境中的一个实现细节就是编程语言的选择。我还没有见过将系统所用编程语言作为主要关注点的架构图。
图 4:在架构图中强调实现语言是不寻常的
然而,我见过太多将集成视为将系统连接在一起的战术理解的图表变体。这种观点强化了集成作为将系统连接在一起的战术理解,因为它强调了连接工具链而不是数字能力。
图 5:在架构图中显示商业集成工具将重点放在实现细节而不是接口上,并将集成视为战术问题
另一个 API 消费者乐于不关心的实现细节是数据来自哪些系统。除了在 SAP 工作的业务用户和他们周围的 IT 人员之外,组织中的任何人都应该不必关心 SAP 系统的怪癖。他们只关心如何访问客户数据或如何创建订单。这个观察结果值得单独说明,因为它是我在集成策略中看到的最常违反的原则之一,也是将集成视为将系统连接在一起而不是在数字能力之上创建干净接口的隐性哲学的最强指标之一。你不需要 SAP API,因为你的 API 用户不关心 SAP,但你可能需要一个订单管理 API。抽象出能力,而不是系统。
你的用户不会停滞不前,而且好的 API 通常会通过重用增加价值。将重用作为 API 的主要目标很容易过度关注(我认为控制复杂性是一个更重要的目标),但它仍然是一个有用的愿望。跟上用户不断变化的需求意味着打破之前的假设,这是一个经典的编程随时间推移的问题。继续我之前的比喻,键盘的工作是将用户的想法无缝地整合到屏幕上的文本中。作为英语母语人士,我从未像汉语母语人士那样为拼音转写而苦恼,但多年来,我却在 Colemak 键盘布局上折磨自己。因为我的物理键盘无法神奇地适应软件布局,所以键盘上的字母和屏幕上显示的字母之间存在阻抗不匹配。通常情况下,这不是问题:作为一个(不太快的)触屏打字员,我已经习惯了不看键盘。然而,这种阻抗不匹配使得学习过程变得痛苦,因为我不得不不断地查看屏幕上的 QWERTY 映射,并在我的大脑处理由此产生的混乱时向下看键盘。我相信有一些键盘是背光的,并且会根据键盘布局在物理键上投射字母。当然,这种改进的接口的代价是更高的实现复杂性,而这种演变是一个编程随时间推移的问题。
无法随着时间的推移适应用户的集成接口,或者为了实现方便而过于容易地随着底层系统而改变的集成接口,都是时间点集成,实际上只是具有多层级的点对点集成。它们可能穿着 API 的外衣,但每次将新系统连接到系统中,并且 API 被复制或滥用来解决实现问题时,就会露出它们的真面目。时间点集成会增加系统间技术债务。
将集成主要视为关于系统的问题,会导致出现大量时间点集成,降低组织敏捷性。
当然,你的吱呀作响的记录系统会抵制任何将它们放入盒子里的尝试。ERP 的设计初衷就是做所有事情,因此尝试将仍然需要与 ERP 集成的新的功能外部化将是一个挑战。它可能需要大量的架构技能来控制由此产生的集成复杂性并将其隐藏起来,但另一种选择是增加你的组织技术债务,在点对点或时间点集成的意大利面条式混乱中添加另一根面条。我知道的唯一偿还这种技术债务的方法是坚持为用户创建干净的接口,并为下游系统创建必要的转换、缓存和编排。如果你不这样做,你就强迫所有 API 用户处理这种复杂性,而他们比你拥有更少的上下文。
我们需要改变思维方式,从思考如何用我们的工具解决集成问题,转变为思考如何构建正确的接口来最大限度地提高敏捷性。
使用通用语言来管理接口演变
许多商业集成工具宣传它们拥有集成环境并根据需要调用通用语言的能力。虽然我理解这种宣传背后的营销策略——它促进了产品渗透和锁定——但作为架构指导,它完全是倒退的。相反,我们应该几乎总是用通用语言管理接口演变,至少有两个原因:这样我们才能更好地管理维护干净接口的复杂性,以及避免在做出战略集成决策时受到工具思维模型的引力影响。
通用语言擅长随着时间的推移进行编程
编程随时间推移意味着随着时间的推移对源代码进行更改,而这正是源代码图同构与正常开发相比相形见绌的一个领域。能够“diff”源代码提交之间的更改是开发人员的超级能力,是一种宝贵的调试技术,可以用来理解缺陷的来源或更改背后的上下文。对集成工具的标记源代码语言进行 diff 比对 Java 代码进行 diff 困难得多,至少有三个原因:模块化、语法和翻译。
通常情况下,开发人员负责源代码的模块化。当然,也可以将所有逻辑都放到 Java 中的单个文件中——经典的“上帝对象”——但有能力的开发人员会在应用程序中创建干净的边界。因为他们直接编辑文本源代码,所以语言的模块边界对应于文件系统边界。例如,在 Java 中,包对应于目录,类对应于文件。源代码提交可能会更改多行代码,但这些代码很可能局限于团队理解的代码中的自然边界。对于集成 DSL,设计调色板对底层文本源代码的模块化具有一定的控制权,这是你为源代码图同构所付出的代价。例如,在一个文件中创建整个工作流并不少见。
同样,标记语言本身可能包含使 diff 变得更难的语法。好消息是,我所查看的工具在“漂亮打印”标记语言方面做得很好,这会添加行尾以使 diff 更容易。但是,工作流中的结构性更改仍然更有可能导致,例如,标记语言中元素的重新排序,这将使 diff 显示比这种操作直观上应该显示的更多行代码更改。此外,一些语言,特别是 XML,会添加大量的噪音,掩盖了实际的逻辑更改。
最后,因为你在集成 DSL 中以更高的抽象级别进行编程,所以你需要一个两步过程来检查 diff。首先,就像你对 Java 所做的那样,你需要在提交本身的上下文中理解更改的行。对于 Java,由于该源代码与你编辑的源代码相同,因此理解到此为止。对于集成 DSL,你需要进行额外的思维飞跃,才能理解这些更改的标记行对整个工作流意味着什么,有效地将它们映射到你将在设计调色板上看到的内容。源代码提交之间的差异只能用文本表示;图形调色板并非旨在表示随时间的变化。所有这些的最终效果是增加了开发人员的认知负荷。
Gregor Hohpe 有一个精彩的故事,展示了低代码平台的可调试性缺陷。在《软件架构师电梯》中,他描述了供应商在他公司推销产品时的经历。一旦他们展示了将解决方案拖放在一起是多么容易,他就要求技术销售人员离开房间两分钟,而 Gregor 在底层标记语言中随机调整了一些东西,这样他就可以在技术销售人员回来时看到她是如何调试的。到目前为止,至少在本书出版时,还没有供应商接受他的提议。
商业集成 DSL 也使得在同一个代码库中扩展开发变得更加困难。不仅难以理解单个源文件的更改随时间的上下文,而且多个开发人员并行编辑同一个源文件也更加困难。这在通用语言中并非没有痛苦,但可以通过开发人员对源代码模块化的直接控制来实现,这就是为什么你很少看到只有 1 或 2 个 Java 开发人员的团队。对于集成 DSL,考虑到源代码模块化的限制以及理解源代码(标记源本身以及它们所代表的图形工作流抽象)所需的额外思维飞跃,合并要痛苦得多。对于此类工具,限制同一个代码库上的并行开发并将其分解为可以并行开发的独立组件的做法非常普遍。
编程随时间推移需要高级测试和环境推广实践。许多集成工具供应商不遗余力地展示他们对这些实践的支持,但再一次,这是一种劣质的开发人员体验。例如,每次测试运行都需要启动解释 XML 源代码为机器代码的运行时。在实际应用中,这种摩擦消除了短时间内测试驱动开发“红、绿、重构”反馈循环的可能性。此外,你可能只限于供应商的框架进行任何类型的单元测试。
通用编程语言的生态系统正在快速发展。测试工具、IDE、可观察性工具和更好的抽象方面的进步得益于这些语言所处的社区的规模。低代码平台的生态系统要小得多,限制了它们以相同的速度进步的能力,而平台约束几乎肯定会迫使开发人员使用供应商提供的工具链来编写和测试代码。这自然会对供应链和静态分析扫描等安全问题产生影响。对于 Java 开源库来说,此类工具受到了很多关注,但在低代码世界的封闭花园中却很少受到关注。
最后,集成工具在运行时提供的操作支持相对贫乏。虽然可观察性工具和弹性模式在通用编程语言及其支持的平台中受到了很多关注,但这些并不是集成工具的主要关注点。我见过多个大规模采用低代码集成工具导致了相当大的性能问题,这个问题随着时间的推移会变得更糟。它通常最初通过额外的许可费用来解决,直到许可费用也变得过高。不幸的是,到那时,已经存在着重大的平台锁定。
低代码工具无法处理与通用编程语言相同的复杂性。我的一个同事描述了一个有争议的环境,他在那里处理使用 TIBCO BusinessWorks(一个知名的商业集成工具)的强制要求。他向 TIBCO 团队发起了一场“烘焙比赛”:他会派他最好的 Java/Spring 开发人员创建一个与另一个 COTS 产品的 Web 服务的集成——用 Apache Axis 编写的 SOAP 接口——他们可以带上他们最好的 TIBCO 开发人员来做同样的事情。Java 开发人员在午餐前就完成了工作实现。TIBCO 团队发现该工具不支持 COTS 产品使用的旧版 Apache Axis,这种遗留复杂性在大型企业中很常见。遵循强制要求将意味着回到供应商那里,更改他们的路线图或在通用编程语言中添加扩展。弗雷德·布鲁克斯在他的著名论文《没有银弹》中将这种扩展称为“偶然复杂性”:它们由于解决方案的选择而增加了复杂性,与问题本身无关。每个使用低代码工具进行所有集成的强制要求都会积累大量的偶然复杂性。
然而,比为所有集成通过商业工具运行而需要的偶然复杂性更令人担忧的是,这种强制要求将重点放在实现而不是接口上,放在系统而不是能力上。
集成工具“思考”的是实现
集成工具的创建,以及今天仍然蓬勃发展,是因为跨 IT 系统范围解锁数据和功能的复杂性。例如,您的实际客户主数据可能驻留在 SAP 中,但客户生命周期的早期阶段存在于 Siebel CRM 中。IBM 大型机系统仍然处理某些客户的核心计费;而其他客户则使用 Oracle ERP。现在,企业想要用 Salesforce 替换 Siebel。引入新产品的业务团队自然明白,将产品配置为适应他们的销售收入流程需要一些时间,但他们最不希望听到的是,仅仅为了整理系统之间的粘合剂而需要很长的 IT 时间表。毕竟是 SaaS!
传统上,这些漫长的周期是点对点集成的结果,这不允许学习。系统之间的每条新连接线都意味着团队必须重新学习如何连接、如何解释数据、如何跨系统路由等等。集成工具将问题分解成更小的部分,其中一些可以重复使用,尤其是连接到系统。看看我们之前看过的 AWS Step Functions 调色板上的某些可用操作
图 6:AWS Step Functions 工作流中的每个步骤都描述了一个实现问题
Step Functions 将所有操作描述为对某些 AWS 服务的某些操作。您可以配置工作流中的每个框来描述,例如,DynamoDB 表名称,允许您专注于调色板主要部分中的整体流程。虽然 Step Functions 是一种相对较新的集成工具,明显偏向于云原生 AWS 服务,但我所熟悉的其他所有集成工具都倾向于沿着类似的思路工作,专注于实现问题。早期针对应用程序集成的本地等效项是企业服务总线 (ESB),它将系统连接作为可重用组件与编排和路由分离。您可以在对 Mulesoft 的 ESB 的简化视图中看到这种分离,之所以这样命名是因为它旨在消除集成的“苦力活”。
图 7:ESB 将连接与编排和路由分离
在 ESB 世界中,有一些自然的错误开始,因为行业渴望在总线上拥有企业范围的规范格式,但它们都共享了对总线输入和输出的适配器的概念——正在集成的系统。在理想情况下,您可以使用像 BPEL 这样的语言来描述您的集成,它可以提供图形设计调色板和源图同构,因为它用 XML 描述了流程。
行业已经从 ESB 大致上转移了,但您可以在现代 API 平台中看到它们的传承。例如,看看 Mulesoft 的三层 API 架构
图 8:Mulesoft 的三层架构保持了连接与体验和系统 API 的分离
Mulesoft 销售 API 管理平台和用于构建 API 的低代码运行时。您可以并且通常应该购买中间件基础设施,并且完全可以将 API 网关与运行时分离,代理到用通用编程语言构建的 API。如果您这样做,就会出现一个问题:如果您在 Mulesoft 运行时之外构建所有 API,您是否会使用 Mulesoft 的三层架构?
我非常喜欢体验 API 的概念。这个名字比微服务社区流行的名字——前端的后端——更不那么术语化,尽管我更喜欢“通道 API”这个词,因为它更明显地涵盖了更广泛的问题。例如,在 B2B 场景中缩小对核心 API 的访问权限显然是一个通道问题,不太明显是“体验”或“前端”问题。无论名称如何,提供优化的通道特定 API 都是一个有价值的模式,它允许通道以不同于底层功能的速度发展,并缩小攻击者的攻击面。
我对过程 API 和系统 API 之间的规范分离不太感兴趣,因为它们关注实现而不是接口:系统层关注连接,而过程层关注编排 [1]。我已经重新绘制了他们上面简化的 ESB 图,以显示连接系统的实现问题上的相似性是很难忽视的
图 9:三层架构强调实现细节,显示了其 ESB 遗产
像 Mulesoft 这样的平台——包括其 ESB 和 API 运行时——的部分价值主张在于内置的连接器库,这些连接器连接到 SAP 和 Salesforce 等系统,这些连接器可以节省您在系统边缘(尤其是系统层)的时间。三层架构简化了这些连接器的使用,并将编排和聚合分离,以鼓励它们的重复使用。
从概念上讲,三层架构旨在约束 API 的设计,使其适合 Mulesoft 的 ESB 遗产。理论上,该架构允许跨层更多地重复使用。在实践中,您受到将过程 API 发展到多个消费者的编程跨时间问题的限制。事实上,我见过许多根本不是 API 的 API,而是 API 外衣下的 ETL,系统层管理提取,过程层管理转换,体验层管理加载。这并不奇怪,因为集成工具从实现的角度思考。
购买集成工具的吸引力在于它们使连接系统的战术问题变得更便宜,避免了定制软件的通常费用和风险。不幸的是,当我们以这种方式构建问题空间时,我们已经允许我们的工具为我们思考。
使用商业集成工具来简化实现问题
正如现在应该清楚的那样,我对企业范围的集成工具强制要求持高度怀疑态度,不是因为我对特定工具本身有任何批评,而是因为我认为这种强制要求代表了对集成价值的根本误解。当然,工具供应商会对此进行反驳,但工具供应商有一个自然而然的、可以理解的目标,那就是增加渗透率和锁定。架构师的作用是确保您不会让供应商的产品策略成为您的架构策略,而是为工具创建适当的 边界上下文。
通过这种视角,我认为商业集成 DSL 至少可以在两个领域增加巨大的价值。
简化工作流程和连接性
仅仅因为实现是次要问题并不意味着在加速实现方面没有真正的价值,只要我们以适当的方式将其构建在简化对底层功能访问的接口后面。毫不奇怪,加速实现正是商业集成 DSL 的主要价值主张。
许多集成 DSL 被推销为“拥有”集成环境,并在必要时调用通用语言。为了解决编程跨时间问题,您需要反转这种控制,将易于演化复杂性的实现部分从那些不太可能随着时间推移而需要大量更改的部分抽象出来。
图 10:为了管理编程跨时间复杂性,使用集成 DSL 来简化实现,而不是拥有接口
我与之互动的一个团队使用 Camunda 来管理微服务编排。与某些编排工具不同,您可以将 Camunda 作为 Java 库与 Spring 和 Spring Boot 集成使用,这使得使用传统的 Java 软件工程学科来管理通用编程语言中的接口演化变得更加容易,同时使用工作流工具(在本例中是开源的,但商业工具也可以正常工作)来简化某些实现方面。
同样,这些系统连接器和适配器可以极大地提供一些实现提升,并且可以抽象到用通用编程语言编写的核心功能抽象后面。这类似于 Mulesoft 的系统 API 指导,即使您的最终 API 策略淡化了系统,这仍然是良好的实现建议。同样,图形工作流可视化可以加速将一系列调用连接在一起,以用于多步骤过程中的简单步骤,就像上面显示的 AWS Step Functions 示例一样。
一般来说,我会谨慎地将大量转换添加到集成 DSL 中,或者至少我愿意随着时间的推移用 Java 等语言重新实现这些转换,因为这往往是许多编程跨时间复杂性所在的地方。转换代表了源系统中的数据与消费系统期望的该数据的接口之间的缓冲区,因此它受到多个方向的演化压力:记录系统的更改以及为消费者演化接口。同样,我会将任何性能优化或弹性代码(如缓存)保留在通用语言中,因为它们随着时间的推移往往会变得非常复杂。
捕捉 B2B 集成的长尾
在 B2B 场景中,通常需要在组织墙外进行集成。如果您幸运,您可以依靠干净的 API 来进行这种集成,但运气不是一个特别有回报的商业策略,您可能不得不与 IT 能力较差的小企业进行集成。必须与像 B2B 合作伙伴一样多样化的系统进行集成,以及处理一些 IT 能力很差的合作伙伴,这带来了一个艰难的挑战,我个人在三个不同的行业中都看到了这种挑战的反复出现
- 一家通过经销商进行交易的能源公司,并签订了共享销售信息的合同,以管理自动库存补充。
- 一家与第三方经销商进行交易的重型机械零售商,但试图在全球范围内优化零件交付。
- 一家与付款人进行交易的医疗保健服务公司,提供增值服务来检测(例如)欺诈、浪费和滥用。
即使这些 B2B 合作伙伴确实拥有适当的 IT 系统,其多样性也可能压倒一切,您可能没有足够的杠杆作用来要求他们编写与您的 API 合同的集成。许多 B2B 合作伙伴也存在于传统行业,迟迟不愿采用新的数字技术。FTP 文件传输、来自大型机系统的 EBCDIC 转换以及 EDI 仍然是您可能需要解决的问题。
缓慢发展的 IT 的优势在于编程跨时间问题得到了缓解。商业集成 DSL 的优势在于它们中的许多可能确实具有支持所需集成模式和转换的功能。将转换直接放在工具中与我上面的建议相矛盾,但由于 B2B 集成往往以律师和采购部门的速度移动,因此这种权衡更具吸引力。当然,您仍然需要一个专门的通道 API,但集成 DSL 可以充当廉价的适配器。
图 11:使用集成工具作为集成合作伙伴和通用通道 API 之间的适配器
使用通用编程语言来解决集成方面的长尾问题可能非常昂贵。使用专门为快速解决问题而构建的工具,只要这些问题不需要快速演变,可能是一个更好的经济决策。
将集成视为业务战略
我经常听到有人用一个理由来为购买集成工具辩护,通常用“我们不是软件公司”之类的说法来表达。这种观点是可以理解的,它旨在作为一项原则,帮助人们在做出艰难的决策时,优先考虑与组织整体市场价值相一致的投资。开发人员的劳动力是一项重大投资,虽然有很多精通集成 DSL 的开发人员,但总的来说,这类开发人员的劳动力市场比那些更擅长使用通用语言编程的开发人员的劳动力市场便宜。
我认为这项原则完全属于“一毛不拔,却要花大钱”的范畴。毕竟,我怀疑你也不是一家数学公司,但到了某个规模,你就会依赖一些相当先进的数学技能。你不会通过为你的财务团队和统计学家购买一台功能较弱的计算器,然后要求他们将整体问题分解成适合工具复杂性上限的方法来解决这个问题,将每个问题都变成你工具锤子可以敲的钉子。
当然,软件是不同的。编写软件是出了名的风险高、成本高,许多组织非常害怕定制软件,以至于他们会不遗余力地避免它。购买图形集成工具可以实现更简单、更易于使用的一种定制软件形式。是的,你的架构图中每个方框之间的线条可能更容易创建。但是,由于此类工具的复杂性上限,线条数量会激增,这就像在你的架构上浇灌缓慢硬化的混凝土,随着时间的推移会增加你的架构技术债务。
几年前,我与一家电信公司合作,该公司希望为其用户提供购买新手机的自助式电子商务功能。任何在该行业工作过的人都知道其中涉及的挑战:购买电信服务比购买零售产品复杂得多,因为电信服务有生命周期。对于手机来说,通常面向客户的抽象生命周期是计划,其中详细说明了短信、数据和语音限制,以及如何计费国际电话(一个极其复杂的实现,涉及法律和运营商协议、海底电缆、整个深海电缆维修行业,以及防止切断电缆的国防协议,所有这些都隐藏在电话号码的干净界面后面)。
实际上,已经开发了一个 API,但它是为呼叫中心代理开发的,而不是为电子商务网站开发的。要获取手机的可用计划,API 和底层系统需要你首先创建一个交易,记录呼叫中心代理的操作——这显然是网站不正确的抽象。我们能够通过创建一个假交易来解决这个限制,以便接收一个包含系统详细信息的 XML 负载。
<x:offerDetails> <id>2207891</id> <program>2205442</program> <filter> <typeCode>C</typeCode> <subTypeCode>E</subTypeCode> <contractTerm>24</contractTerm> </filter> </x:offerDetails>
一旦我们与各个专家协调,了解了这些神奇的数字和字母的含义——来自底层计费系统的泄漏抽象——我们仍然需要进行一次电话才能获取定价详细信息。最后一次电话返回了超过 1000 行的 XML 代码,其中大约 100 行与我们的电子商务需求相关。
虽然这绝非易事,但我们与底层 IT 组织合作,创建了一套新的 API,这些 API 更清晰地代表了电子商务问题,没有所有额外的遗留复杂性,干净的界面将泄漏的抽象转换为有意义的功能,因此电子商务开发人员不需要了解计费系统机制。我们必须抽象出遗留的复杂性,以便我们能够创建自助服务的未来。架构图反映了一种新的思考问题的方式,即从数字能力而不是底层系统来思考。我们不允许下游复杂性或实现编程语言在我们的电子商务团队的图表中找到位置。
图 12:尽管下游存在重大复杂性,但我们确保了与核心功能的干净接口,以提高电子商务敏捷性。
当一切尘埃落定后,这家电信公司成为该国第一家在推出新款 iPhone 时拥有完全自动化的自助服务体验的公司,不仅击败了其直接竞争对手,还击败了强大的苹果公司。
无论是否真实,著名的杰夫·贝索斯关于只通过可外部化的 API 进行沟通的命令可能是他们目前世界统治的关键。该命令具有深远的影响,其中之一是将集成对话从思考系统转变为思考能力,这在技术内部创造了巨大的组织敏捷性。另一个更具颠覆性的影响是通过简化对这些能力的消费者的界面,独立于运行这些能力所需的专业知识,来从内部运营中产生收入流——基础设施供应、呼叫中心、履行。这样做在他们的架构图中创建了新的方框,在以前有线条的地方创建了方框,因为他们将复杂的过程重新定义为用户友好的可编程接口。
你的集成策略是组织敏捷性的关键架构组件。人们希望将它外包给产品,类似于其他购买与构建的权衡——以管理风险——是可以理解的,但这种方法总是会导致集成被视为战术问题。正如亚马逊向我们展示的那样,将集成对话从将系统连接在一起重新调整为在业务能力之间公开自助服务接口,可以带来巨大的商业价值。这样做需要从本文探讨的集成原则类型来思考:
原则
描述
从用户的角度设计你的接口
你的 API 本身就是数字产品,旨在帮助你的开发人员和系统集成商解决复杂性。正如任何产品经理都知道的那样,一个好的产品界面旨在让你的用户的生活更轻松,而不是你的。
抽象出能力,而不是系统
底层系统是一个实现问题。避免泄漏抽象,并提供底层能力的简化视图。
隐藏实现复杂性,即使在演变过程中也是如此
构建可以随着时间推移而演变的抽象,即使这意味着更复杂的实现。
创造未来;适应过去
抵制将遗留集成的底层复杂性暴露给消费者的诱惑,因为另一种选择是强迫你的每个消费者都去处理这种复杂性,而他们对它的了解远不如你。
集成对你的业务至关重要
在规模上,理顺业务复杂性的唯一方法是在干净的接口后面构建简化的抽象。
在《软件架构师电梯》中,Gregor Hohpe 描述了数字组织如何在“一阶导数”中运作,这是一种数学极客的说法,意思是他们将注意力从当前的数字足迹转移到变化率。我将超越 Gregor,说一个好的集成策略存在于二阶导数中:你的集成策略,以及投入时间和金钱来简化组织能力接口的能力,是组织加速的关键驱动因素。它可能一开始会让你慢一点,但随着时间的推移,这些接口将成为你数字化转型的油门。
图 13:构建数字加速需要关注编程随时间推移的问题,尤其是系统之间干净接口的必要性。
所以,请务必购买你的 CRM 和你的收入管理系统,以及你的呼叫中心的基于 ML 的情绪分析附加组件。购买你的 API 网关、你的分析数据库和你的容器编排系统。向数字原生企业学习产品运营模式、内部化方法和自主团队结构。请记住,如果你继续将集成视为需要克服的战术性麻烦,以便利用这些新系统,那么这一切都不会让你在数字世界中具有竞争力。
你无法购买集成,但没关系;自己构建它值得投资。毕竟,它可能是你投资组合中最具战略意义的软件。
脚注
1: 我对 Mulesoft 模型的主要批评是强调实现问题,因为我认为这会导致将集成视为战术问题。Praful Todkar 和 Ryan Murray 在他们关于构建良好分解的服务架构的系列文章中,主张了一个表面上类似的模型。虽然我认为他们的模型中基础能力和业务能力之间的界限在实践中相当模糊,但我赞赏他们强调分类而不是架构分层,以及强调接口而不是实现。Mulesoft 的三层架构和 Ryan 和 Praful 的三种服务分类都是有用的模型,可以用来思考将服务分解以实现可组合性的正确方法,但我认为,通过关注数字能力而不是关注实现问题(如编排和连接),我们可以获得更大的可组合性。
致谢
非常感谢所有在过程中通过批判性反馈帮助我的人,尤其是 Ed Wilson、Rebecca Parsons、Martin Fowler、Sina Jahan、Kief Morris、Peter Gillard-Moss、Bruna Gonclaves、Ed Mangini、Ian Cartwright、Srinivasan Raguraman、Chris Ford、Charith Tangirala、Ken Collier 和 Matteo Vaccari。他们的反馈对于突出我原本没有在总体论证中明确说明的假设至关重要,这篇文章因他们的审阅而变得更好。任何不准确之处当然都是我的责任。
重大修订
2021 年 12 月 14 日:完成首次出版
2021 年 12 月 9 日:发布“使用商业集成工具简化实现问题”
2021 年 12 月 7 日:发布“使用通用语言管理接口演变”
2021 年 12 月 1 日:发布“将大部分精力投入构建干净的接口”
2021 年 11 月 30 日:发布第一部分