七的博客

重构项目随笔

开发经验

1. 重构起源

因公司项目业务的需求,需要对项目进行重构。项目需要从 V1.0 版本过度到 V2.0 版本,重构的过程自然是比较艰辛的。简单地说是个电力采集系统,1.0 版本从 20153 月份开始开发。版本迭代已经很多次了,目标客户也是针对海外客户,例如伊朗等一些中东国家。对于这样的一个外包项目,对于我们团队来说,我们需要从头开始梳理项目业务,毕竟我们之前并不是做这块的。

当一个项目维护出现比较大的困难时,管理层就会开始想怎么解决这个问题。对于软件工程这种问题,最好的办法就是重构,在保持原有功能的基础上,对原先的代码进行重构处理,让代码变的可维护、可扩展。

2. 为什么要重构

重构最主要的原因应该有以下几点:

  1. 项目代码已经不可维护,客户有新需求就只能不停地加 if else ,甚至有时候 if else 都不知道往哪里加。原项目成员不断地离职,导致熟悉业务逻辑的开发人员越来越少,每次加新功能都担心会不会影响原有的功能。
  2. 整体项目质量较低、可维护性差、可扩展能力不强。由于历史原因以及缺乏较高水平的技术 Leader ,项目从一开始构架就设计的不是很合适。团队间没有统一的编码规范,引发的问题就是开发写代码不严谨,想到什么写什么。最典型的一个就是 JSON 的序列化以及反序列化了,一个项目中出现了 GSONFastJsonJackson 三种类库。对于一个单模块的项目来说,所有的依赖都在一个 POM 文件中,出现多个相同作用的类库相对来讲是比较不应该的。类似的技术方面问题还有很多,这里就没法一一列举。
  3. 1.0 版本在迭代的时候,并没有考虑到未来的用户量。导致线上项目在运行过程中,发生了许多问题。最典型的问题就是在用户访问量高的时候,系统出现很卡的情况。这对于用户的体验性来说,是一件非常不友好的事情。

3. 重构可能面临的问题

重构也不是说重构就可以重构的事情,很多时候重构可能就是领导层一拍板的事情。重构可能会碰到的问题比较多,这个时候需要全面考虑。

  1. 从公司层面来说:
  • 重构需要花费较多的人力以及资源,如果项目非常的大的话,可能重构的时间会高达一年,这对于公司来说是种比较大的消耗。在重构的这段时间里面,不能给公司产生任何经济效益。重构的受益者基本就是程序员自己了,而且很多情况下也是唯一的受益者。

  • 最终的重构结果可能并不会跟想象中的那么好。也许一个项目在线上已经运行了很久,而且还是比较稳定的阶段。

  1. 从开发的层面来说:
  • 重构一个系统,需要对该系统整体的业务以及逻辑需要比较清楚,如果不清楚项目的业务逻辑的话,重构是非常难进行的下去的。
  • 重构是为了解决项目中所碰到的实实在在的问题,不能因为有代码洁癖就盲目对代码进行重构

4. 如何开始重构

重构应至少有以下几点通用的步骤:

  1. 熟悉项目原有架构,对整体技术选型做个了解,重点分析业务流程,免得开始重构的时候手忙脚乱。
  2. 对数据库模型进行调整,对之前设计的不合理的地方进行逐步修改,切记不可跨度太大,否则就相当于重写而不是重构了。
  3. 测试用例,对某个模块重构完成以后,需要测试重构后的结果是否达到了预期效果。
  4. 评估重构所花费的时间。在合理的时间范围内,并且团队有足够精力跟时间去重构。

5. 重构碰到的一些问题

我们在重构的过程中,也是碰到了导致项目重构的一些共性问题。比较突出的问题主要有以下几种:

  • 重复代码过多,到处都是粘贴复制的代码块。一些公用的业务逻辑代码或者是工具类函数没有抽取出来公用,没有复用的意识。或者是 A 封装了一个类库或者工具类函数后, B 写代码的时候优先找一个已经可以直接拿来用的,但是没有找到或者是不会使用,导致 B 自己又写了一个。这样就是一种恶性循环,导致重复的代码越来越多。

  • 单个函数过长,或者类文件过大,导致代码阅读起来非常的困难。单个 Java 文件,见过最长的代码是高达 1W 多行,注释占的比例基本就是微乎其微。这样的代码已经不知道过了多少个人的手,后面接手的人想修改,但是奈何有心无力。这样的代码根本是非常难阅读以及修改的。最致命的是有时候一个函数能高达几千行,这样阅读是需要一直点翻页的,按照人大脑的记忆力,超过一个屏幕以后的内容很有可能就已经开始忘记了。

  • 函数、变量等命名过于随意,想到什么就命名什么。各种组合的命名,例如中文跟英文结合的命名,最后我们能看到的变量名很难知道到底是什么意思。有些项目例如像国企或者政府机关的项目,确实有一些项目是使用中文命名的,这个是没办法改变的事情。但是对于正常的项目来说,我们应该是可以做到使用英文来进行命名的。现在互联网这么发达,翻译软件翻译能力也比较强大,翻译个单词应该是比较容易的一件事情。

  • 注释问题。在一些比较复杂的业务流程中,没有稍微加点注释。在无关紧要的地方,却存在大量的注释。一段好的代码有时候是不需要很多注释的,读起来就像是阅读一首诗一样,非常的优雅,非常的优美,而不是像裹脚布一样又臭又长。在确实需要注释的地方,加上一些必要的注释,让代码看起来更加的完善。注释在程序编译完以后都就被擦除掉,对程序的性能并不会造成影响。但是对后面接手你工作的那个人,也许是一种很好的指引。

  • 判断分支过长。见过最长的 if else 嵌套高达16层,而且是在单个函数中。一个函数最长的时候有见过 1500 行,这样的函数很难进行重构,并且对阅读代码非常的不友好。每次有bug 的时候,在这个函数里面改代码都是有种心惊胆战的感觉,生怕自己修改的代码会引发一连串的问题。

6. 总结

  • 重构前负责人需对项目重构做出周全的重构计划,按照计划小步重构,大步迈进。
  • 需求实实在在的变动的,所以项目框架很难长久,重构可以适当地延续生命。
  • 重构项目不可脱离实际业务场景,不能盲目重构项目。
  • 重构前确保对业务梳理清楚,不清楚前切记不重构。
  • 重构完成之后,一定要对重构后的代码进行单元测试跟集成测试,否则很难发现问题。

7. 题外话

很多时候的项目重构都是跟项目开发进度息息相关的,往往项目开发进度越快,后期重构的时间花费越多,所花费的人力以及物力是非常巨大的。但是这本身就是一个相斥的问题,项目初期往往都是要求快速迭代,然后能快速开发出新功能,后台再慢慢迭代。

经常就碰到下面的一个场景:

产品经理: 这个功能需要多久才能完成?

开发: 至少需要 3 天吧,这个功能还挺麻烦的。

产品经理: 我觉得这功能很容易做的,先快速跑起来再说。

开发: 。。。。

然后开发就开始一顿操作猛如虎,先把代码给拼出来,功能可以用起来。每次都是说,代码以后可以改,不好的地方以后可以优化。代码中的问题就越来越多,积累的时间如果很久的话,bug越来越多。各种不规范导致的问题就开始暴露出来。最后的结果导致就是项目的重构。