改进旧代码库的推荐路线:走向可扩展可维护系统的11条经验

每个程序员,项目经理或团队负责人的生命周期中至少发生一次,你接手一坨超过百万行代码的系统,原来的程序员很久以前就离职,现在也许正在某个阳光明媚的地方度假,文档(如果有的话)最有可能的情况就是与现有的系统不同步。

而你的工作则是带领团队脱离这个混乱。

在经历逃离的本能回应之后,您开始对项目进行了了解,公司高层领导是不能容忍项目失败的情况。然而,通过你手头现有的东西,失败是大概率发生的事件。那么该如何应对?

我有幸(或不幸)已经经历过若干次类似的经历,我和一小部分朋友发现,如果能够把这些垃圾代码变成健康的可维护的项目,实际上是非常值得一试的事情。以下是我们总结改进旧版代码库的一些经验(或者叫军规)。

1、数据备份

在开始做任何事情之前,您需要备份所有可能相关的内容,这样可以确保不管发生什么情况不会丢失数据。我们很难记得每天修改了哪些东西,特别是配置数据容易受到这种问题的影响,配置通常不会进行版本控制,如果能够进行定期备份,那则可以规避很多麻烦。把所有东西复制到一个非常安全的地方,除非它是只读模式,否则永远不会触摸到。

2、重要的先决条件,构建一个真实的仿真环境

我之前的文章中错过了这一步,假设这个环境已经存在了,但许多 HN 网友指出了这一点,他们是绝对正确的。

第一步是确保你知道现在正在生产环境运行的是什么,这意味着您需要能够构建一个软件版本 —— 和您的真实环境保持一致 —— 相同的软件环境与二进制版本。

如果你找不到一个方法来实现这一点,那么如果你提交代码到生产环境,就可能会遇到一些令人不快的意外。确保新的代码在合适环境尽可能地被测试,然后你才会有足够信心将其运行到生产环境。上线时做好准备可以随时切换回老的代码,并确保通过日志记录了相关重要内容,以便在后续排查问题能派上用场。

3、冻结 DB 修改

尽可能冻结数据库修改,直到完成第一阶段的改进,直到团队对代码库已经有了彻底的了解,遗留代码已经弃之身后时,才考虑修改数据库结构。在此之前任何的数据库修改可能会导致一些棘手的问题,你失去了并行运行旧系统和新的代码库的能力。保持 DB 完全不变,您可以比较新的业务逻辑代码与旧的业务逻辑代码,如果所有这些效果都与预期一样,则应该完全没有区别。

4、编写测试

在进行任何修改之前,编写尽可能多的端到端以及集成测试,确保这些测试能够产生正确的输出,并覆盖所有潜在的情况。

这些测试将具有两个重要功能:帮助在早期阶段清除任何误解,另外一方面,一旦您开始编写新代码来替换旧代码,这些测试将可以更好保护您的系统。

自动化您的所有测试,如果您已经有 CI 的经验则尽快使用它,并确保您的测试运行足够快,以便在每次提交后运行全套测试。

5、Instrumentation 和日志

如果旧平台仍然可以增加 Instrumentation,在一个全新的数据库表中执行此操作,为您可以考虑的每个事件添加一个简单的计数器,并添加一个单个函数来实现此功能,以根据事件的名称来增加这些计数器。

这样,您可以使用一些额外的代码行实现带有时间戳的事件日志,您将了解到有多少事件导致另一种事件。一个例子:用户打开应用程序,用户关闭应用程序。如果两个事件应该导致一些后端请求,那么这两个计数器应该在长期上保持不变,差异是当前打开的应用程序的数量。如果您看到更多的应用程序打开,而不是应用程序关闭,你知道必须有另一种应用程序结束的方式(例如崩溃)。

这个简单的技巧可以将每个后端应用程序变成一个类似的簿记(bookkeeping)系统,就像一个真正的簿记系统那样,所有的数字必须匹配,确保它们在所有用到的地方没有问题。

随着时间的推移,这个系统将监控健康方面变得非常宝贵,并且将成为源代码控制系统变更日志的一个很好的伴侣,您可以在其中确定每个错误引入的时间点,以及对各种情况产生影响的计数。

我通常保留这些计数器的分辨率为 5 分钟(因此每小时记录 12 次),但如果你的系统有更少或更多事件,则可能需要修改这个时间间隔。所有计数器使用同一个数据库表,因此每个计数器只是该表中的一列。

6、每次只修改一个点

在添加新功能或修复错误的同时,不要陷入同时改进代码以及修改其运行的平台的陷阱。这会导致很多头大的问题。

7、平台更改

如果您决定将应用程序迁移到另一个平台,那么请先执行此操作,但要保持一切功能完全一样。你可以添加更多的文档或测试,但不能超过这一点,所有业务逻辑和相互依赖关系应该保持原样。

8、架构变化

接下来要解决的是改变应用程序的架构(如果需要)。在这个时候,您可以随意更改代码的较高级别结构,通常通过减少模块之间的水平链接数量,从而减少与最终用户进行任何交互时代码活动的范围。如果旧代码本质上是一体的,现在将是一个很好的时机使其更加模块化,将大型功能分解成较小的功能,但是保留变量和数据结构的名称。

HN 网友 mannykannot 指出,架构修改并不总是可行,如果特别不幸运,那么可能需要非常深入理解代码才能进行任何架构更改。我同意这一点,因此我做个小的补充,如果您同时进行高级别更改和低级别更改,至少需要将其限制在一个文件,或最坏情况下限制在一个子系统,以便尽可能限制更改的范围。否则你可能很难调试刚才所做的更改。

9、低级重构

到目前为止,您应该对每个模块的功能有很好的了解,并为实际工作做好准备:重构代码以提高可维护性,并使代码具备扩展新的功能的能力。这很可能是项目中耗时最多的一部分,文档需要随之进行,在完整编写文档介绍并彻底了解一个模块之前,不要随意更改模块。

这个阶段也可以修改变量和函数命名、修改数据结构,以提高代码清晰度和一致性。记得添加相关测试代码(根据需要,可进行单元测试)。

10、修复 bug

现在你准备好进行一些最终用户可见的变化,第一件事情将是修复多年来积累在队列中的 bug。像往常一样,首先确认 bug 仍然存在,然后编写一个测试并修复 bug,您的持续集成和端到端的测试应帮您避免由于缺乏理解或某些错误而导致的任何错误及外围问题。

11、数据库升级

如果上述工作都已经完成,你可以再次拥有可靠且可维护的代码库,您可以选择更改数据库 schema 甚至替换数据库。已经完成的上述工作都将有助于您以无负担的方式进行变革,而无需担心任何意外,您可以使用新的代码和所有的测试来测试新的数据库,以确保您的迁移没有任何问题。

在路线图上前行

恭喜,到这里您已经走出了丛林,现在已经准备好可以实施任何新功能了。

不要尝试彻底重写

彻底重写是一种几乎保证会失败的项目。一方面,你是在未知的领域开始,你甚至会不知道要重构什么,另一方面,你也将所有的问题推到最后一天,就在你用新系统启用之前的那一天。很悲剧的是,那也是你失败的时刻。业务逻辑的假设最终会证实存在问题,那时您将突然了解到为什么旧系统会用某种奇怪的方式来工作,最终也会意识到能将旧系统放在一起工作的人也不都是白痴。 如果你真的想要将公司(以及你自己的信誉)带向一个泥潭,就来一个彻底大重写吧,但如果你足够聪明,彻底重写系统通常不会成为桌上的一个讨论选项。

替代方案:迭代式改进

要解开这些线团最快方法就是从你已经理解的代码入手(它可能是一个外围设备,但也可能是一些核心模块),并在它的旧的上下文的范围内尝试逐步改进。

如果旧的构建工具不再可用,您将不得不使用一些技巧(见下文),但至少在您开始更改时,尽可能多地保持旧的系统工作。一个典型的提交通常只包含数行代码。

发布!

所有修改尽可能发布到生产环境,即使修改的代码是最终用户不可见的,因为当你对系统了解不足时,只有生产环境才会告诉你新的修改哪里会有问题。如果这个问题只是在小的改变之后出现,你将获得几个优势:

很容易弄清楚出了什么问题

您将处于改善流程的良好状态

您应该立即更新文档,以记录获得的新见解

合理使用代理服务器

如果您正在重构一个 Web 系统,感谢上帝,你可以在最终用户和旧系统之间部署一个代理服务器。您可以精确控制每个 URL 哪些请求进入旧系统,哪些请求路由到新系统,从而可以更轻松,更精细地控制运行的内容。

如果您的代理足够强大,您甚至可以控制将某个 URL 一定百分比的流量发送到新系统,以便观察新系统的运行情况。如果您的集成测试也能够连接到这个代理那就更好了。

很有道理,但这一切需要太多的时间!

那么这取决于你如何看待它。如果按照这些步骤确实存在不少工作,但是它的确有效,而且这个过程的任何优化都让你进一步彻底了解整个系统。我个人在这方面也有一个很好的声誉,我真的不希望这样的工作中出现任何负面的问题。

有时候如果公司系统已经出现问题,而且可能会影响客户时,如果按照这个流程可能使事情好转,我宁愿完全控制和和使用这个过程,而不是为了表面的节省几天或几周的时间的方式。如果你更多地是牛仔的做事方式,你的老板也同意 —— 那么也许那是可以接受的高风险方式,但是大多数公司宁愿采取稍慢一点,更稳健的重构之路。

本文作者:佚名

来源:51CTO

时间: 2024-10-30 04:36:23

改进旧代码库的推荐路线:走向可扩展可维护系统的11条经验的相关文章

五款PHP代码重构工具推荐_php技巧

在软件工程学里,重构代码一词通常是指在不改变代码的外部行为情况下而修改源代码.软件重构需要借助工具完成,而重构工具能够修改代码同时修改所有引用该代码的地方.本文收集了五款出色的PHP代码重构工具,以帮助你完善更加优秀的项目. 1. Rephactor Rephactor是一款命令行重构工具,这是一款自动化工具,允许开发者以一种简洁的方式在不同的代码库中修改源码. 主要功能: 保证重构的可逆性-- 一旦发现问题,代码是可逆的,可以回溯到前一个版本. 查找替换功能-- 普通查找替换,方法重命名,类重

如何改进javascript代码的性能_javascript技巧

本来在那片编写可维护性代码文章后就要总结这篇代码性能文章的,耽搁了几天,本来也是决定每天都要更新一篇文章的,因为以前欠下太多东西没总结,学过的东西没去总结真的很快就忘记了,记录一下在你脑力留下更深的印象,特别是这些可维护性代码,性能什么的,当在你脑子里形成一种习惯了,那你就牛了!这里也要给初学者一个建议:多总结你学过的东西,因为这其实也是在学习新知识! 好,进入我们的主题:如何提高JS代码的性能. 1.优化DOM交互 DOM与我们的页面紧密相关,浏览器渲染页面也就是在渲染解析后的DOM元素,DO

15分钟学会使用Git和远程代码库

Git是个了不起但却复杂的源代码管理系统.它能支持复杂的任务,却因此经常被认为太过复杂而不适用于简单的日常工作.让我们诚实一记吧:Git是复杂的,我们不要装作它不是.但我仍然会试图教会你用(我的)基本的Git和远程代码库干活的工作步骤,在15分钟内. 工作步骤 我会展示以下的步骤,通常能帮我独自在一台或多台机器上做项目.   创建一个远程的空代码库(在BitBucket上) 在本地代码库添加一个项目 在分支上开发新功能 a) 保留新功能 或者 b) 丢弃它们 也许,回到某个早先的时间点 将本地代

微软一站式示例代码库

官方网站:http://1codechs.codeplex.com/ 这个下面有最受欢迎软件推荐下载和浏览示例代码KB以及C++, .NET 编码规范下载. 微软一站式示例代码库 中文官方博客 http://blog.csdn.net/mscodesample/article/details/7877255  

功能丰富的 Perl: Perl 和 Amazon 云,第 4 部分--深入探究完整 mod_perl 站点的代码库

这个共分 5 部分的系列文章向您介绍了如何使用 Perl 和 Apache 构建一个照片共享网站,从而访问 Amazon 的 Simple Storage Service (S3) 和 SimpleDB.在本期文章中,研究完整 mod_perl 站点的代码库,包括如何设置顶级配置.如何使用处理程序,以及如何设置外部依赖关系. 在本期文章中,我们将研究完整的 mod_perl 站点(只讨论代码:模板在下期文章讨论).前几期文章中,我们的节奏有些缓慢,现在,通过研究 mod_perl,我们将加快步伐

从单个代码库和多个数据库创建多个Drupal站点

系统管理员或开发人员有许多理由选择采用一种多站点配置在同一个服务器上托管多个站点.例如以下这 种配置: 使您能够构建一个高效的开发环境 允许您在公开站点之前暂存并测试它 允许在同一个站点上运行不同软件 支持跨多个站点共享单个代码库 利用共享的托管主机 允许在同一个服务器上运行类似的安全(基于安全套接字层的 HTTP [HTTPS])和标准 (HTTP) 站点 简化服务器管理 但是,不是所有这些理由都可以通过 Drupal 的多站点特性得到最好的处理.本文将重点介绍一种战略: 如何使 Drupal

Android开发神器(里面有各种UI特效和android代码库实例)

http://www.23code.com/tui-jian-an-zhuo-kai-fa-shen-qi-li-mian-you-ge-zhong-ui-te-xiao-he-shi-li/ 网上有很多开源的安卓代码库很好用,对于刚学习安卓的童鞋亦或者老鸟都是很好的学习对象. 我平时有关注开源代码的习惯,这么多年也搜集了不少精彩的源码. 到后来发现自己手机里装的都是几百个demo app,删又不舍得删,不删又占资源, 于是就准备搞了个23code应用,里面汇集了我精心整理的应用,此后每周应该都

面对糟糕的旧代码 千万不要重写

程序员都有一颗工程师的心,所以当他们到一片新的场地想做的第一件事就是,将旧的一切推倒重来.是的,他们决不会满足于简单的增量劳动. 或许这种微妙的心理定位可以解释:为什么程序员进入新项目组后宁愿丢掉旧代码重新写,也不愿意修修补补.他们认为旧代码简直一团糟. 但是,事实上真是这样吗?你之所以认为旧代码一团糟,其实是由编程的一个基本定律决定的,那就是:写代码容易,读代码难. 为什么你觉得旧代码异常混乱?因为读代码更难. 这大概就是代码Reuse难以实现的原因. 这就是你组里的每个人都喜欢用不同的功能将

android git repo-repo 与 git的基本操作以及建立代码库

问题描述 repo 与 git的基本操作以及建立代码库 我从供应商那里拿到了一套repo的代码库,现在要把它放到自己的服务器上,让其他人可以进行开发,现在的问题是不知道怎样在服务器上建立这个库?怎么更改url?希望能提供一些思路或者资料,谢谢!