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

接手历史悠久的老项目,干还是跑?

时间:2023-03-22 00:47:40 科技观察

本文转载自微信公众号《跨界建筑师》,作者Zachary。转载本文请联系跨界架构师公众号。大家好,我是Z哥,这是我的第199篇原创,离200只差一步。为了庆祝这个重要的时刻,我也在考虑要不要在第200篇的时候搞点小活动。还没想好,下周去看看。不过不管怎样,还是要为Z哥的坚持点个赞,哈哈。所以,看完文章,别忘了拉到文末点个赞哦~好了,言归正传。许多人抱怨旧项目多么垃圾。这确实是个大问题。据IEEESpectrum此前发布的一份报告显示:自2010年以来,全球在IT产品和服务上的支出约为35万亿美元,其中约四分之三用于运营和维护现有的IT系统。此外,至少有2.5万亿美元用于更换遗留IT系统,其中约7200亿美元浪费在失败的更换工作上。https://spectrum.ieee.org/computing/it/inside-hidden-world-legacy-it-systems因此,程序员社区面对不堪重负、历史气息浓重的旧项目将是一种常态。但是我们能做什么呢?是硬着头皮填别人挖的坑,还是跑路?如果不跑路,最常见的应对方式无非是“重写”或者“重构”。1.Rewriting一般来说,越年轻的程序员越喜欢rewriting。除了青春活力的原因,更主要的是我可以彻底摆脱旧代码的技术债和束缚,可以充分发挥自己的才能。但是,对于旧系统的改写,没有高层的支持,没有业务部门的配合,没有可靠的开发团队,这件事要按预期完成的可能性微乎其微。而且,选择“rewrite”的解决方案,并不只是重写一组代码那么简单。系统切换也很头疼。在更复杂的项目中,就像重写一套代码一样困难。而一旦选择了“rewrite”,就意味着旧的系统会被并行开发一段时间,或者会积累很多的需求。业务方能否继续支持“rewrite”也将面临很大的挑战。甚至这些问题都可以解决。“改写”的另一种可能结果是,几个月后,改写后的系统在别人眼里就变成了“破烂不堪的旧系统”。这是最讽刺的……如果在重写过程中出于任何原因牺牲了质量,那么讽刺很可能是真实的。所以,很多公司之所以不支持改写,是因为不是不能用。这样一来,他们并不迂腐,也是一种理性的选择,他们是对的。二Refactoring相对来说,年纪大的程序员可能更倾向于refactoring。毕竟,他们有更多机会看到和体验那些痛苦的重写事件。当然,主要原因是他们掌握了更多处理“垃圾代码”的方法,相信小规模的代码重构也能化腐朽为神奇,提升项目质量。确实如此,但有一个前提。即垃圾代码的产生率低于重构的速度。但是对于大多数中小型公司来说,开发团队可能不具备这样的条件。因为熟练的程序员要么去管理岗位,要么负担太多,没有太多时间做重构。此外,技术不佳的程序员不断复制粘贴,挖更多的坑。通过重构改进老项目,可能永远走在“重构之路”上。而且,如果项目的技术复杂度大于业务复杂度,重构测试的成本会很高。除了这两种常见的方式之外,还有其他的方式来处理这些旧系统。他们的风险和回报在下表中得到了很好的体现。其实Z哥认为,这些方法我们都可以用,但是一定要遵循正确的思路。(什么是绞杀?继续往下读)首先,从业务角度考虑选择哪种方案。从业务敏捷性的角度来看,响应速度能不能做得更快?从运营效率的角度,如何通过系统改造提升业务运营效率?从客户洞察的角度出发,如何让系统更好地发现客户Insights,从而更好地理解客户需求,进化产品?第二,考虑系统本身,比如我们想通过改造获得多大的灵活性?最后,根据业务帮助的整体价值选择哪种方法。如果对业务的帮助是巨大的,完全值得投入大量资源重写,那就不要害怕小规模的重构。如果对业务帮助不大,那就别想重写了。老实说,只是在一个小范围内修补它。当你不确定解决方案时,选择模块替换是一个很好的方式,相当于通过一次更换一个部件来翻新整台机器上的所有部件,从而完成重写的效果。马丁·福勒称其为“绞杀法”。“绞杀”的最佳实践是DDD+微服务,因为它们可以提供更好的“隔离”和“自治”,更有利于“替换”。改造方案确定后,需要制定衡量指标,并在改造实施过程中持续监测这些指标的变化。最好通过可视化工具共享此信息。这有两个优点。一是让团队了解转型的进展和结果,确保转型朝着正确的方向前进;二是让相关干系人(领导、业务单位)也能了解工作进展情况,增加预期的确定性,不断获得他们的支持。具体的重构方法我就不说了,大家可以看我之前的文章《好的重构方法才能摆脱“屎山”》。你可以谈谈重写,我们以前没有谈过。我的建议是遵守以下原则。系统具有进化的能力。使用度量来跟踪进化方向。以小步骤快速迭代。01系统具有演化能力既然是改写系统,就一定要为可预见的未来做一些预留,以方便后续的演化。毕竟能够决定重写的系统,自然是比较核心的系统。技术上和业务上都将继续发生变化。关注系统的演化能力,是为了减少未来项目复杂度的增加。具体方法可以概括为三个词:抽象、分类(分层)、解耦。02用指标把握进化方向前面也提到了指标的价值。这里继续强调它的重要性。如果说改写期间,指标是衡量改写工作好坏的尺子,那么改写之后就是指导未来系统演进的灯塔。无论未来系统需要做什么升级改造,你对自己的认识越清晰,你的决策和选择就越合理。这就是指标的作用。随着业务逻辑的不断堆积,缺乏指标的系统很容易过度增长。03小步快迭代随着近年来CI/CD的流行,小步快跑的敏捷开发被越来越多的人提及并开始使用。它的好处是显而易见的,项目的可控性更高,容错能力更强。如果你不知道“一小步”有多“小”?可以只考虑release有没有问题,能不能快速回滚为准。可以快速回滚的迭代节奏是“小步”。其实重写系统后,还有一个很头疼的问题要解决,就是数据迁移。业界常用的解决方案有四种。我先概括一下主要思路,待会儿我会发一篇文章来讨论。01双写新库配置为老库的从库,从老库同步数据。写入数据时,不仅要写入旧库,还要写入新库。数据验证。双方数据完全同步后,灰度关闭流量。由于双写的存在,如果切换过程中出现问题,读写流量可以随时切换到老库,安全感强。02异步双写+对账这个方案其实是双写的一种变体,将同步写变成了异步写。因此需要一个对账机制来保证最终的一致性。一般这种异步机制要么通过MQ,要么通过数据库的binlog来实现。03直接使用新库,惰性数据迁移。在这个方案中,需要设置一个缓存层来存储数据key。流程如下:先访问新库,如果有数据,直接进入第3步,如果没有数据,进入第2步。访问旧库,找到对应的数据插入到新库中,然后进入第3步,进行业务逻辑操作……随着时间的推移,数据会慢慢从旧库同步到新库。使用同步工具对剩余未同步的数据进行全量同步。原则上,以上每一种方案在实际切换流量之前都应该对数据进行校验,以保证双方的数据一致。最后,迁移完成后,可以使用流量回放工具(如阿里的jvm-sandbox-repeater)或者全链路压测工具来验证新版本系统是否可以正常运行。好的,总结一下。在这篇文章中,Z哥给大家分享了处理旧项目的思路。总共有5种类型:重构、重新部署、更换平台、重写和绞杀。选择哪一个。接下来,我将详细阐述重写,我建议遵循三个原则:系统具有进化能力。使用度量来跟踪进化方向。以小步骤快速迭代。最后分享三种常见的新老数据迁移方案。双写异步双写+对账直接使用新库,数据懒迁移