代码之家  ›  专栏  ›  技术社区  ›  Andreas

大规模重构策略

  •  22
  • Andreas  · 技术社区  · 16 年前

    我目前正在一段代码中工作,其中逻辑和数据访问都存在于GUI类中。显然,我想在这种情况下有所改进。

    目前的结构基本上是:

    • 大泥球

    最终目标是实现类似DDD的结构:

    • 达尔
    • 领域模型
    • 服务层
    • 演示模型
    • GUI

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

    9 回复  |  直到 7 年前
        1
  •  15
  •   Aaron Digulla    16 年前

    不要尝试“大爆炸”。它几乎总是打在你脸上,因为它是一个高风险,绝望的措施,当一切都失败了。

    分而治之:这很有效…如果你的世界只有两面。在真正的软件中,你必须同时征服这么多的前沿领域,你很少能生活在黑白幻想中。

    我想我职业生涯的大部分时间都在使用类似“扼杀”的东西:逐渐地将坏的旧代码变形为闪亮的新代码。这是我的食谱:

    从某个地方开始,在哪里并不重要。编写一些单元测试来查看代码的实际行为。找出它做你认为它做的事情的频率和不做的事情的频率。使用你的IDE重构代码,这样你就可以测试它了。

    第一天之后,猜猜你是不是从正确的地方开始把这个怪物分开。如果是这样的话,继续下去。如果没有,找个新地方重新开始。

    这种策略的优点:它只需一个小步骤就可以工作,因此风险可以得到控制,如果有什么东西坏了,如果必须存在于上周您一直在研究的代码中。

    缺点:这需要花费大量的时间,你会感到沮丧,因为通常情况下,进展会如此缓慢,直到“结”突然出现,所有的事情都会像魔术一样开始到位。

        2
  •  6
  •   David Hall    16 年前

    我从没听说过“扼杀者应用”这个词——我喜欢。在可能的情况下,这将始终是一个好的方法,它当然可以将风险降到最低,而且非常务实,一块一块地把这座大大厦拆下来。

    在我的经验中,这不起作用的地方就是需要立即进行相当重要的更改的地方——需要进行一些重构(或大量黑客攻击)的更改。在这种情况下,我经常发现我需要做的更改正是大泥球的核心,除了变脏之外没有其他选择——即使是应该做的标准维护或轻微的增强更改也是可怕的,主要的重构是最好的选择。

    对于这些情况,我会坚持分而治之——我一直追求的第一个目标是可测试性,一旦你拥有了它,其余的一切就变得容易多了。事实上,这常常是我重构远离泥球的主要驱动因素之一,这种类型的代码通常几乎是不可测试的,希望有示例UI输入和输出,但有时甚至会丢失。

    因此,当面对所有东西都集中到UI中的代码时,我通常首先将离散的功能单元分解为类和方法,然后将代码的这些部分向下推到域或服务层中。一点一点地做这件事大大减少了破坏某件事情的机会,并且使得在事情确实出错时更容易确定破坏代码的位置。

    在每次更改结束时运行任何可用的测试用例,并确保仍然满足某种基线。

    如果你边写边写好单元测试,你就可以开始减少问题的规模,我发现采用Strangler方法很快就变得实用了——用合适的单元测试或者至少是合适的框架来编写合适的单元测试,逐步替换部分功能变得更加实用。

        3
  •  4
  •   Andreas    14 年前

    我偶然发现了“天皇的方法”,它似乎有可能攻击这种性质的问题。

    http://mikadomethod.wordpress.com/

    还有一个关于天皇方法的讨论,来自REDEV 2010。

    http://oredev.org/2010/sessions/large-scale-refactorings-using-the-mikado-method

        4
  •  2
  •   Sharon Katz    9 年前

    大爆炸/大重新设计/重写软件…或者其他任何名字都不能作为一个活的软件。 原因是:

    • 您仍然需要使用(可能)您拥有的相同资源来支持现有的软件。

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

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

        5
  •  1
  •   Peter Miehle    16 年前

    取决于您是否必须始终处于工作状态,以便在需要时修复和部署bug,那么Devide和Converse将是一个很好的解决方案。如果您可以维护旧的代码,在处理新的代码时(并且让弟子将错误修复应用到这两个代码基),重新编写可能是更好的解决方案。

        6
  •  1
  •   SmacL    16 年前

    如果通过重构,您的意思是在不修改功能的情况下改进代码,那么我将从创建自动回归测试基线开始。有很多工具可以帮助解决这个问题。我用 TestComlete 尽管有好的廉价的替代品。

    在建立了回归测试基线之后,我个人会选择分而治之,因为根据我的经验,这是最有可能成功的。一旦你有了一个测试基线,选择哪种方法就不那么重要了。

        7
  •  1
  •   mezoid    16 年前

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

    如果这是一个非常小的项目,我会尝试从头开始重写它……但是你并不经常拥有那种奢侈。

    否则,我会一块一块地把它削掉。我会编写单元测试来验证现有的功能,并慢慢地使用TDD将代码转换成一个优雅而设计良好的系统。根据这个过程需要多长时间,它可能会开始看起来像你上面提到的扼杀应用程序。

    BigBang是非常危险的,因为您没有简单的方法来验证更新后的系统是否与旧系统做相同的事情。

    分而治之的风险比“大爆炸”要小……但如果它是一个足够大的系统,它最终会像“大爆炸”一样有问题。

        8
  •  0
  •   Rune Grimstad    16 年前

    完全重写是一个选项吗?根据我的经验,从头重写通常比试图清理现有的混乱更有效。您仍然会保留现有代码的一部分,但会保留在新的上下文中。对于GUI和数据库也是如此,如果你有一个的话。从头开始重写,随身携带你能用的东西。

        9
  •  -1
  •   Manoj    16 年前

    从一个干净的新体系结构开始,将旧的代码片段移动到这个新体系结构中,并根据新体系结构对其进行重构,这将是一个不错的选择。我认为在移动函数时采用自下而上的方法是很好的。