重构项目,你真的准备好了吗?

更新日期: 2019-07-02阅读: 2.1k标签: 项目

我相信每个接受过老项目的程序员可能都吐槽过“前人的代码都是屎”。一个已经有些年头的项目,几乎肯定可以看到——到处拷贝来拷贝去的代码,随处可见的拼写错误,头重脚轻的函数……再看一看当年的提交者,可能是公司里的元老,甚至是大boss,不禁心里暗暗的鄙视,怀疑是否自己进错了公司。

而你被分配到接管这坨“屎”一般的代码,并且要在上面添加更多的功能,每次的增删代码都让你如履薄冰,每次遇到原来代码里的bug都让你的发际线再次上扬。

终于有一天,你忍不住了,脑子里面满满都是一个念头——我要重写这个代码。然后你真的这么做了,花了整整一个晚上/天/星期的时间,把代码改成了你心中满意的模样。然后代码上线了:

Happy Ending:重构的代码获得了同事的交口称赞,大家纷纷夸你代码比以前好写多了。

Normal Ending:过了几个月,你发现重构的代码又不行了,加一个新功能费死劲了,于是你又在筹划下一次重构。

Bad Ending:重构的代码上线后,bug不断,老板夺命连环call让你连夜修补,你发现老代码这么写不是没有道理的。

这样的故事每个经手过老项目的程序员可能都多少有类似的体会,在我的职业生涯中也经历了屈指可数的几次重构,然而每一次的重构经历几乎都踩到了各种各样的坑。


你真的需要重构吗

在重构项目之前,一定要再三的问自己(和自己的组员)这个问题:我们真的需要重构吗?

重构项目,在只是重构的前提下,对于公司的收益来说是——0,因为你的产品的用户,他们并不会为你的重构行为来买账,对于他们来说,你的源代码写的好看与否根本无所谓,对他们重要的是产品本身有没有改进。对于公司来说,重构行为不但没有带来任何利益,反而消耗了程序员资源,对于公司来说是损失。

一个互联网产品的生命周期可能就只有短短的几年,放长一点看,现在写的代码可能过几年就会毫无用处,在这样的前提下,现有项目的重构,一定是建立在项目本身还十分有前景的基础上,这个项目将来还有多少潜力,值不值得去重构?如果这个产品本身并没有什么可做的了,那么是否还值得花时间去重构它?


为什么需要进行项目重构

每个项目重构的理由各不相同,但个人总结来主要是以下两点

  1. 原来的项目漏洞太多,或者稳定性太差,当前的框架很难彻底根治。

  2. 新的项目需求,原有的程序框架已经无法满足。

假设你的项目没有很多bug,稳定性也很好,或者暂时没有在现有框架下很难实现的新的需求,那么不建议进行项目重构。

我在上一家公司的SEM组工作时,经历的第一次重构,是将后台的竞价计算出的竞价的结果,由数据库的表(Table)存储改成了推送到队列系统(RabbitMQ)。后台竞价程序算出的竞价结果需要由另一个上传程序上传到Adwords等竞价平台,我们在过去的做法是在数据库建立了一张表,竞价程序将算出的新竞价存储在其中,上传程序则定期的去查询表中的新加入的记录,将其成批上传,并在上传后删除。那么为何要进行这次重构?

  1. 随着公司的投放的广告词增加,单一上传程序实例很难在短时间内上传所有的竞价,但是如果运行多个上传程序的实例,则会出现多个示例同时查询新加入竞价并上传,删除同一记录造成数据库死锁。(1. 原来的项目漏洞太多,或者稳定性太差,当前的框架很难彻底根治。

  2. 新业务需求需要计算另一种格式的竞价,如果继续使用数据库表来存储,则要么需要对已有的表进行字段扩容/修改,要么建立新的表单。但是当时已经预见将来可能会支持更多格式的竞价,于是数据库表的存储方式将不再灵活。(2. 新的项目需求,原有的程序框架已经无法满足。


重构项目

经过再三衡量,我们终于还是决定重构项目,恭喜你,你将有一段踩坑之旅。


重构项目之前

重构项目的第一步是要了解项目。

重构时最容易发生的一类错误是没有能够完全的将原来的功能忠实的重现出来。很多开发者并不是手头的项目的原作者,并且项目也经过了很长时间的迭代,当代码越滚越大的时候,几乎没有人(包括原作者和产品经理)能够完全了解项目到底包含了哪些内容。当你看到重构后的功能和原来一模一样,并且测试人员也没有测出问题的时候,说不定哪个猴年马月添加进来的特殊功能,悄悄的被你干掉了。等到上线后,这个特殊功能的用户突然发现功能没了,于是过来投诉。


重构ING —— 测试

如果说什么是重构中最重要的第一步, 我认为是测试。

如果原来的代码没有单元测试、集成测试,有条件的话一定要补充上。为什么测试如此重要?打一个比好,重构就好像对着一把老钥匙来配新钥匙,而测试代码则是老钥匙的模子,我们做出来的新钥匙要能够和这个模子全对上。这个模子越详细,则新钥匙可以正常开锁的概率越大。

回想我在过去的重构中出现的一次重大失误,便是在重构过程中,有一个原来的单元测试出现了错误,原本的断言是结果为NULL,但是我的结果是0,当时觉得可能两种结果都可以,于是错误的选择了将单元测试的结果“改正”,结果在代码上线后,0的结果造成了程序输出和之前相比大不相同。总结一下:

1. 如果有集成测试,则这样的错误可以在上线之前发现。
2. 应该相信原来的单元测试集,而不应该“想当然”的去认为自己重构的逻辑正确。


重构ING —— 分支

代码重构的过程中,一定不建议先删除代码全部重写。比较推荐的是先拷贝出一个新的函数/文件/文件夹,然后写全新的代码。为什么要这么做?

  1. 在写新代码的时候可以一边写一边参照原来的代码。

  2. 新代码的代码审查(Code Review)会比较干净。

  3. 项目管理工具(Git,SVN)的历史比较干净。

回到我上面说的由数据库的表(Table)存储改成了推送到队列系统(RabbitMQ)的重构,当时我的做法是,在竞价程序端,重新实现了输出的函数,使得竞价结果可以改为推送到队列系统。而在上传程序端,则重新实现了一个新的程序,只从消息队列中消费推送的消息,然后上传到Adwords等广告平台。原有的旧上传程序则没有改动丝毫。


重构项目的上线 —— 开关

稍微大一些的重构,我会比较推荐使用程序开关,使用一些控制参数来控制逻辑入口是用老代码还是新代码,这样在线上出现了问题,可以及时的调整控制参数,迅速的回滚到老的逻辑。

如果程序运行的结果本身就是不确定的,不容易看出重构的错误,甚至推荐在重构的入口处设置A/B测试,这样在线上让一部分流量先走重构后的逻辑,同时将新/老逻辑的流量标记成不同的测试bucket,可以在数据测量平台上看到新老代码的表现如何。如果新代码的表现合理,则可以不断加大新代码的流量覆盖,直到100%。

在我上面提到的重构中,我选择在竞价程序计算段创建了一个新的A/B测试,对照组采用将竞价结果写到数据库的方法,实验组则将竞价结果发送到消息队列。同时在生产环境中,旧的和新的上传程序都在同时运行。在刚上线的时候,我选择将1%的竞价结果推送到消息队列中,然后观察新的上传程序能否将消息队列中的消息消耗掉。同时,在产品的监视页面,对对照组和实验组的竞价结果进行分析,确认两个组的竞价结果并没有明显的差别。


总结

总结一下个人的重构心得,重构前是否必要,重构中做好测试、分支、开关。


来自:ChaosYang1987  


链接: https://www.fly63.com/article/detial/4004

程序员最喜欢什么样的项目经理?

在当今的专业环境中,项目经理需要戴上各种帽子,在管理团队的日常功能和理解大局策略之间切换。正因为如此,项目经理对组织变得更有价值,并且他们对技能和战略角色的需求在全球范围内不断增长。但这也提出了一个问题:如何在如此高压的环境中成为更好的项目经理?

原生JS实现随机点名项目

随机产生规定范围内的整数,然后再产生相同范围内的整数,两者相同时,则暂停。所用知识:Math.random() * num: 产生从0到num的随机数,Math.floor(): 向下取整,简单的DOM操作等

没有项目经验找工作处处碰壁怎么办?

我马上就要毕业了没有开发经验怎么办?我投递了 N 多公司全部没有给工作机会,有的给了面试机会也是没有下文了怎么办?我简历上什么东西都没有,要不要伪造一个工作经历呢?

当了项目经理才明白的10件事!

项目经理这个神奇的职位,改变了我很多工作处事的方式,从前性情纯真的耿直boy,现在变成了人鬼皆爱的老油条, 以下是我当了项目经理之后明白的10件事, 如有雷同,真是太巧。

pm2 快速部署前端项目

pm2 大家应该都知道,主要是用来管理 node 进程,但是同样可以用来部署前端代码。也可以手动添加 public key 到服务器上的 ~/.ssh/authorized_keys,

关于小型长周期项目的一些建议

我不是专业的项目经理,这里不讨论大型项目管理的事情。我们比较常遇到的可能是小型的长周期项目,比如2-4个人,做半年甚至一年的项目。这种项目通常不会有专职的项目经理

水印项目的实现以及两种实现方案的选优

通过 attachShadow 这个方法生成一个shadow root 即shadow的根节点,然后在这个根节点下面通过循环语句添加水印,利用position为absolute进行排版,使其铺满容器

浅谈RPC

近几年随着微服务化项目的崛起,逐渐成为许多公司中大型分布式系统架构的主流方式,而今天所说的 RPC 在这其中扮演着至关重要的角色。随着这段日子公司项目微服务化的演进,发现在日常开发中都在隐式或显式的使用 RPC

在Vue项目中使用Eslint+Prettier+Stylelint

首先搭建vue项目,lint选择ESLint + Prettier,配置方式选择In dedicated config files。具体搭建过程这里就不赘述了,如果不熟悉的同学可以点击这里。配置 Stylelint,目前还没有stylelint选项,需要我们自己安装相关的 npm 包

vue项目better-scroll使用注意点

created : 中请求数据,ajax是异步的,这个时候可能mounted已经执行完了,也就是dom挂载完了,但数据还没请求回来,无法获取到内部元素(数据渲染出来的dom)高度. 无法渲染内部元素,无法滚动

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!