大规模重构的策略

23

我目前正在处理的代码中,逻辑和数据访问都出现在GUI类中。显然,我想改善这种情况。

当前的结构基本上是:

  • 庞大的代码堆积

最终目标是实现像DDD一样的结构:

  • DAL
  • 领域模型
  • 服务层
  • 展示模型
  • GUI

那么,你会如何解决这个问题呢?

9个回答

17

永远不要尝试“大爆炸”。它几乎总是会让你吃亏,因为当其他所有方法都失败时,这是一种高风险、绝望的措施。

分而治之:如果你的世界只有两面,那么这个方法很有效。但在真正的软件中,你必须同时征服很多方面,所以你很少有机会生活在一个非黑即白的幻想中。

我想我在我的职业生涯中一直在使用类似“扼杀”的东西:逐渐将糟糕的旧代码转变为闪亮的新代码。以下是我的步骤:

从某个地方开始,不管它是哪里。编写一些单元测试来了解代码的实际行为。弄清楚它做你认为它要做的事情的频率和它不做的频率。使用你的IDE重构代码,以便可以测试它。

第一天后,猜测你是否已经开始了正确的地方来拆散这个怪物。如果是,继续。如果不是,找一个新的地方重新开始。

这种策略的优点:它采取小步骤,因此风险可以控制,如果出现问题,它必须是在你上周正在工作的代码中。

缺点:需要很多时间,而且你会感到沮丧,因为经常会觉得进展缓慢,直到“结”的部分突然解决,一切都像魔术般自然地落入了位。


6
我从未听说过“Strangler应用程序”的术语 - 我很喜欢它。在可能的情况下,这总是一个好方法,它确实最小化了风险并且非常务实,逐个击破大型建筑物。
但根据我的经验,在需要立即进行相当重要的更改 - 需要一些重构(或大量的黑客攻击)的情况下,这种方法不起作用。在那种情况下,我经常发现我需要做的更改正好在大球泥的核心位置,除了弄脏手之外别无选择 - 即使应该是标准维护或小增强更改也会变得可怕,而主要的重构是最好的选择。
对于这些情况,我会采用分而治之的方法 - 我始终瞄准的第一个目标是可测试性,一旦你拥有了它,其他所有事情都变得容易得多。事实上,这通常是我从大球泥中重构的主要驱动因素之一 - 那种代码通常非常难以测试,希望有示例UI输入和输出,但有时甚至缺少这些。
因此,当面对将所有内容都放入UI中的代码时,我通常会开始将离散功能单元分解为类和方法,然后将这些代码部分推入域或服务层。逐步进行可以大大降低出错的可能性,并使定位错误代码变得更加容易。
在每次更改结束时运行您可用的任何测试用例,并确保仍然满足某种基线。
如果您一边编写良好的单元测试,一边减少问题的规模,我发现很快就可以采用Strangler方法 - 有了良好的单元测试或至少允许编写良好的单元测试的正确框架,逐渐替换功能部分变得更加实用。

4

1

取决于你是否需要始终保持工作状态,以便在必要时进行错误修复和部署,那么分而治之将是一个不错的解决方案。如果你可以在编写新代码的同时维护旧代码(并有纪律性地将错误修复应用于两个代码库),那么重写可能是更好的解决方案。


1
如果你所说的重构是指在不修改功能的情况下改进代码,我会首先创建一个自动化回归测试基线。有很多工具可以帮助完成这个任务。我使用TestComplete,但也有一些好的廉价替代品。
建立了回归测试基线之后,我个人会采用分而治之的方法,因为在我的经验中,这种方法最有可能成功。一旦你有了测试基线,选择哪种方法就不那么重要了。

1

对我来说,这取决于情况。

如果是一个非常小的项目,我会考虑从头开始重写它...然而你很少有这种奢侈。

如果不行,我会逐步地分解它。我会编写单元测试来验证现有功能,并慢慢使用TDD将代码转换为优雅和良好设计的系统。根据这个过程需要多长时间,它可能会开始看起来像你上面提到的StranglerApplication。

BigBang非常危险,因为你没有简单的方法来验证更新后的系统是否与旧系统执行相同的操作。

分而治之比BigBang风险小...但如果它是一个足够大的系统,它可能会变得像BigBang一样棘手。


1

大爆炸/大重构/重写软件等其他名称都不能为现有软件提供支持。

原因如下:
  • 您仍然需要使用(可能是)相同的资源来支持现有软件。

  • 您可能没有重写的要求。您的旧代码已经嵌入了所有要求。您的工程师不知道所有的软件领域和所有的要求。

  • 重写需要时间。在此期间,您将发现现有软件已经改变以支持这段时间内所需的东西。 您的新软件实际上是从原始软件中分离出来的,需要合并(这也需要时间)。


0

是否考虑全面重写?根据我的经验,从头开始重写通常比试图清理现有混乱的代码更有效率。您仍然可以保留现有代码的部分内容,但在新的上下文中使用。如果您有GUI和数据库,也同样适用。从头开始重写,并带上您可以使用的内容。


-1
从一个干净的全新架构开始,逐个将旧代码移到这个新架构中,并对其进行重构以适应新的架构,这是一个不错的选择。我认为在移动函数时采用自下而上的方法会更好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接