为了重构庞大的代码库,我应该记住什么?

时间:2009-05-15 23:15:21

标签: java architecture refactoring layer

我将在庞大的代码库(18000+ Java类)中重构某些部分。目标是能够将较低层提取为独立库,以便在当前使用此代码库副本的其他项目中重用。特别是将一部分重构为独立于业务逻辑的框架。最终,我希望代码具有干净的架构层次。

我用一个名为Structure 101 for java的工具查看了代码,发现很多(!)的架构分层问题,其中较低层引用了上层。

我不想简单地开始搞乱代码,而是试图找出一个合理的策略来解决这个问题。我应该记住什么?

我正在考虑至少采取一些小步骤。我也在考虑进行单元测试,但这需要创建它们,因为没有。

对此有何想法?

9 个答案:

答案 0 :(得分:7)

您还应该看看Michael Feathers使用遗留代码:

http://www.amazon.com/Working-Effectively-Legacy-Robert-Martin/dp/0131177052/ref=sr_1_1?ie=UTF8&s=books&qid=1242430219&sr=8-1

我认为您可以采取的最重要的一项措施是确保在重构​​/拉出到单独的模块后一切仍然有效。通过引入一个持续集成系统来增加这一点,该系统在您检查某些内容时运行测试。

答案 1 :(得分:5)

18,000个班级正朝着“巨大”的目标前进。这将给你带来明显的问题,包括构建/编译时间,以及当你启动ide时烟雾从计算机中冒出来。

我的第一个假设是,有很多类,有很多重复的常见功能和可能未使用的类甚至可能是子系统。我期待这一点,因为当某些东西变得那么大时,开发人员越来越不可能知道整个系统,或者不知道这些Util函数在哪里,并且发现编写新函数更容易。寻找要删除的冗余将有助于简化。

另一种可能的冗余来源是无用的深层次层次结构,或成堆的无意义接口(例如 - 我在那里工作的目录大约有50个左右的类,大多数> 1000行(不是我的,不是我的!)。它们中的每一个都实现了一个接口,它只不过是它自己的方法框架。这些接口没有其他实现。所有50个都可以删除而没有问题)。还有那些刚刚发现OO并且非常热衷于它的开发人员 - 你知道那些,扩展了5个抽象类和3个接口链的单个具体实现。

除此之外,我会尝试使用代码的一小部分(最绝对的几百个类)并将它们移动到子项目中,然后我将其作为jar链接到main。然后你可以在一点平静的情况下处理这个问题,并有一个合理的希望,能够理解整个事情 - 这也有一个心理方面 - 如果你觉得你在工作,那么做一些好工作的动力就会减少对于一个巨大的,难以理解的混乱的东西,比你正在完全理解你自己的清洁子项目。

答案 2 :(得分:4)

第一件事:祝你好运,你需要它。这可能是你遇到的巨大工作。这对我来说听起来很熟悉;我过去曾做过类似的事情。

要考虑的一件事;在你开始重构之前,我真的强烈考虑建立一个广泛的测试框架。原因是:通过良好的单元测试和回归测试,您可以开始进行更改,而无需担心破坏现有功能。 (也就是说,总是有一个问题,但是......)

那说:我会考虑切掉不同的“垂直”功能片,看看你是否可以为它们编写不同的单元和集成测试;一旦完成,我就会跳进并开始研究重构器。虽然最初它可能非常小,但只需隔离垂直功能片然后为其编写集成和单元测试代码的过程将为您提供现有代码库的大量经验。如果你最初设法让那个好一点,那么你就会领先一步。

完成后,开始查看可能更大的功能块进行重构。如果不可能获得重构的干净功能块,我会开始看小块;如果你能找到一小块(有时非常小)代码然后提取,单元测试和重构,你就会向前发展。这似乎是非常非常缓慢的进展,如果你有一个非常大的项目,它会,但你会有所作为。

但总的来说,考虑首先进行测试以确认预期的功能。一旦这些测试到位,你就可以自信地重构(不是完美的信心,但总比没有好),你不会破坏事物。从小处着手,并以现有代码库中显示出来的技术为基础。这是一个漫长的过程,但你最终会到达那里,代码库会更好。

答案 3 :(得分:3)

最重要的是:

  • 识别功能域,这将有助于在庞大的代码库中定义应用程序。
  • 反过来,识别这些应用程序之间的依赖关系:底层的那些(所有其他应用程序使用的)通常是技术框架或库。

  • 创建scenario testing(而不是单元测试,在此阶段过多“本地化”)以识别重要的运行时进程及其输出。场景测试更关注集成,也可用于非回归测试。

  • 准备当前的生产环境并限定当前的错误,因为当您开始重构时需要并行运行(以确保您仍然保持相同的功能),并且您不希望并行运行到100%兼容(因为这意味着你已成功复制了错误!)

  • 确保创建适当的merge workflow来管理代表不同(并且可能是并行)重构工作的不同分支。

答案 4 :(得分:1)

如果您要提取课程组并将其转换为独立的图书馆,请确定一个小组的成员并开始将他们变成一个有凝聚力的整体,限制他们与外界的互动。尽可能减少依赖关系。完成后,取出该组,将其转换为库,重新插入库,然后启动新组。你清理的垃圾越多,就越容易理解剩下的东西。

答案 5 :(得分:1)

尽量使您的依赖树尽可能平坦。

执行此操作的一种好方法是使用反向依赖项,其他代码可能依赖于接口/服务,但不依赖于该服务的提供程序。这对我们帮助很大。

答案 6 :(得分:0)

只是一些想法:

  • 寻找常见的设计模式 - 尝试查看哪些类用于核心工作,哪些是工厂,哪些是外墙或适配器。
  • 将代码拆分为依赖于或共享应用程序状态的类组。
  • 确定哪些类具有持久对象,以及在数据库中进行序列化的类(应该是最容易隔离的,提供最干净的事务接口,然后在项目之间移植)

答案 7 :(得分:0)

我的想法是,在设置测试基础架构之后,如果可以使用测试代码的常见功能进行抽象,则可以编写用于测试用例的代码生成工具,除了可视化之外,静态代码分析工具可能是附加组件工具。对不起,这是个主意。我甚至无法命名这些工具。

答案 8 :(得分:0)

我与我正在处理的代码库处于类似的位置。 swing UI和业务逻辑之间的紧密集成。重构是一个微妙而耗时的项目。

我强烈推荐Martin Fowler的Refactoring。这是我发现的最重要的工具,它帮助我改进了处理糟糕代码库的方法。他概述了重构任何代码的逻辑和直接过程。它有助于从已多次完成此操作的人那里阅读。