您如何处理重构和合并需求之间的紧张关系?

Posted

技术标签:

【中文标题】您如何处理重构和合并需求之间的紧张关系?【英文标题】:How do you handle the tension between refactoring and the need for merging? 【发布时间】:2010-09-17 01:51:09 【问题描述】:

我们在交付新版本时的政策是在我们的 VCS 中创建一个分支并将其交给我们的 QA 团队。当后者开绿灯时,我们标记并发布我们的产品。该分支会保留(仅)接收错误修复,以便我们可以创建技术版本。这些错误修复随后被合并到主干上。

在此期间,主干看到主要的开发工作,并且可能会受到重构更改的影响。

问题在于需要有一个稳定的主干之间存在紧张关系(以便错误修复的合并成功 - 如果代码已被提取到另一个方法,或者移动到另一个class) 以及在引入新功能时需要对其进行重构。

我们的策略是在足够的时间过去并且分支足够稳定之前不进行任何重构。在这种情况下,可以开始在主干上进行重构更改,并且在主干和分支上手动提交错误修复。

但这意味着开发人员必须等待相当长的时间才能在主干上提交任何重构更改,因为这可能会中断从分支到主干的后续合并。不得不手动将错误从分支移植到主干是很痛苦的。在我看来,这阻碍了发展......

你如何处理这种压力?

谢谢。

【问题讨论】:

【参考方案1】:

这是一个真正的实际问题。如果您有多个版本需要支持并为每个版本分支,情况会变得更糟。如果您也有真正的研发部门,那就更糟了。

我的偏好是让主干线以正常速度继续运行,而不是坚持下去,因为在发布时间在商业上很重要的环境中,我永远无法争辩我们应该让代码稳定的情况(“什么,你的意思是你在不稳定的状态下发布它?”)。

关键是确保为错误修复创建的单元测试在错误迁移到主分支时进行转换。如果您的新代码更改真的只是重构,那么旧测试应该同样有效。如果您的更改不再有效,那么无论如何您都不能只移植您的修复程序,您需要让某人认真考虑新代码流中的修复程序。

在处理此类问题多年后,我得出结论,您可能至少需要 4 个代码流来提供适当的支持和覆盖,以及一组非常严格的流程来管理它们之间的代码。这有点像能够用 4 种颜色绘制任何地图的问题。

我从来没有找到任何关于这个主题的真正好的文献。它将不可避免地与您的发布策略以及您与客户签署的 SLA 相关联。

附录:我还应该提到,有必要将分支合并作为特定里程碑写入主分支的发布时间表。如果您有一群辛勤工作的开发人员正在执行他们的工作来实现功能,请不要低估将您的分支整合在一起可能需要的工作量。

【讨论】:

【参考方案2】:

在我工作的地方,我们继续在主分支中进行重构。如果合并变得棘手,它们只需要临时处理,它们都是可行的,但偶尔需要一些时间。

【讨论】:

【参考方案3】:

也许我们的问题来自这样一个事实,即我们的分支必须具有相当长的寿命(最长 18 个月),并且必须针对它们进行许多修复。

确保我们只从极其稳定的代码分支可能会有所帮助,但不会那么容易...... :(

【讨论】:

【参考方案4】:

我认为可以通过在您的开发过程中添加以下成分来处理紧张局势:

    持续集成 自动化功能测试(我想你已经算过单元测试了) 自动交付

通过持续集成,每次提交都意味着一个构建,所有单元测试都会在其中执行,如果出现任何问题,您都会感到震惊。您开始更多地使用 head,并且不太容易分支代码库。

通过自动化功能测试,您只需单击按钮即可测试您的应用程序。通常,由于这些测试需要更多时间,因此每晚运行一次。 有了这个,版本控制的经典角色开始失去重要性。您不会根据版本及其成熟度来决定何时发布,更多的是业务决策。如果您已经实施了单元和功能测试并且您的团队正在提交经过测试的代码,那么 head 应该始终处于可以发布的状态。不断发现、修复和发布错误,但这不再是循环过程,而是持续的过程。

您可能会有两种类型的批评者,因为这意味着要改变一些根深蒂固的做法。首先,持续交付的范式转变对管理者来说似乎是违反直觉的。 “我们不是冒着发布重大漏洞的风险吗?”如果你看看 Linux 或 Windows 发行版,这正是他们正在做的事情:向客户推送版本。而且,由于您可以使用一套自动化测试,因此风险会进一步降低。

接下来,QA 团队或部门。 (有些人会争辩说问题在于它们本身的存在!)他们通常会厌恶自动化测试。这意味着学习新的,有时是复杂的工具。在这里,最好的做法是通过实践来宣讲。我们的开发团队开始致力于持续集成,同时使用Selenium 编写功能测试套件。当 QA 团队看到该工具在运行时,很难反对它的实施。

最后,我所描述的过程并不像在您的开发过程中添加 3 个要素那么简单。这意味着您开发软件的方式将发生深刻变化。

【讨论】:

我同意你的三个项目,但我认为它们对我的担忧没有帮助......我担心在经历了大的重构更改的开发线中合并更改的困难:这些更改会导致许多冲突... :( 持续集成背后的理念是小步进行重构并持续集成。这样可以缓解一些问题。根据代码的设计,您仍然可能最终会进行广泛的制动更改。首先重构以减少依赖。【参考方案5】:

在我工作的地方,我们会为每个重要的更改(功能添加或错误修复)创建临时的、短暂的(不到一天 - 几周)工作分支。主干是稳定的,并且(理想情况下)可能一直都可以释放;只有 done 项被合并到其中。每天从主干提交的所有内容都会合并到工作分支中;这可以很大程度上自动化(我们使用 Hudson、Ant 和 Subversion)。 (这是最后一点,因为通常最好尽早解决任何冲突,当然。)

我们当前使用的模型很大程度上受到 Henrik Kniberg 的一篇出色文章 (which I've plugged before) 的影响:Version Control for Multiple Agile Teams

(在我们的例子中,我们有两个 scrum 团队在一个代码库上工作,但我开始认为这种模型即使是一个团队也可能是有益的。)

额外的分支和合并会有一些开销,但不会太多,真的,一旦你习惯了它并更好地使用工具(例如svn merge --reintegrate很方便)。不,我并不总是创建临时分支,例如对于较小的、低风险的重构(与当前工作中的主要项目无关),只需一次提交到主干即可轻松完成。

我们还维护一个较旧的发布分支,其中不时修复严重错误。诚然,如果代码的某些特定部分在主干中与分支相比有了显着的发展,则可能需要手动(有时是乏味的)合并工作。 (随着我们不断从主干(内部)发布增量,并让营销和产品管理部门决定何时进行外部发布,这有望成为一个不那么重要的问题。)

我不确定这是否直接回答了您的问题,或者您是否可以在您的环境中应用它(与单独的 QA 团队和所有人员一起) - 但至少我可以说您所描述的紧张局势对我们来说并不存在我们可以随时进行重构。祝你好运!

【讨论】:

【参考方案6】:

也许 Git(或其他 DVCS)更擅长处理合并到更新的代码,这要归功于它们(真正)管理更改而不仅仅是比较文件......正如Joel says:

使用分布式版本控制,合并很容易并且工作正常。因此,您实际上可以拥有一个稳定的分支和一个开发分支,或者为您的 QA 团队创建长期分支,他们在部署之前测试事物,或者您可以创建短期分支来尝试新想法并查看它们是如何工作的。

不过还没试过……

【讨论】:

重构更改通常是无法自动合并的更改,即使是 DVCS。 (例如,如果一个人在一个分支上更改了方法签名,而另一个人在第二个分支上移动了该方法,而另一个人在不同的级别上修复了一些东西以完全消除对该方法的需求。)使用 DVCS 将减少问题,但不能完全消除。

以上是关于您如何处理重构和合并需求之间的紧张关系?的主要内容,如果未能解决你的问题,请参考以下文章

您如何处理模型类中的外键关系

您如何处理源代码管理中的 Visual Basic 6.0 frm 和 frx 文件?

您如何处理消息队列中乱序的消息?

您如何处理使用 36 位映射的 IO?

您如何处理 fetchxml 结果数据?

在类似 LMAX 的破坏者模式中,您如何处理缓慢的消费者?