如何处理耗时超过一个冲刺的重构?


49

我使用的代码库超过50万行代码。迫切需要重构。已经确定了重构工作将比正常的两周冲刺花费更长的时间。正如我在本网站上的其他答案所建议的那样,这些不能分解成较小的任务。产品需要在迭代结束时工作,并且部分重构将使系统处于无法使用的状态,因为项目之间的依赖关系非常糟糕。那么解决这一障碍的最佳方法是什么?我再次提到,将其分解成较小的部分不是一个选择,这已经完成了。

更新:人们似乎需要解释为什么这不能适合2周的冲刺。冲刺中涉及的不仅仅是编写代码。我们的政策是没有测试就没有代码。该策略并不总是存在,并且代码库中的很大一部分都没有。另外,我们的某些集成测试仍然是手动测试。问题不在于重构本身如此之大。事实是,小的更改会影响系统的许多部分,因此我们需要确保这些部分仍然可以正常运行。

因为我们有每月的修补程序,所以我们不能推迟或延长冲刺。因此,经过sprint的更改无法停止将其他工作添加到此修补程序中。

重构与重新设计:仅仅因为我们的开发过程效率不足,无法在两周的周期内完成此重构,所以不能保证将其重命名为重新设计。我想相信,随着我们流程的改进,将来我们可以在两周的周期内完成完全相同的任务。这里讨论的代码很长时间都不需要更改,并且相当稳定。现在,随着公司的发展方向变得更加适应变化,我们希望代码库的这一部分与其余部分一样具有适应性。这需要重构。根据这里的答案,很明显,在正常的sprint的时间范围内缺少必要的脚手架来进行此重构。

回答:

我将采用科宾·马奇(Corbin March)首次提出的分支与合并方法,以便我们可以更多地了解这些问题领域以及如何识别缺失的测试。我认为,向前迈进,我们应该采用Buhb建议的方法,确定缺少测试的区域并先实施这些区域,然后再进行重构。这将使我们能够保持正常的两周冲刺周期,就像这里的许多人一直在说的那样,重构应该总是如此。


23
顺便提一句,按照定义,这是大规模的重新设计,而不是重构。希望你不要把这个作为挑剔-恕我直言用清晰的术语来避免通讯问题是很重要的:-)
彼得Török

9
@Charles,“重构通常是在很小的步骤中完成的。在每个小步骤之后,您都会得到一个在功能上没有变化的工作系统。 ”引自我上面链接的页面。
彼得Török

2
@Charles:重构可以始终增量进行,同时保持系统正常运行。在要重构的类/程序包/模块的顶部放一个大的“ Refactoring in progress”注释,并一次完成一个部分。如果在对象模型转换期间剪切了临时发行版,那就可以了。
肖恩·麦克米兰

7
如果您执行的步骤如此之大,以致于您无法定期使用一段有效的代码,那么这就是重构何时重新设计的真正定义。请不要因为别人误用您的电话而生气。询问重新设计没有错。评论者只是试图表明您不会得到想要的答案,因为您正在滥用这个词,这已经发生了。
jprete 2011年

5
我知道这不是一个话题,但是您让我感到好奇的是,在什么情况下无法一步一步地进行重构。请分享一些与此有关的背景。
2011年

Answers:


14

如果您有延迟重构的奢侈之处,建议您将即将到来的迭代重点放在添加单元测试和自动集成测试上,以便您可以舒适地重构代码库,然后在单个sprint中进行重构。


68

我的建议:

  1. 创建一个分支
  2. 每天从主干合并到分支机构并解决冲突。
  3. 工作直到完成。您的分支可能不在几个sprint的核心开发范围内。
  4. 合并回主干。

没有回避它可能变得丑陋的事实。我不羡慕你 以我的经验,当您彻底更改项目时,将所有正在进行的开发合并到新范例中要比完成所有工作之后将新范例合并到现在已更改的主干中要容易得多。尽管如此,它仍然会很受伤。


1
我们已经讨论了使用这种方法的问题,如果在解决之前没有其他想法出来,这就是我们计划要做的事情。
查尔斯·兰伯特

3
如果要执行如此彻底的重构,恐怕您在主干和分支之间来回合并会产生大量开销。
乔治

在大多数情况下(希望如此),这些合并的更改不会影响此处讨论的代码。如果可以确保可靠的结果,我不介意延长此变更的时间表。
查尔斯·兰伯特

1
考虑到您的演示文稿似乎暗示的波动性,也许您应该考虑使用Git,因为它有助于进行这种推测性分支和合并。
John Tobler

1
@乔治:我也是,每天的合并似乎有点偏执,但这实际上取决于团队的规模。更多的人,更多的变化,和您应该更频繁地合并。如果您想有时间工作,则每日似乎是最低限制。
Matthieu M.

40

并非每个任务都可以在2周的(人工)冲刺中完成,因此需要常识。如果无法将其分解,而必须完成,则继续进行。该过程并不比最终结果重要,应该被视为指导方针,而不是永不间断的法律。


3
您的答案是关于该主题的很好的信息。正如您所说,我是来“继续做下去”的。我问了这个问题,希望能获得一些信息,以便我可以提出一个与现有流程并行运行的流程,或者以某种方式修改当前流程以解决当前情况。我需要告诉开发人员一些事情,以便他们可以制定指导方针,因为这至少还会发生两次。
查尔斯·兰伯特

+1表示“该过程并不比最终结果重要,应该将其视为准则,而不是永不间断的法律。” -人们真的似乎忘记了这一点。
Bjarke Freund-Hansen

32

只需进行3、4或5周的冲刺。谁在乎?您显然确信在较短的时间内什么也做不了,所以请停止战斗。

只是不要告诉您的皇家盲人敏捷坚持学会会员。


似乎由于组织原因(每月修复程序),很难更改2周的sprint。
史蒂夫·贝内特

10

我建议从迈克尔·费瑟斯(Michael Feathers)的《有效地处理旧版代码》一书开始。他介绍了各种技术,以减少重构样式更改的范围。


可以肯定地说是一本好书,但是我不认为这涉及对多个sprint进行拆分重构。
亚当李尔

4
我将为此+1,因为它可能是您开始学习如何有效使用遗留代码的最佳书,正如书名所述。与可能问这个问题但不了解将事情分解为更小的步骤的人有关。
查尔斯·兰伯特

@Anna-然后,您可能想(重新)阅读第25章,它讨论了打破各种防止微小变化的联轴器的技术。
kdgregory

@kdgregory足够公平。:)介意将其添加到您的答案中以使其更加出色吗?
亚当李尔

7

在我们的商店中,当我们有大量的重构或重写任务无法在发布窗口中完成时,我们会将功能保留在系统中。但是,我们会在时间允许的情况下开始使用新的重构的乐高积木功能。最终,我们进入了完成了足够的乐高积木的状态,冲刺提供了足够的时间将乐高积木插入应用程序并为用户打开。

简而言之,我们使用新名称分解或重做大型功能。然后,最后,我们使用重命名的重构工作,而不是讨厌的旧代码。


这是一个好主意,但需要进行高层沟通。例如,当我在编码时,如果我确定一个未在任何地方使用且不公开的方法,则将其删除。
查尔斯·兰伯特

5

专门进行一次冲刺,以弄清楚如何在重构期间使代码正常运行。这可以采用不推荐使用的方法和类,包装器,适配器等的形式。您的重构可能会使代码在短时间内变得更脏,从而使代码长期保持清洁。没关系。现在,您是说无法完成。我认为这是不对的-考虑一下您的流程(如果可以完成的话)会是什么样子,请考虑可以采取哪些步骤来做到这一点。然后潜入。


我们已经完成了所有这一切。这就是我明确表示无法分解的原因。
查尔斯·兰伯特

真?您花费了整个冲刺时间,只是计划如何在不中断系统的情况下进行重构,却一无所获?我发现很难相信专门的计划冲刺什么都没有完成。也许您需要聘请一名顾问(不,我不是一个人,不是想找一个演出)。
Carl Manaster

1
我什么也没说。我是说我们经历了与您描述的过程类似的过程,并且在另一端出现了一些无法在单个sprint中重构的代码。
查尔斯·兰伯特

我说:“专门花一点时间弄清楚如何在重构期间使代码正常运行。” 您说:“我们已经完成了所有这一切。” 您现在是否在说其他话?抱歉,这听起来很抱歉,但我不明白。
Carl Manaster

5

+1正是Corbin March的答案,这正是我的想法。听起来您的代码库有点丑陋,清理起来将需要多个冲刺周期。
就像科宾说的那样

  1. 将其分支为“重构项目”
  2. 测试您的分支机构更改
  3. 升级到您的测试环境以进行质量检查
  4. 逐步将其合并回主干,直到重构完成。

我敢肯定,如果您的项目经理很难看到它,那么将其出售给您的开发经理不会有任何问题,然后向他们解释罗马不是一天建成的,并清理掉扔入罗马的所有垃圾。一天也不行。重构将花费一些时间,但最终在更容易维护,更快速的增强版本,更少的生产票据以及更完善的SLA方面值得这样做。


1
我拥有所有需要与所有人交谈的弹药。当我提出它时,我只需要一个正式的计划就可以执行它。从这里的答案中,我无疑会提出一个可重复的解决方案。
查尔斯·兰伯特

4

尽管您真正想做的重新设计是一项艰巨的任务,但是否可以重构较小的零件以打破/分离各个依赖关系?您知道-如有疑问,请添加间接功能。与您无法完成的庞大任务相比,这些解耦中的每一项都应该是一项更小的任务。

删除依赖项后,您应该能够分解其余的重构任务,以便在sprint中获得。


3

在我目前正在从事的项目中,我们正在使用4周的冲刺。有时我们无法完成用户故事,而只是在下一个冲刺期间重新启动它。

但是,恕我直言,应该可以将重构分解为适合4周冲刺的较小故事。如果您无法在4周内使代码保持一致状态,我觉得您是在重写应用程序而不是在重构它。


一个4周的冲刺就可以解决这个问题。但是,由于其他错误修复等原因,我们无法停止当前2周的冲刺。因此,这将不得不扩展多个冲刺。因此,我的问题的症结所在。
查尔斯·兰伯特

正如我所说,我们正在使用4个星期的冲刺,如果一个故事没有在4个星期内完成,我们只是将其安排在下一个冲刺中。在至少两周的冲刺结束后,您是否至少可以使系统处于一致状态(然后在下一个冲刺中继续进行)?
乔治

不是可验证的一致状态。
查尔斯·兰伯特

我必须对其他人所做的努力表示敬意,希望您能找到另一个可以使用而不是“重构”的词。重构是定义明确的,并且其范围比您需要进行的大量且耗时的重新设计和编程要紧迫和短期的。
John Tobler

2

我建议当某些任务需要比2周的冲刺周期更长的时间时,将该任务定为另一时间。您的团队已经确定了重构的需求,这一点很重要。有时,没有其他选择……是的,这确实很糟糕。

当开始重构的时候,您只需暂停正常的sprint。你别无选择。使用智能版本控制-分支,重构,测试,合并。在某些时候,重构某些大型项目总是优先于功能。如果可能的话,我也将尝试将关注点分开以提高灵活性。


我们不能永远推迟它,您的答案也没有解决如何执行重构。
查尔斯·兰伯特

@查尔斯:“预定了另一个时间。” ;)我没有说要取消该项目。
IAbstract

2

最近,我们在代码库的一部分中也遇到了同样的问题(该问题也有所扩大),我希望可以与您分享一些见解。在我的情况下,代码库是由另一个团队开发的,因此原始开发人员中没有人参与此重构。我在代码库方面的经验约为1年,而另一位开发人员则要求2年。

请给我两个关于其他答案的小笔记:

  • 分支将帮助您为自己建立一个游乐场,但切勿将更改合并到一个大型变更集中。您将与团队的其他成员陷入严重麻烦。
  • 您需要逐步执行此操作,并且可以完成。没有理由。阅读“有效使用旧版代码封面”进行介绍。再次阅读。
  • 认为自己可以迈出一大步是谬论。尽管工作似乎更多,但逐步进行管理起来却容易得多。

看似“关闭预订”两个星期或更长时间不会引起人们的注意。您需要确保获得项目管理,甚至更重要的是团队的支持。如果团队不致力于这种重构(这意味着现在就去做,而不是在不久的将来),那么您就会遇到麻烦。

不要一个人做,要使用结对编程。严格来说,这并不意味着您需要一直坐在同一个键盘的前面,而是可以单独处理一些细小的任务(例如,编写捕获此类行为的测试)。

进行临时重构,并按原样进行处理。(某种“扔掉的”原型重构,“扔掉的”位很重要!)老实说,您不太可能知道重构将带来的所有影响。从头开始重构将在某些方面为您提供帮助:

  • 您将发现系统中从未存在的部分。
  • 您将对模块如何互连有更好的了解
  • 您将发现一种将系统分为模块的新方法,这可能与您当前的理解大不相同。与您的伴侣讨论见解。尝试提炼您的新观点。编写简短的体系结构白皮书(或绘制图表),说明当前事物的位置以及逻辑上应该属于的位置。

当您完成从头开始的重构后,希望您会发现您不能随便更改所有内容。您会感到难受,这只是一个很大的麻烦,您不能只是轻按一下开关并使其工作。这就是我所发生的事情,您的情况可能有所不同。

但是,我和我的搭档确实对我们的系统有了更好的了解。现在,我们可以识别单个的,较小的(尽管仍然很大)的重构/重新设计。我们以图表的形式捕获了对系统的愿景,并与团队共享,以及为实现该愿景而想到的积压项目。在共同共识的推动下,我们决定了在下一次迭代过程中将实施哪些项目。

帮助我们的最后一件事是使用一块大白板。有太多事情要记住。记笔记非常重要。在一天结束时给自己写一份简短的汇报单,记录下您今天要做的事情和明天要做的事情。它确实有助于放松大时间,如果您想跟上任务,就需要放松一下。祝好运!



0

我们手头有两种类型的作品:

  1. 工时工作
  2. 天才作品

重构通常是第一类工作,因为开发人员已经知道了许多方法,例如DRYSRPOCPDI等。因此,当一个项目需要两个月的时间进行重构时,只需两个月,没办法。因此,我的建议是不要重构原始项目,而让它按当前情况工作。停止接收利益相关者和产品所有者的新要求和要求。然后,让团队进行项目工作,直到重构并准备就绪为止。


0

一个建议可能会有所帮助:如果您有未经测试的代码,以致您没有足够的时间在两周的冲刺时间内重构重新测试它,请考虑首先对代码进行一些其他不相关的小改动,以便您可以专注于在为第一个或第二个冲刺编写测试时。也许您可以为要重构的代码确定几个未经测试的客户端;选择一个客户并对业务进行一些其他用途上的更改,这将迫使您为该客户编写测试。一旦您对代码更加熟悉,通过使用它,并且进行了更多测试,并且可能已经完成了一些次要的重构,那么您将处于更好的位置来完成重构,并且(现在更加容易) )在一次迭代中进行测试。

另一种方法是复制有问题的代码,对其进行重构,然后一次将一个客户端移至新代码。这项工作可以在迭代中分解。

并且不要放弃:不要只是接受一个大型重构不能分解成更小的步骤。最简单/最快/最好的方法可能要花费比迭代更长的时间。但这并不意味着没有办法进行迭代大小的块。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.