如何有效地重构遗留代码?

时间:2010-09-09 22:25:18

标签: java refactoring

  

可能重复:
  What should I keep in mind in order to refactor huge code base?
  When is it good (if ever) to scrap production code and start over?

我目前正在处理一些遗留的源代码文件。它们有很多问题,因为它们是由一位对Java知之甚少的数据库专家编写的。例如,

  1. 班级中的字段是公开的。没有吸气剂和制定者。
  2. 使用原始类型,而不是参数化类型。
  3. 不必要地使用static
  4. 超长方法名称。
  5. 方法需要太多参数。
  6. 经常重复自己。
  7. 我想修改它们,使它们更加面向对象。什么是最佳实践和有效/高效的方法?

8 个答案:

答案 0 :(得分:8)

阅读Michael Feathers的“Working Effectively with Legacy Code”。伟大的书 - 显然它将比这里的答案更详细。它有很多处理事情的技巧。

看起来您已经发现了许多问题,这是问题的很大一部分。其中许多听起来像是可以相对容易地修复 - 当然,它的整体设计和架构更难做到。

是否已经进行了单元测试,或者您是否也会添加它们?

答案 1 :(得分:5)

开始之前,为应用程序创建系统级回归测试套件。您需要这样做,以便您可以验证您的更改不会破坏。

要进行重构,您需要使用良好的IDE和文本搜索工具(例如grep)的组合。使用文本搜索工具查找要修复的“综合症”的出现,然后使用IDE(及其内置重构功能)来修复实例...一次一个。

例如,Eclipse允许您重命名方法或类,或生成getter和setter。因此,您可以通过以下方式治愈“公共”属性:

  1. 将属性更改为私有。
  2. 生成getter和setter方法。
  3. 保存文件。
  4. 完成属性现在为私有的所有Java编译错误,并根据需要更改为使用getter或setter。
  5. 这种方法会给你带来低调的成果。更基本的设计问题更加困难,如果没有对应用程序进行根本重组,可能无法修复。重构功能将帮助您执行此类更改,但决定做什么最终取决于您。

    最后,我的建议是不要太野心勃勃。进行渐进式改进,并准备在代码“足够好”时绘制线条。你不会达到完美......即使你从干净的石板开始也不会......所以不要把你的期望设定得很高。

答案 2 :(得分:3)

只是代码不好,还是会损害用户体验?持续重构是一个好主意,但它不应该成为一个目标。它应该在用户交互,可维护性,稳定性,性能等方面改进应用程序。

这就是为什么我不是非常喜欢巨大的重构只是为了提高代码质量。相反,重构您使用的代码。

在使用遗留系统数年之后,我个人发现:

  1. 为您自己创建一个愿景,了解您在完成代码后的代码。它应该是可以实现的,包含技术变更列表,一般架构变化。对于哪些类最关键的改变,粗略优先考虑也是一个好主意。几年前我们缺乏这样的愿景,虽然我们进行了很多重构,但代码质量几乎没有提高。
  2. 现在,您应该限制您的重构,以达到您的愿景。不要陷入做目前表现良好的陷阱。
  3. 专注于特定组件,并使其更好。然后继续下一个。很有可能做出影响整个系统的巨大变化,但实际上你会引入比你解决的更多问题。
  4. 编写集成回归测试。即,一些测试很多功能的大型测试。它不是最佳的,但它是你能做的最好的。为旧系统中的每个类编写单元测试可能会浪费时间,因为它不是为了进行测试而设计的,而是想重新设计一半的类。
  5. 接受需要时间

答案 3 :(得分:1)

Eclipse应该能够处理#1并帮助您通过其他许多方式。

至于将差的OO代码转换为优秀的OO代码,非常困难。通常,从头开始重写它似乎更容易。

我倾向于自下而上。当我正在处理一些小部分时,我会认识到一堆数据作为一个组合在一起,我会做一个好的对象来替换那些代码而不改变其他任何东西 - 非常小的变化,每次变化之间都有不断的测试

这最好是一个平庸的设计,但老实说我不知道​​你是否可以在大型项目上从非OO转到优秀的OO而不解剖原始程序,理解它并将其用作重写的模板很少有项目允许这样做(即使它可能更快,你很少能够说服管理层这个事实)

答案 4 :(得分:1)

我认为重点是风险

丑陋的代码只是丑陋,但它可以工作,它已经过测试和修复。如果更改了可运行代码,则会出现风险。所以测试至关重要。

  • 你可以在重构时重构相关代码 你必须将bug修改为保守主义解决方案。

也许第一个挑战是说服你的经理:)

答案 5 :(得分:0)

没有吸气剂和二传手的问题是什么?我建议只有当你需要添加非平凡的getter或setter时才重构那些(例如,通过验证)。

其余听起来像你需要识别值组并创建包含它们的新类型,所以不是传递String名称,字符串地址,int yearOfBirth,String [] accountNames,int []余额,而不是传递客户,反过来会有一个帐户[]。

IDEA Ultimate Edition有一个非常好的代码重复检测器(它只缺少'建议的解决方案'按钮!),还有CPD等。

我建议在大型遗留代码库中,您可能会浪费时间重构代码,但却发现它还没有被使用过。我概述了删除未使用代码的一些步骤:http://rickyclarkson.blogspot.com/2009/12/deleting-code-what-first.html

答案 6 :(得分:0)

这些“问题”中有多少是真正的问题,而不仅仅是风格问题?在这个列表中,我能看到的唯一“真实”问题是“经常重复自己”,这更像是一个持续的维护问题,应该在正常的代码维护期间解决,无论如何有人要更改代码。

答案 7 :(得分:0)

我想修改它们,使它们更加面向对象。

面向对象不应该是重构时的唯一目标。您应该问自己的问题是什么是预期的投资回报率(更好的质量?更容易的增强?更好地在整个团队中共享此代码?)投资回报率不仅仅是文字,您应该准备用数字衡量投资回报率(甚至例如质量改进)。您应该在估算投资回报率时考虑产品的使用寿命。

您还应该问自己,代码的大小取决于您要重构的代码。重构库可能很容易,但可能会导致依赖于此库的源代码中的大量更改,这项工作远远大于重构库。

在接触任何代码之前,您应该估计完成重构代码和相关代码所需的总工作量。您应该估计代码的完全重写,部分重写,或者只是在不触及API的情况下进行内部重写。

通过成本和回报,您可以决定重构代码是否值得。