从定义上看,重构意味着改变程序的内部结构,而不改变外部的功能行为。这样做大多是为了提高程序的非功能性属性,从而提高代码的质量。然而,即便是经验丰富的敏捷开发者,在进行大规模的重构时也是如履薄冰。社区中的成员对掌控大规模重构的几种方式进行了讨论。

  在近的讨论中,Andreas想要知道三种可能完成大规模重构的方法中哪种好。他的方式包括,

  一次完成——定义终状态的结构,然后将代码一次完成。

  分而治之——将一大团乱七八糟的代码分为两段,然后重复这样的操作,直至完成……

  压制(Strangling)——压制类

  大多数回应者都认为“一次完成”几乎不会成功的。Aaron Digulla指出他在整个职业生涯中一直使用压制的方法。这种想法是要慢慢地将不好的代码变为崭新的优质代码,并在过程中用测试来保证转换的正确性。这种策略的优势在于,因为你是从小片段慢慢开始的,因此风险很小。David Hall和Shane MacLaughlin强调了分而治之方法的重要性,但也要针对程序所有修改的部分编写充分的测试。一些人建议完全推倒重写,但是正如InfoQ之前的一篇文章所说的,那会让你面临一系列的挑战。

  Sibylle Peter和Sven Ehrke提到,他们使用的方法是,先对工作进行评估,然后为大规模的重构制定主要计划。对于每个重构步骤,他们都会遵循以下三步:

  分析:定义想要的结果,并找到达到目的的方法。

  实现:应用重构技术来相应地改变代码。

  稳定:应用一些方法,确保实现的结果是持久的。

  另一种让大规模重构得以进行的方法是“天皇牌”(Mikado)方法。回顾天皇牌方法的历史,我们会发现它与Daniel Brolund和Ola Ellnestam所做的工作有关,而它的名字来自于天皇牌游戏。根据这个方法,

  修改代码像进行天皇牌游戏一样。当你想要对代码库做出修改时,几乎无法以正确的方式做出准确的修改你需要做些准备、移动代码、抽取类等等。我们很少会第一次抓到天皇牌。更多的是,在“重构天皇”可用之前,你需要做一系列的变动,有条不紊地向你的牌堆的底部进发,以达到目的。

  使用天皇牌方法,首先要记住终的目的。对于任何需要重构的代码,我们首先要创建一幅依赖图,在上面写下终的目标。下一步是识别出想要达到目标所需要的直接前提,然后以这种方式继续识别依赖关系,直到达到没有任何前提或者依赖的叶子节点。这可能是开始重构好的方式。一旦有了依赖关系图,那么核心思想是从叶子节点一步一步回溯,直到达到目标。

  这种方法强调了撤销操作的重要性,团队不应该害怕因为回退而抛弃一些改变。他还建议不要停止分析,而应该从基本步骤开始,然后理解顺序。现在他们已经提供了关于“天皇牌”方法的书的草稿版本。

  因此,大规模重构很难做,做好这项工作的关键在于要识别出起点,然后沿着路线小步前进。