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

您知道如何改进遗留代码库吗?

时间:2023-03-21 00:01:52 科技观察

这在每个程序员、项目管理员和团队负责人的一生中至少会发生一次。原来的程序员早就离开去度假了,给你留下了一堆勉强维持公司运转的数百万行狗屎和(如果有的话)与代码不匹配的文档。你的任务:带领团队走出困境。在你的第一反应(逃命)过去之后,你开始熟悉这个项目。公司的管理层都在看着你,所以项目只能成功;然而,看了代码之后,失败几乎是不可避免的。那该怎么办呢?幸运的是(不幸的是)我遇到过几次这种情况,我和我的伙伴们发现将这个热气腾腾的狗屎变成一个健康且可维护的项目是一项有利可图的业务。以下是我们的一些经验:备份在开始做任何事情之前备份所有可能与之关联的文件。这确保不会丢失在其他地方可能很重要的信息。一旦你修改了其中的一些文件,你可以花一天或更多的时间来解决这个愚蠢的问题。配置数据通常不受版本控制,因此特别容易受到这方面的影响。如果你定期备份你的数据,用它备份你就幸运了。所以谨慎总比后悔好,把所有东西都复制到安全的地方,除非文件是只读的,否则不要碰它。重要先决条件:你必须确保你的代码在生产环境中构建、运行和生成我假设环境存在,所以我完全错过了这一步,但是HackerNews上的很多人指出了这一点,结果证明他们是对的:第一步是确保你知道你在生产中运行的是什么,这意味着你需要在你的设备上构建一个每个字节都与生产中运行的版本相同的版本。如果你找不到办法去做,一旦你投入生产,你很可能会经历一些意想不到和可怕的事情。确保尽可能地测试所有内容,然后在您有足够的信心它可以工作时将其部署到生产环境中。准备好切换回旧版本,无论它运行得有多好,并确保记录所有内容以备不可避免的事后分析。冻结数据库。尽可能冻结你的数据库,直到你完成修改代码。在您非常熟悉代码库和遗留代码之前不要修改数据库。如果在此之前过早地修改数据库,可能会遇到大问题,失去让新旧代码和数据库共同打下坚实基础的能力。保持数据库完全不变,可以比较新逻辑代码和旧逻辑代码的运行结果,比较的结果应该和预期的没有什么不同。编写测试在进行任何更改之前,编写尽可能多的端到端测试和集成测试。确保测试输出正确并测试您对旧代码将如何运行的假设(为一些意外做好准备)。这些测试有两个重要的作用:第一,它们可以帮助你摆脱前期的一些误解,第二,这些测试在你编写新代码替换旧代码时也有一定的保护作用。自动化测试,有CI经验的可以使用,保证在你提交代码后CI能快速完成所有测试。日志监控如果老设备还在,增加监控能力。在一个新的数据库中,为您能想到的每个事件添加简单的计数器,并添加一个根据事件名称递增这些计数器的函数。通过一些额外的代码来实现带时间戳的事件日志,您可以了解有多少事件发生导致了其他类型的事件。例如:用户打开APP,用户关闭APP。如果这两个事件导致后端调用次数长期保持不一致,那么就是当前打开的应用数量。如果您发现打开的应用比关闭的多,您必须知道导致应用关闭的原因(例如崩溃)。您会发现每个事件都与其他事件有许多不同类型的联系,您通常应该尝试保持这些固定联系,除非系统中存在明显的错误。您的目标是在开始时通过在调用链中向下使用计数器到指定级别来尽可能减少这些错误事件。(例如:用户支付应该得到相同数量的支付回调)。这个简单的技巧可以将每个后端应用程序变成一个真正的簿记系统,就像一个真正的簿记系统,所有的数字都必须匹配,如果它们在某个地方不匹配,就会出现问题。随着时间的推移,这个系统在监控健康方面变得非常宝贵,它也是使用源代码控制修改系统日志的好伙伴,您可以使用它来识别错误何时被引入生产,以及什么影响了各种计数器。影响。我通常保持计数器每5分钟记录一次(每小时12次),但是如果您的应用程序生成更多或更少的事件,您应该修改此间隔。所有计数器共享一个数据表,每条记录只是简单的一行。一次改变一件事不要陷入在改进代码或平台可用性的同时添加新功能或修复错误的陷阱。这会让你很头疼,因为你现在必须弄清楚每一步操作的结果是什么,它会使你之前建立的一些测试失效。改变平台如果您决定将您的应用程序转移到另一个平台,最重要的是保持它与以前完全一样。如果您觉得有必要,您可以添加更多文档和测试,但不要忘记所有业务逻辑和相互依赖性都与以前相同。修改架构接下来要处理的是更改应用程序的结构(如果需要)。此时,你可以随意修改高层代码,通常是为了减少模块之间的横向联系,这样可以减少代码活动时对最终用户的影响范围。如果旧代码体积庞大,现在是时候将其模块化,将大块代码分解成许多较小的部分,但不更改变量名称和数据结构。HackerNews的用户mannykannot指出,修改高层代码并不总是可行的,如果你特别倒霉,可能要为一些架构上的改动付出惨重的代价。我同意这也应该在这里提示,所以这里有一些补充。另外我想补充的是,如果在修改高层代码的同时修改了一点点低层代码,尽量只修改一个文件或者最坏情况只修改一个子系统,尽量限制修改的范围尽可能。否则,您可能很难调试刚刚所做的更改。低级代码的重构既然您对每个模块的作用有了充分的了解,您就可以准备做一些实际的工作了:重构代码以提高其可维护性并为添加新功能做好准备。这可能是项目中最耗时的部分,记录您所做的一切,并且在您完全记录并理解它之前不要对模块进行任何更改。之后,您可以自由修改变量名、函数名和数据结构,以提高代码的清晰度和统一性,然后请进行测试(如果可能,包括单元测试)。修复错误既然您已准备好进行一些用户可见的更改,那么战斗的第一步就是修复多年来积累的大量错误。和往常一样,首先验证bug是否仍然存在,然后编写测试并修复bug,你的CI和端到端测试应该避免一些由于不熟悉或一些额外的东西而导致的错误。升级数据库如果您已经在可靠且可维护的代码库上完成了所有工作,您可以选择更改数据库模式,或者用不同的数据库完全替换数据库。之前完成的步骤将帮助您更可靠地修改数据库而不会遇到问题,您可以充分测试新数据库和新代码,并且之前编写的所有测试都可以确保您顺利迁移。遵循路线图恭喜您走出困境并准备好添加新功能。永远不要尝试完全重写完全重写是一种注定要失败的项目。一方面,你从未知领域开始,所以你甚至不知道要构建什么,另一方面,你将所有问题都推到新系统即将上线的前一天。不幸的是,这也是你失败的时候。假设发现业务逻辑有问题,你会觉得很奇怪,然后你会突然明白为什么旧系统会以奇怪的方式运行,并最终意识到可以将旧系统组合在一起的人也可以工作.不是所有的白痴。在那之后。如果你真的想毁掉公司(和你自己的声誉),那就去重写它,但如果你足够聪明,你就会知道完全重写系统根本不是一个选择。因此,替代方案:增量迭代工作解开这些纠结的最快方法是使用您熟悉的代码中的任何元素(它可以是外部或内核模块)并尝试使用旧上下文来增量改进。如果旧的构建工具不再工作,您将不得不使用一些技巧(见下文),但至少在您开始进行更改时,尽量保留已知的工作。这样,随着代码库的改进,您可以更好地理解代码的作用。典型的代码提交最多应该是两三行。发布!每个修改都会发布到生产环境中,即使某些修改对用户不可见。使用尽可能少的步骤也很重要,因为有时当您对系统缺乏了解时,只有生产环境才能告诉您问题出在哪里。如果在你只做了一个小的修改后出现问题,有一些好处:很容易找出问题所在这是改进流程的好地方你应该立即更新文档以展示你的新见解使用的好处代理如果您进行Web开发,谢天谢地,您可以在遗留系统和用户之间放置一个代理。这样你就可以轻松控制每个URL的哪些请求指向旧系统,哪些请求指向新系统,从而更容易和更精确地控制运行什么以及谁可以看到正在运行的系统。如果您的代理足够智能,您可以使用它为各个URL将一定比例的流量发送到新系统,直到您满意为止。如果您的集成测试也可以连接到此接口,那就更好了。是的,但这需要很多时间!这取决于你如何看待它。的确,按照上面的步骤优化代码,会有一些重复的工作步骤。但它确实有效,这里介绍的任何步骤都假设您对系统的了解比实际了解的多。我需要维护自己的声誉,而且我真的不喜欢在工作中遇到负面惊喜。运气好的话,公司的系统已经出问题了,要不然可能会严重影响到客户。在这种情况下,我更愿意完全控制过程并获得好的结果,而不是节省两天或一周。如果你更喜欢牛仔做事的方式,而且你的老板同意承担更大的风险是可以接受的,那么尝试冒险可能没有错,但大多数公司宁愿走稍微慢一点但更确定的胜利之路.