遗留系统替换模式

有效地对遗留软件系统进行现代化改造

当组织面临替换现有软件系统的需求时,他们往往会陷入一个半完成的技术替换循环中。我们的经验告诉我们,有一系列模式可以打破这种循环,这些模式依赖于:刻意认识到替换遗留软件的预期结果,将这种替换分解成多个部分,逐步交付这些部分,以及改变组织文化以认识到变化是永恒的现实。

2024 年 3 月 5 日


Photo of Ian Cartwright

伊恩·卡特赖特是 Thoughtworks 的技术总监,他利用自己 20 年的架构师和实践开发人员经验,帮助客户提高其技术能力。

Photo of Rob Horn

罗伯·霍恩是 Thoughtworks 的技术总监。他是一位经验丰富且充满热情的技术顾问和敏捷实践者,在他 25 年以上的职业生涯中,大约有 15 年时间致力于帮助客户解决金融、社会、旅游和公共部门的遗留系统现代化挑战。

Photo of James Lewis

詹姆斯·刘易斯是 Thoughtworks 的技术总监,也是技术咨询委员会成员。当他不参加关于相同主题的会议演讲时,他将时间花在为客户提供分布式系统架构和组织设计方面的建议。


在过去的几十年里,我们一直在帮助大型组织改造他们的遗留系统。在此过程中,我们了解了很多关于什么有效的方法,以及看到了许多导致失败的路径。我们决定抽出一些时间,将我们学到的知识记录下来,以各种我们见过的模式的形式呈现。

本文充当这些模式的中心。我们经常看到组织陷入半完成的遗留系统替换工作循环中。我们认为,打破这种循环的关键在于按顺序执行四项活动,但主要是在公司的生命周期中迭代执行。我们将这些活动用作组织我们描述的模式的主要结构。

我们一直认为,有效的软件开发涉及逐步发布有价值的功能,我们认为编写也是如此 - 尤其是在网络时代。我们从这篇叙事文章开始,并将逐步添加模式,因为我们写下了它们的详细信息,以及其他展示它们如何组合的示例。我们不能保证任何日期,因为我们的首要任务是客户工作,而客户工作并不缺乏需要替换的遗留系统。如果您有兴趣在这些工作出现时听到更多内容,它们将在 马丁的推特 和本网站的 RSS 提要 上发布。

遗留系统替换的循环

我们与许多组织合作过,这些组织多次尝试移除遗留系统。在一个相当典型的组织中,他们经历了一系列 3-5 年的现代化计划。每次他们都会定义一种新的技术方法,然后作为大型多年现代化计划的一部分,朝着这种新方法努力。

在每个计划的某个阶段,他们都会遇到一个临界点,此时不断变化的业务需求会超过他们当前的技术策略,从而引发重新开始的必要性。如果他们采用了瀑布式“大爆炸”方法来实施该计划,这意味着要放弃大部分工作。在其他情况下,如果采用了更渐进的交付方法,采取的方法只是在已经很复杂的架构之上添加一层稍微更新的技术。对于这两种情况,他们都无法停用任何遗留堆栈,成本节约和风险降低的关键业务目标仍然无法实现,这是许多遗留系统替换工作中常见的结局。

他们在反复失败中发挥作用的几个关键因素。

首先,他们所看到的糟糕结果很大程度上是组织的产物;具体来说,是其领导层、结构和工作方式。他们认为,只要选择更新的技术,而将其他所有东西保持不变,他们就能从过去获得不同的结果。事后看来,这显然是不切实际的。

其次,现代化工作将由一个大型变更计划交付,该计划本身包含一系列项目和团队。这些项目被视为与任何 BAU(业务照常)工作正交。因此,业务需求的 BAU 交付继续针对现有系统进行,而新项目团队则针对在替换计划开始时商定的需求集进行交付。

随着时间的推移,他们发现业务实际需要的东西与计划开始时实际签署的东西之间存在越来越大的差距。每个计划运行的时间越长,计划与 BAU 和未来需求之间的差距就越明显。虽然变更控制流程已到位,可以将新需求添加到计划中,但这些流程非常耗时,并且由于前期供应商合同,成本高得令人望而却步。

几个失败中的第三个关键因素是对现有系统和业务流程的 功能一致性 的渴望。这些尝试从承诺为业务提供与今天完全相同的东西开始,但不知何故,在幕后,技术已经“改进”。由于已经看到了多次失败,并且担心会造成混乱,业务领导者认为这是一种风险较低的策略。这里的挑战是,即使定义和商定当前的“现状”功能也是一项巨大的工作,它导致了对大型单次“大爆炸”切换发布的计划。

我们从这个组织和许多其他组织的观察结果表明,技术最多只占遗留问题的一半,工作方式、组织结构和领导层对于成功同样重要。

打破循环

显然,需要打破“技术替换计划”的循环。简而言之,组织需要能够在不断交付业务需求的同时,替换过时的技术,所有这些都在加速的技术变革和更激烈的竞争环境的背景下进行。

我们发现有一系列方法可以帮助解决这些挑战。它们有助于将问题分解成更小的部分,以便能够与改进的技术并行交付新需求。从广义上讲,它们可以分为四类

  1. 了解您想要实现的结果
  2. 决定如何将问题分解成更小的部分
  3. 成功交付各个部分
  4. 改变组织以允许此过程持续进行

了解您想要实现的结果

对于组织来说,在解决遗留问题时,商定他们想要实现的结果至关重要。虽然这似乎很明显,但组织的不同部门对预期结果的看法往往大相径庭。大多数遗留系统现代化计划都涉及我们列出的几个结果,但重要的是在踏上旅程之前确定哪些结果是优先事项。

降低变更成本

许多组织决定解决遗留问题的关键转折点是,他们想要的业务变更的成本开始远远超过任何预期的收益,无论是由于机会成本(即延迟)还是实施成本。一个早期预警信号是,必须花费数周时间以及数十万或数百万美元才能对网站进行更改,而这些更改只会带来少量业务绩效提升。

在这一点上,通常不再可能证明进行任何不带来高投资回报率的更改是合理的。换句话说,技术的现状已经开始决定业务可以进行的变更规模。对于许多组织来说,这意味着在进行“BAU”变更或必须启动更大的项目之间做出选择。这些更大的项目随后会成为所有以前不可证明的小变更的磁铁,从而增加了它们的范围、成本和风险

改进业务流程

我们已经看到了很多例子,其中业务流程在遗留系统旁边不断发展,这些流程与系统的运作方式紧密耦合,系统中的约束以及通常的“系统外”变通方法塑造了人们在工作中遵循的业务流程。

我们看到的一个例子是航空公司值机系统,该系统使用“绿屏”终端,由于遗留系统的限制,必须严格按照顺序执行该流程,这意味着更正或错误意味着重新开始值机流程。此外,航空公司最初没有提供联程航班,当添加联程航班时,由于该技术的限制,它必须作为遗留系统中的一个单独工作流程进行。因此,如果乘客在值机时没有提到他们有联程航班,就会执行错误的流程,包括打印错误的行李标签,只有在此之后,系统才会标记联程航班。值机人员的工作和乘客的体验本来可以得到很大改善,但由于遗留系统,这是不可能的。

鉴于此,更新和更改业务流程反过来需要更改支持技术的工作方式也就不足为奇了。尝试在不改变技术的情况下更改工作流程,通常会导致“系统外”工作,即人们诉诸于将数据提取到电子表格或类似工具中,在那里进行处理,然后将数据导入回遗留系统。

在一个组织中,整个库存订购流程实际上是在团队经理的个人电脑上运行的 Microsoft Access DB 上完成的。他们感到沮丧,因为遗留系统无法支持其供应商的更新工作实践。他们每周进行几次数据导入和导出,在此期间,组织的其他部门会看到过时的数字,因为没有人意识到发生了什么。

值得注意的是,替换系统以支持数据导入和导出的需求通常源于这种变通方法。

停用旧系统

停用旧系统是遗留系统现代化的一个常见原因。这通常是由支持旧硬件或软件的挑战所驱动的,例如支持成本不断上升以及硬件和软件的支持合同到期。

我们发现,从业务的角度来看待旧系统的退休很有用。因此,一个系统建立在旧技术之上本身并不足以成为替换的理由。相反,我们需要关注这带来的业务影响,例如不断上升的运行成本,或者缺乏支持或对系统了解不足带来的风险。

虽然一些组织确实为旧技术的过时做了很好的计划,但许多组织似乎忽略了这个问题,直到它达到危机点。反过来,这往往会促使组织采用看起来像是低干扰选项或快速获胜的现代化方法,这些通常是反模式,我们将在后面描述一些这些陷阱。

多年来,我们对许多大型组织如何在其业务中运行不受支持的硬件和软件感到震惊,在 eBay 上购买备件是一个令人惊讶的常见故事。如果你有遗留技术,那么进行适当的调查并创建一个包含各种生命周期结束支持日期的日历非常值得。

虽然许多组织将旧系统的退休作为遗留现代化的关键成果,但通常会发现这实际上并没有发生,遗留系统仍在使用,相关的业务目标也未实现。

迫在眉睫的颠覆

对于一些组织来说,解决遗留问题的实际临界点可能是由于外部因素,例如监管变化、新的“初创”竞争对手或现有竞争对手的重大变化。通常在这一点上,面对“必须做”的改变,很明显,应对所需的资金和时间已经变得太大。

外部事件让组织领导层清楚地认识到,他们不再有能力以成比例的成本进行改变。

更新的技术

采用新技术不应该是遗留现代化的理由,仅仅为了新技术而新技术很少是任何组织的关键目标。相反,应该以最能满足当前和未来业务需求的方式选择和使用新技术。这里的一个挑战是技术变化的速度正在加快,“有用”的技术生命周期正在缩短。“有用”的实际定义取决于组织,但总的来说,我们需要考虑以下因素:

  • 允许竞争优势
  • 匹配竞争对手或市场产品
  • 允许更快的变化速度
  • 更便宜的改变
  • 运行成本更低

我们今天对最佳和最有用的技术的决定,很可能在相对较短的时间内被更好的替代方案所取代。这使得找到满足未来需求的技术的正确决定可能非常冒险。

这里一个好的方法是不做任何不能在 2-3 年内轻松“重做”的决定。这对技术选择和整体设计和方法都有影响。选择一个需要 5-10 年才能收回成本的巨大平台很难证明,因为我们承认这种变化正在加速。

决定如何将问题分解成更小的部分

广义地说,这涉及在当前的业务和技术架构中找到合适的“接缝”。重要的是,你必须考虑当前解决方案的各个元素如何映射到不同的业务能力。对于遗留系统,这通常意味着发现一个大型技术解决方案如何满足多个业务需求,然后看看是否有可能提取单个需求以使用新解决方案独立交付。理想情况下,这些应该能够以最小的相互依赖关系交付。

一个常见的反对意见是,找到这些接缝太难了。虽然我们同意这在开始时很有挑战性,但我们发现它比其他方法更好,其他方法往往会导致功能一致性和大爆炸式发布。我们还观察到,许多组织排除了这种方法,因为他们孤立地看待技术或业务流程。仅仅改变技术的一部分,或者独立更新一个业务流程,很可能失败,但如果我们能够一起考虑和实施这两个方面,那么就有办法“吃掉大象”。

入门

遗留现代化在旅程开始时似乎是一个最令人望而生畏的命题。就像任何旅程一样,我们必须首先尝试了解要采取的初始方向。此外,就像所有旅程一样,你必须从你所在的地方开始。我们遇到的一个常见问题是,我们似乎经常在一个没有看到前方景观的森林里开始,因此不知道要走的方向。因此,第一步是爬上一棵树,环顾四周!这意味着在最短的时间内尽可能多地了解当前的系统和架构。这通常非常难做,很容易陷入过多的细节中。

幸运的是,有一些非常有用的工具可以协作使用,以获得足够好的理解来继续。这些工具将在其他地方详细讨论,但摘要列表将包括 事件风暴沃德利映射、业务能力映射和领域映射。请注意,在这个列表中,我们主要关注的是业务概念如何映射到系统架构,以及反过来了解该 架构如何支持价值创造。这是一种通常缺失的视图,特别是对于遗留系统。

理解问题的模式
创建城镇计划 †确定组织的稳定部分,以便围绕它们构建团队和软件
事件风暴 †用于理解业务流程的技术
识别业务能力 †确定组织的稳定部分,以便围绕它们构建团队和软件
价值流图 †描述用户如何完成工作的工件

† 目前只是一个存根

具体来说,我们发现人们经常在遗留系统的边界处停止发现式活动,“这里有龙”,不要再往前走了。如果不越过边界,揭示遗留系统如何支持(或阻碍)业务流程和活动,就很难找到和提取薄片来交付。

另一个经常被忽视但非常有价值的信息来源是系统本身的用户。事实上,根据作者的经验,这通常是你能够找到大量有用信息的地方,尤其是暴露了通常围绕旧系统构建的许多变通方法和影子 IT 生态系统——也就是说,实际上运行业务的 Access 数据库和版本化的 Excel 电子表格。客户旅程映射、创建服务蓝图和价值流映射是用来有效地呈现这种细节的工具。

分解问题的模式
提取产品线按产品线识别和分离系统。
提取价值流 †识别和分离关键价值流
功能一致性使用新的技术栈复制遗留系统的现有功能。

† 目前只是一个存根

成功交付各个部分

对更快变化的需求以及能够增量交付和独立更改业务元素而无需大型依赖关系,往往会导致“敏捷”交付方法以及基于微服务的架构。对于这些可独立部署的组件,持续交付成为必不可少。除了普通的软件交付之外,让这变得具有挑战性的是,要找到从现有大型解决方案中切断、与之共存以及最终替换元素的策略。有几种成功的策略,包括并行运行、入口分叉和流量转移。

交付模式
金丝雀发布 †将更改推广到一小部分用户
关键聚合器结合来自业务不同部分的数据,以支持做出关键决策
暗启动 †调用新的后端功能,但不使用结果,以便评估其性能影响。
转移流程首先将跨组织活动从遗留系统中转移出去
事件拦截拦截对系统状态的任何更新,并将其中一些路由到新组件
遗留系统模拟新系统以旧系统无法察觉任何更改的方式与遗留系统交互。
恢复到源代码识别数据的源头并集成到该源头
停止世界切换 †在切换到新系统时暂停正常的业务活动
过渡架构安装的软件元素可以简化遗留系统的替换,我们打算在替换完成后将其删除。

† 目前只是一个存根

改变组织以允许此过程持续进行

如果我们退一步,看看交付新业务需求的整个过程,我们可以很快发现这只是一个部分的技术问题。如果我们使用新技术来缩短构建解决方案的时间和成本,那么我们将突出显示在达成一致需求和将更改投入生产方面遇到的任何问题。

我们需要组织结构和流程的改变,以充分利用更好的技术,并且根据 康威定律,我们还需要一个能够促进这种改变的技术架构。如果团队及其沟通方式围绕着现有的遗留解决方案和流程进行组织,我们可能需要使用 逆康威操作 对其进行重组,以匹配新的解决方案及其架构。

遗留系统会限制和限制采用更现代的工程实践的能力,尤其是那些与极限编程和持续交付相关的实践。在替换遗留系统时,重要的是要确保工作方式发生改变,以确保我们不会最终得到一个速度慢、难以改变且成本高昂的系统。

遗留也是组织文化和领导力的产物,如果没有更广泛的改变,你应该预期与以前相同的成果。我们已经观察到许多遗留现代化工作由于“企业抗体”而失败,这些抗体发现了一些新的变化,并采取行动将其从组织中剔除。

举一个大型组织如何拒绝改变的例子:我们与一家非常大的电信公司合作,该公司希望为手机构建软件。领导层都理解这意味着比他们看到现有的专注于固定基础设施的程序更快的反馈周期和更频繁的更改。

虽然领导层理解这一点,但他们没有对现有的工作实践或管理这些流程的中层管理人员进行任何改变。因此,现有的变更控制流程被严格地应用。最终,软件团队花费在填写变更控制表格和参加变更控制会议上的时间比他们生产软件的时间还要多。“企业抗体”成功地拒绝了这种新的工作方式。

组织变革是一个很大的话题,已经有大量的文献可供参考,遗留系统面临的主要挑战往往与时间有关。很少有组织能够在重构(或重建,对于外包受害者来说)整个交付方式以及组织结构和关键业务流程的同时,推迟遗留系统现代化。虽然组织转型这一更广泛的话题超出了我们的范围,但我们确实建议了一些在遗留系统环境中应用和保护新工作方式的策略。如果你只是改变遗留系统而不做其他任何事情,那么可以预料你将在几年内再次替换遗留系统。

持续组织变革的模式
构建时就打算继续 †以你希望在遗留系统上线后继续的方式创建遗留系统替换。
增量替换 †以你希望在遗留系统上线后继续的方式创建遗留系统替换。
新公司 †成立一家全新的公司来追求市场颠覆。
受保护的试点 †创建一个新的工作试点项目,并将其与正常的公司治理流程分离。

† 目前只是一个存根

当然还有其他组织转型策略和方法,我们只是重点介绍了这两种方法,因为在某种程度上,它们允许更早地开始遗留系统现代化工作,而不是推迟。

示例:集成中间件移除

这个例子描述了我们团队如何使用多个遗留系统现代化模式,成功地替换了对客户业务运营至关重要的集成中间件,作为更大规模的遗留系统现代化项目的一部分。他们结合了模式和重构,成功地管理了业务风险,并促进了吃掉这头大象中特别难啃的部分。

了解结果

我们团队面临的挑战是如何用一个新的可支持、灵活的解决方案来替换已经不再支持、难以更改且成本很高的集成中间件,而不会中断或危及现有的业务运营。所讨论的中间件用于在后端系统和店面之间进行集成。这些系统共同负责每天销售价值数千万英镑的独特高价值产品。

这项工作是更大项目中的一个高优先级部分。支持业务的所有后端系统都将被替换,店面也将在几年内进行现代化改造。

因此,根据上面的步骤 1,团队需要实现的业务成果被定义为:

  1. 改进业务流程
  2. 如何改进?这个特定的集成中间件解决方案包含大量的逻辑,包括业务核心规则,例如在哪个渠道上销售产品,或者如何在店面内何时展示产品。这个现有系统非常难以更改,阻碍了业务创新,逻辑中的缺陷导致了一些问题,例如产品在一段时间内甚至无法出售!

  3. 尽快淘汰旧系统
  4. 为什么?为了降低现有的(并且不断增加的)许可证和支持成本。此外,为了减轻在过时的中间件和数据库技术上运行关键功能而给业务带来的风险。

Integration Middleware Removal Example

分解问题:第一个缝合点和重构

初始阶段,团队与那些对遗留系统有深入了解的人员一起进行了一个研讨会,以协作地可视化现状和目标软件架构。完成此操作后,他们发现了一个可以利用的技术缝隙,即遗留后端和集成中间件之间的基于消息的集成。遗留后端是一个老化的 J2EE 应用程序,它将“发布产品”消息放到一个由非常旧版本的 SwiftMQ 提供的队列中。 事件拦截 模式在这里很有用,如果将其实现为 基于内容的路由器,它将允许控制来自遗留后端的路由消息的方式,并创建一个选项,使消息能够路由到新系统。

集成中间件还处理来自店面的消息(例如,用于产品销售),使用 JDBC 直接更新遗留后端背后的主数据库中的状态。异步消息通过 SwiftMQ 和 JDBC 数据库更新共同构成了遗留后端和集成中间件之间的接口。

Branch by abstraction

虽然当时没有发现,但团队能够在子系统级别使用 分支抽象 模式,作为启用遗留中间件替换的策略。抽象层是队列和 JDBC。通过确保新实现符合该抽象层,它可以被替换为“有缺陷的供应商”,而不会影响业务运营。

团队首先通过重构实现事件拦截,添加了一个事件路由器。

(P)Refactoring to add Event Interceptor

事件路由器 (1) 的创建考虑了三个主要功能:

  1. 从一个 SwiftMQ 队列中出队消息,并将它们入队到另一个 SwiftMQ 队列中 (2)。一些配置的微小更改使集成中间件能够从这个新队列 (2) 中消费消息。
  2. 总的来说,重构使观察到的系统行为保持不变,但事件路由器现在已成为过渡架构的一部分,已插入消息处理管道中。

  3. 事件路由器的愿景是通过配置启用将消息路由到备用目的地,从而使新实现能够处理发布消息。 事件拦截
  4. 事件路由器还将提供从旧的 SwiftMQ 技术到为目标架构选择的新的 ActiveMQ 技术的桥梁。

实现事件路由器并不像预期的那样简单。由于缺少可用的驱动程序/库,与 SwiftMQ 集成存在问题,并且该方法多次受到挑战。团队了解了这种方法将解锁的选项的价值,并完成了工作并发布到生产环境中。他们监控了新组件在野外的运行情况,并准备使用新的 持续交付 管道逐步增强其功能。

成功交付各个部分:构建功能,维护契约

New Implementation and Rollout

新的店面管理器 (1) 现在由团队迭代构建。与本示例相关的是,该构建包括实现遗留模拟模式的主数据库适配器 (2)。这是作为抽象层的一部分所需的,用于使用从店面接收到的销售信息更新主数据库。由于事件路由器不会转换消息,因此创建了一个遗留事件适配器 (3) (消息转换器),用于将消息转换为新格式,不会将遗留世界暴露给新世界,并符合新架构的原则。遗留店面 适配器(4) 也在新的店面管理器 (1) 和遗留店面之间实现,以隔离新实现,使其不受将来店面替换时发生的更改的影响。

在遗留店面 (5) 上引入了一个新的 API,新的店面管理器将使用它。此外,还添加了一个功能,使新 API 上发布的产品的回调可以发送到新的店面管理器的适配器 (4)。重要的是,这使遗留实现和新实现能够并行运行。

成功交付各个部分(续):过渡到实时服务 - 使用第二个缝合点

所有部分都到位后,企业能够测试新的解决方案,但如何以**风险管理的方式**将其推出到实时服务中。

为了做到这一点,他们利用了另一个缝隙——这次使用按产品细分模式。事件路由器得到了增强,可以根据产品类型和唯一产品 ID 添加可配置路由 (6)。团队能够根据 ID 测试单个产品的发布、管理和销售,然后随着时间的推移,使用越来越多的产品类型配置路由器,实质上增加了由新解决方案处理的产品百分比。

当所有产品都由新系统处理时,遗留集成中间件被停用,实现了许可证、支持和数据中心托管费用的显著节省。

Legacy Gone

改变组织以允许此过程持续进行

我们的团队已经在组织的另一个部门与客户合作,并且已经成功地替换了另一个遗留系统。

在整个组织的工程层面上,持续交付和良好的支持质量实践现在已成为既定规范,微服务风格的架构使容器化服务能够定期且独立地部署到基于云的平台上。

新项目中的团队与新的利益相关者合作,需要将业务的这一部分也带到相同的“敏捷和 CD”旅程中,早期的风险管理发布使信任得以建立。随着时间的推移,可以证明新的工程和质量实践(包括 CD)如何减轻历史上导致更高程度的官僚主义和治理的相同风险。因此,较少频率、较大范围的发布也被较小、更频繁、更高置信度的部署所取代,并在企业准备好接受更改时向企业发布切换发布。

结束语

当然,与上面简化的故事中所暗示的相比,复杂性和集成需求要大得多。在生产环境中测试新实现后不久,就出现了对考古学需求的示例。一些对业务至关重要的管理信息报告不一致——产品“丢失了”。

经过深入调查,团队发现集成中间件使用的数据库(用于存储长时间运行的业务事务状态)被复制到组织的数据仓库中。通过一系列批处理作业、存储过程和视图,这些数据被用于业务关键 KPI 报告。

LegacyModernizationExample_Archeology

为了确保这些报告不会中断,需要额外的遗留模拟。团队在来自店面的销售消息上使用了 线缆监听,并使用 JDBC 将数据注入数据仓库中的相应表格。这些额外的模拟也成为了过渡架构的一部分,并在可能的情况下被移除。

抽象分支方法以及上面描述的模式和实践旨在降低风险。

使用事件拦截(技术缝合)、遗留模拟和过渡架构,客户能够将问题分解。然后,通过产品(业务缝合)进行细分,在本例中为产品类型,可以对更广泛的推广进行精细控制,并进一步管理风险。总体而言,这种方法允许企业以他们舒适的速度进行系统替换。

这种方法可以管理风险,但也有成本。因此,需要考虑的问题是“企业对这种风险缓解的价值如何?”明确并量化它,将允许团队跟踪针对它的投资。事件路由器和遗留模拟是过渡架构的一部分,旨在管理风险。它们的作用是创造选项,使风险能够得到管理。这种工作很容易被视为“一次性”——因此,应尽可能避免成本。在“风险缓解价值”与“过渡架构成本”的权衡中,要明确和透明。


致谢

Bill Codding、Chris Ford、James Emmott、Kief Morris、Mark Taylor、Meaghan Waters、Peter Gillard-Moss、Rebecca Parsons 和 Simon Brunning 在我们的内部邮件列表中讨论了这些模式的草稿。James Emmott 建议在标题中使用“置换”。

卡片插图中使用的曼彻斯特新旧电车照片来自 Picasa,经过裁剪和颜色处理。

重大修订

2024 年 3 月 5 日: 事件拦截

2022 年 7 月 7 日: 恢复到源发布

2022 年 3 月 28 日: 过渡架构首次发布

2022 年 1 月 20 日: 转移流程

2022 年 1 月 19 日: 关键聚合器

2022 年 1 月 12 日: 遗留模拟

2021 年 7 月 27 日: 功能一致性

2021 年 7 月 21 日: 提取产品线

2021 年 7 月 20 日: 遗留置换模式发布