如何在迁移前重构遗留应用

如何在迁移前重构遗留应用

💡 原文英文,约3400词,阅读约需13分钟。
📝

内容提要

迁移前重构比直接迁移更安全。先选定业务能力(如订单处理),用特征测试保护行为,再分离业务规则与基础设施,引入仓储、支付等接口适配器,隔离副作用,改善依赖方向。每次小步重构后运行测试,避免混入行为修复。AI可辅助识别依赖和审查差异,但不应过早设计目标架构。当能力边界清晰、外部依赖可替换时即可开始迁移,无需追求完美架构。

🔎

延伸解读

迁移前重构的边界选择

文章强调,迁移前重构不应变成无休止的清理项目。关键在于先选定一个业务能力(如订单处理)作为迁移边界,只重构阻碍该能力安全迁移的部分。例如,订单处理直接调用MySQL和Stripe SDK是相关的问题,而报告模块的日期格式或管理界面的CSS则无关。这种范围纪律能避免准备工作变成开放式清理,确保重构服务于迁移目标。

依赖方向改善的实际意义

通过引入接口(如OrderRepository、PaymentGateway)并让具体实现(如MySqlOrderRepository、StripePaymentGateway)依赖抽象,可以改善依赖方向。这并非为了追求整洁架构,而是为了创建可替换的边界。当基础设施可以独立替换时,迁移数据库或支付提供商就不再需要重写业务逻辑,从而降低迁移风险。

AI辅助重构的正确用法

文章建议,使用AI时应给出具体、受限的任务,例如“引入OrderRepository接口而不改变行为”,并要求AI解释每个结构变更。AI还可用于对比重构前后的实现,检查异常、返回值、副作用顺序等是否变化。但应避免让AI过早设计目标架构,因为架构选择应基于团队规模、事务要求等约束,而非模式识别。

迁移就绪的判断标准

文章提出,当你能清晰回答以下问题时,能力就接近迁移就绪:输入输出是什么?业务规则是否可见?外部依赖是否显式(如通过接口)?基础设施能否被替换而不影响业务逻辑?关键行为是否有测试保护?副作用是否明确?如果这些答案清晰,即使代码不完美,也可以开始迁移,无需追求完美架构。

Q&A

为什么在迁移遗留应用之前要先进行重构?

因为遗留系统往往将业务规则、持久化、基础设施、外部集成和编排混杂在一起,直接迁移会同时移动多种职责,增加风险和难度。先重构可以分离这些关注点,使重要行为能够独立迁移,从而降低迁移的复杂性和风险。

在迁移前重构遗留应用时,如何选择迁移边界?

选择迁移边界时,不要从清理整个应用开始,而应先确定要迁移的第一个业务能力,例如“处理订单”。然后围绕该能力映射其输入、业务行为和副作用,以此作为重构的边界。这样可以使重构更有针对性,避免范围蔓延。

如何将业务规则与基础设施分离?

可以通过提取纯业务逻辑来实现,例如将价格计算等决策逻辑从数据库和支付SDK等基础设施中分离出来。具体做法是创建一个纯函数,如calculateOrderTotal,它只依赖订单数据,不涉及任何外部系统。这样业务规则就可以独立于基础设施进行测试和迁移。

在遗留应用中引入接缝(seam)的目的是什么?

引入接缝的目的是为了替换硬依赖,使依赖可以被替换或模拟。例如,将直接创建数据库客户端的代码改为通过接口注入OrderRepository,这样在测试或迁移时可以轻松替换为其他实现,而无需修改业务逻辑。

如何隔离副作用与决策逻辑?

将业务决策(如订单能否取消、新状态是什么)提取为纯函数,例如cancelOrderState,它只返回新状态。而副作用(如持久化、释放库存、退款、审计)则保留在编排层。这样决策逻辑可以独立测试和迁移,不受副作用执行方式变化的影响。

为什么要把外部系统放在适配器后面?

因为外部SDK(如Stripe)如果被大量模块直接依赖,替换或迁移支付处理会非常困难。通过定义应用层接口(如PaymentGateway)并创建适配器(如StripePaymentGateway)来封装SDK,可以本地化供应商特定代码,使应用只依赖抽象,从而便于替换外部系统。

在重构过程中如何利用AI辅助,同时避免其盲目设计目标架构?

AI可以用于识别依赖、提取接口、审查差异等,但应给出受限的转换任务,例如“引入OrderRepository接缝而不改变可观察行为”,并要求解释每个结构变更。避免让AI直接设计目标架构,因为架构应基于约束(如部署频率、团队规模、事务要求)而非模式识别。

如何判断一个业务能力是否已准备好进行迁移?

当你能清晰回答以下问题时,该能力就接近迁移就绪:能描述其输入和输出;重要业务规则可见;外部依赖明确;基础设施可替换(如更换MySQL不影响定价逻辑);重要行为有测试保护;知道所有副作用;主要未知点已记录。

迁移前重构时,哪些内容不应该做?

应避免大规模重命名、格式化整个仓库、替换所有模式、重写稳定算法以及修复所有发现的bug。这些活动会产生大量噪音,使行为变更难以审查,且可能引入意外行为变化。应聚焦于直接阻碍迁移的耦合点。

迁移前重构的最终目标是什么?

最终目标不是追求完美架构,而是创建“可迁移友好”的结构,使业务能力能够独立迁移。重构应停止在能力变得可移动时,而不是继续清理代码。这样迁移就变成一系列受控的变更,而不是一次重写。

🏷️

标签

➡️

继续阅读