当前位置: 首页 > 科技观察

换血!重写旧系统的一场噩梦被我亲手终结

时间:2023-03-16 10:44:37 科技观察

换血!一场重写旧系统的噩梦,被我自己Influence终结了。更糟糕的是,当您尝试在更改代码之前编写单元测试时,您会发现代码最初并不是设计为可测试的。所以,在所有的挣扎和尝试之后,你可能只是冻结了应用程序,再也不想碰它了……那么,有没有办法既能改变无法维护的代码,又能不那么糟糕呢?我们知道更改代码是有风险的,重构的成本太高。在这种情况下,从头开始重写代码看起来是个好主意。按照这个思路,接下来会发生什么?您与管理层讨论在重写现有应用程序的同时禁用新功能一段时间。重写包含当前应用程序功能的新程序大约需要6个月。几个月后,一个严重的错误出现了,必须在旧代码中修复。因此,您再次修补旧代码和新代码。再过几个月,该公司向客户提供了一些新功能。但是新功能必须用旧代码实现,因为新版本还没有准备好。你不仅要重新回到旧代码,而且你还要添加一个TODO,以便在新版本中实现这些新功能。快进5个月,您意识到项目可能会延迟,并且遗留应用程序比您想象的更棘手。7个月过去了,你开始测试一个新版本,QA质量检查发现了很多需要修复的错误。9个月后,公司再也无法忍受“不开发功能”。领导不满意,你身心俱疲。您正在努力更改旧代码,同时以更快的速度重写它。最终结果是你做了两个系统。摆脱旧代码需要一段时间,因为新代码还没有准备好。每个特性都需要在新系统和旧系统中实现两次。最终,我选择了终止我当前正在处理这个问题的项目。我们有两个内部并行工作的系统:购物车(旧系统)和预订(新系统)。事实上,booking应该取代cart。这个项目三年前就开始了,但三年过去了,这个项目仍然没有完成。Booking一般比cart好,但不是所有方面都比cart好。有些采购流程会用到booking,但是还是有很多流程用到cart。新功能现在需要两倍的时间来实施,因为新旧系统并行工作。有趣的是,由于最初的设计目的并不是为了支持我们想要的新功能,而是因为预订有点过时,所以建议“适当重写购物车系统”。如果按照这个思路,在接下来的几个月里,我们可能希望两个系统并行运行。显然,这不是一个好的解决办法,而我知道还有一种解决系统问题的有效办法,那就是“杀”。如何“杀死”旧代码库很简单:逐步移除旧代码库并使用新代码库。方法如下:让新代码充当旧代码的代理。用户使用新系统,新系统重定向到旧系统。重新实现新代码库中的每一步,以便从最终用户的角度来看没有任何变化。通过让用户使用新功能来逐渐淡化旧代码。删除旧的、未使用的代码。说到我们的系统,我们有一个用于处理付款的购物车模块。我们试图重写,想法是创造一种新的、比购物车预订更好的支付方式。但是项目并没有100%交付,因为重写花费了太多时间,我们不得不在旧的购物车系统上开发新功能。最后,我们还是创建了两个模块。让我们再试一次,这次是“杀死”购物车模块。与以往方法不同的是,这次我们引入了一个新的预订模块作为代理服务器。它很容易设置。很快,我们就可以将支付处理逻辑交付到生产环境中,而无需复制它。然后,一步一步,我们可以开始将支付逻辑迁移到新的预订模块。在迁移逻辑时,我们去掉了cart模块上未使用的代码。这个过程可能需要一段时间,但我们正在逐渐放弃旧的、无法维护的购物车,并开始实施新的更好的预订。结论最好的地方是解决重写期间无法交付新功能的问题。使用这种技术,不需要重复代码,更不用说将新功能实现两次了。此外,您需要尽快让新系统上线,更快地获得反馈,最大限度地减少工作量并降低搞砸事情的风险。最后,您可以有条不紊地重写代码,而无需将代码冻结6个月。尽管“扼杀”可能很暴力,但这个比喻恰恰描述了慢慢摆脱旧系统,这比完全转换风险更小。当旧代码确实难以使用时,这可能是迈向更好设计的第一步。如果您正在进行领域驱动设计(DDD),我建议您使用这种方法来逐步淘汰遗留系统。您可以将遗留系统视为黑盒,并创建一个气泡上下文,在其中应用部署DDD原则。BubbleContext与遗留系统交互。逐渐地,新功能将在不断增长的Bubble上下文中实现。同时,在业务中使用旧系统的机会越来越少,直到有一天,你可以彻底关闭旧系统。