您如何处理重构和合并需求之间的紧张关系?
我们交付新版本时的政策是在 VCS 中创建一个分支并将其交给我们的 QA 团队处理。 当后者批准后,我们就会标记并发布我们的产品。 该分支保留(仅)接收错误修复,以便我们可以创建技术版本。 这些错误修复随后会合并到主干上。
在此期间,主干会看到主要的开发工作,并且可能会受到重构更改的影响。
问题在于,需要有一个稳定的主干(以便错误修复的合并成功——如果代码已被提取到另一个方法,或移动到另一个类,则通常无法成功)和引入新功能时需要重构它。
我们的政策是在经过足够的时间并且分支足够稳定之前不进行任何重构。 在这种情况下,可以开始在主干上进行重构更改,并且要在主干和分支上手动提交错误修复。
但这意味着开发人员必须等待相当长的时间才能在主干上提交任何重构更改,因为这可能会破坏随后从分支到主干的合并。 并且必须手动将错误从分支移植到主干是痛苦的。 在我看来,这阻碍了发展……
你如何处理这种紧张局势?
谢谢。
Our policy when delivering a new version is to create a branch in our VCS and handle it to our QA team. When the latter gives the green light, we tag and release our product. The branch is kept to receive (only) bug fixes so that we can create technical releases. Those bug fixes are subsequently merged on the trunk.
During this time, the trunk sees the main development work, and is potentially subject to refactoring changes.
The issue is that there is a tension between the need to have a stable trunk (so that the merge of bug fixes succeed -- it usually can't if the code has been e.g. extracted to another method, or moved to another class) and the need to refactor it when introducing new features.
The policy in our place is to not do any refactoring before enough time has passed and the branch is stable enough. When this is the case, one can start doing refactoring changes on the trunk, and bug-fixes are to be manually committed on both the trunk and the branch.
But this means that developpers must wait quite some time before committing on the trunk any refactoring change, because this could break the subsequent merge from the branch to the trunk. And having to manually port bugs from the branch to the trunk is painful. It seems to me that this hampers development...
How do you handle this tension?
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这是一个现实的实际问题。 如果您需要支持多个版本并为每个版本进行分支,情况会变得更糟。 如果您也有真正的研发部门,那就更糟糕了。
我的偏好是让主干以正常速度进行,而不是等待,因为在发布时间在商业上很重要的环境中,我永远不会争论我们应该让代码稳定下来(“什么,你的意思是你在不稳定状态下释放它?”)。
关键是确保为错误修复创建的单元测试在错误迁移到主分支时进行转换。 如果您的新代码更改确实只是重构,那么旧测试应该同样有效。 如果您的更改不再有效,那么您无论如何都不能只是移植您的修复程序,并且您需要让某人认真考虑新代码流中的修复程序。
经过多年管理此类问题后,我得出的结论是,您可能至少需要 4 个代码流才能提供适当的支持和覆盖范围,以及一组相当严格的流程来管理它们之间的代码。 这有点像能够用 4 种颜色绘制任何地图的问题。
我从未找到任何关于这个主题的真正好的文献。 它不可避免地与您的发布策略以及您与客户签署的 SLA 相关联。
附录:我还应该提到,有必要将分支合并作为特定的里程碑写入主分支的发布时间表中。 如果您有一群勤奋的开发人员正在实施功能,请不要低估将分支机构整合在一起可能需要的工作量。
This is a real practical problem. It gets worse if you have several versions you need to support and have branched for each. Even worse still if you have a genuine R&D branch too.
My preference was to allow the main trunk to proceed at its normal rate and not to hold on because in an environment where release timings were important commercially I could never argue the case that we should allow the code to stabilise ("what, you mean you released it in an unstable state?").
The key was to make sure that the unit tests that were created for the bug fixes were transitioned across when the bug was migrated into the main branch. If your new code changes are genuinely just re-factoring then the old tests should work equally well. If you changes are such that they are no longer valid then you can't just port you fix in any case and you'll need to have someone think hard about the fix in the new code stream.
After quite a few years managing this sort of problem I concluded that you probably need 4 code streams at a minimum to provide proper support and coverage, and a collection of pretty rigorous processes to manage code across them. It's a bit like the problem of being able to draw any map in 4 colours.
I never found any really good literature on this subject. It will inevitably be linked to your release strategy and the SLAs that you sign with your customers.
Addendum: I should also mention that it was necessary to write the branch merging as specific milestones into the release schedule of the main branch. Don't under-estimate the amount of work that might be entailed in bring your branches together if you have a collection of hard-working developers doing their job implementing features.
在我工作的地方,我们为每个重要的更改(功能添加或错误修复)创建临时的、短期的(不到一天 - 几周)工作分支。 躯干是稳定的并且(理想情况下)可以一直释放; 只有已完成项目会合并到其中。 每天从主干提交的所有内容都会合并到工作分支中; 这可以在很大程度上实现自动化(我们使用 Hudson、Ant 和 Subversion)。 (当然,最后一点是因为通常早点解决冲突比晚点解决更好。)
我们当前使用的模型很大程度上受到一篇优秀文章的影响(我之前插入过),作者:Henrik Kniberg:多个敏捷团队的版本控制。
(在我们的例子中,我们有两个 Scrum 团队在一个代码库上工作,但我认为即使只有一个团队,这种模型也可能是有益的。)
额外的分支和合并会产生一些开销,但实际上不会太多,一旦您习惯了它并更好地使用这些工具(例如
svn merge --reintegrate
很方便)。 不,我并不总是创建临时分支,例如,用于较小的、低风险的重构(与当前正在工作的主要项目无关),这些重构可以通过对主干的一次提交轻松完成。我们还维护一个较旧的版本分支,其中不时修复关键错误。 诚然,如果代码的某些特定部分与分支相比在主干中发生了显着的变化,则可能需要手动(有时是乏味的)合并工作。 (随着我们不断从主干(内部)发布增量,并让营销和产品管理决定何时进行外部发布,这希望不再是一个问题。)
我不确定这是否直接回答了您的问题,或者如果您可以将其应用到您的环境中(与单独的 QA 团队等) - 但至少我可以说您所描述的紧张对我们来说并不存在,我们可以随时进行重构。 祝你好运!
Where I work, we create temporary, short-lived (less than day -- a few weeks) working branches for every non-trivial change (feature add or bugfix). Trunk is stable and (ideally) potentially releasable all the time; only done items get merged into it. Everything committed from trunk gets merged into the working branches every day; this can be largely automated (we use Hudson, Ant and Subversion). (This last point because it's usually better to resolve any conflicts sooner than later, of course.)
The current model we use was largely influenced by an excellent article (which I've plugged before) by Henrik Kniberg: Version Control for Multiple Agile Teams.
(In our case, we have two scrum teams working on one codebase, but I've come to think this model can be beneficial even with one team.)
There is some overhead about the extra branching and merging, but not too much, really, once you get used to it and get better with the tools (e.g.
svn merge --reintegrate
is handy). And no, I do not create a temp branch always, e.g. for smaller, low-risk refactorings (unrelated to the main items currently under work) that can easily be completed with one commit to trunk.We also maintain an older release branch in which critical bugs are fixed from time to time. Admittedly, there may be manual (sometimes tedious) merging work if some particular part of code has evolved in trunk significantly compared to the branch. (This hopefully becomes less of an issue as we move towards continually releasing increments from trunk (internally), and letting marketing & product management decide when they want to do an external release.)
I'm not sure if this answers your question directly, or if you can apply this in your environment (with the separate QA team and all) - but at least I can say that the tension you describe does not exist for us and we are free to refactor whenever. Good luck!
也许 Git(或其他 DVCS)更擅长处理更新代码的合并,因为它们(真正)管理更改而不仅仅是比较文件......如 乔尔说:
不过还没有尝试过...
Maybe Git (or other DVCS) are better at handling merges to updated code thanks to the fact that they (really) manage changes rather than just compare files... As Joel says :
Not tried yet, though...
在我工作的地方,我们在主分支中进行重构。 如果合并变得棘手,则只需临时处理即可,它们都是可行的,但有时需要一些时间。
Where I work, we keep with the refactoring in the main branch. If the merges get tricky, they just have to be dealt with on an ad-hoc basis, they're all do-able, but occasionally take a bit of time.
也许我们的问题来自这样一个事实:我们的分支必须具有相当长的寿命(长达 18 个月),并且必须针对它们进行许多修复。
确保我们只从极其稳定的代码分支可能会有所帮助,但不会那么容易......:(
Maybe our problem comes from the fact that we have branches that must have quite a long life (up to 18 months), and there are many fixes that have to be done against them.
Making sure that we only branch from extremely stable code would probably help, but will not be so easy... :(
我认为可以通过在开发过程中添加以下成分来解决这种压力:
通过持续集成,每次提交都意味着一个构建,其中所有单元测试都被执行,并且您如果出现任何问题,我们会感到震惊。 您开始更多地使用 head 进行工作,并且不太容易对代码库进行分支。
通过自动化功能测试,您只需单击按钮即可测试您的应用程序。 一般来说,由于这些测试需要更多时间,因此每晚运行。
这样,版本控制的经典作用就开始失去重要性。 您不必根据版本及其成熟度来决定何时发布,这更多的是业务决策。 如果您已经实施了单元和功能测试,并且您的团队正在提交经过测试的代码,则 head 应始终处于可以发布的状态。 错误不断地被发现、修复并发布,但这不再是一个循环过程,而是一个连续的过程。
您可能会遇到两种类型的批评者,因为这意味着改变一些根深蒂固的做法。 首先,持续交付的范式转变对于管理者来说似乎是违反直觉的。 “我们不是在冒着发布重大错误的风险吗?” 如果你看一下 Linux 或 Windows 发行版,你会发现这正是他们正在做的事情:向客户推送版本。 而且,由于您使用了一套自动化测试,因此危险会进一步减少。
接下来是 QA 团队或部门。 (有些人会认为问题在于它们本身的存在!)他们通常会厌恶自动化测试。 这意味着学习新的有时甚至是复杂的工具。 在这里,最好的办法就是边做边讲。 我们的开发团队开始致力于持续集成,同时使用 Selenium 编写功能测试套件。 当 QA 团队看到该工具正在运行时,很难反对它的实施。
最后,我所描述的过程并不像在开发过程中添加 3 个要素那么简单。 它意味着您开发软件的方式将发生深刻的变化。
I think the tension can be handled by adding following ingredients to your development process:
With continuous integration, every commit implies a build where all unit tests get executed and you are alarmed if anything goes wrong. You start working more with head and you are less prone to branching the code base.
With automated functional tests, you are able to test your application at the click of the button. Generally, since these tests take more time, these are run nightly.
With this, the classic role of versioning starts to lose the importance. You do not make your decision on when to release based on the version and its maturity, it’s more of the business decision. If you have implemented unit and functional testing and your team is submitting tested code, head should always in state that can be released. Bugs are continuously discovered and fixed and release delivered but this is not any more cyclical process, it’s the continuous one.
You will probably have two types of detractors, since this implies changing some long rooted practices. First, the paradigm shift of continuous delivery seems counter-intuitive to managers. “Aren’t we risking to ship a major bug?” If you take a look at Linux or Windows distros, this is exactly what they are doing: pushing releases towards customers. And since you count with suite of automated tests, dangers are further diminished.
Next, QA team or department. (Some would argue that the problem is their existence in itself!) They will generally be aversive towards automating tests. It means learning new and sometimes complicated tool. Here, the best is to preach by doing it. Our development team started working on continuous integrations and in the same time writing the suite of functional tests with Selenium. When QA team saw the tool in action, it was difficult to oppose its implementation.
Finally, the thurth is that the process I described is not as simple as addig 3 ingredinents to your development process. It implies a deep change to the way you develop software.