所以我们在项目中有这个巨大的mainmodule.cpp源文件(11000行很大吗?),每次我不得不触摸它时,我都会畏缩。

由于这个文件是如此的核心和大,它不断积累越来越多的代码,我想不出一个好方法来让它实际上开始缩小。

该文件在我们产品的几个(> 10)维护版本中被使用和积极更改,因此很难重构它。如果我“简单地”将其拆分为3个文件,那么从维护版本合并回更改将成为一场噩梦。而且,如果您拆分具有如此长而丰富历史的文件,跟踪和检查SCC历史中的旧更改突然变得非常困难。

这个文件基本上包含了我们程序的“主类”(主要的内部工作调度和协调),所以每次添加一个特性,它也会影响这个文件,每次它的增长。:-(

在这种情况下你会怎么做?关于如何在不打乱SCC工作流程的情况下将新特性移动到单独的源文件中,您有什么想法吗?

(注意:我们使用c++和Visual Studio;我们使用AccuRev作为SCC,但我认为SCC的类型在这里并不重要;我们使用Araxis Merge来做实际的文件比较和合并)


当前回答

我的0.05欧分:

重新设计整个混乱的系统,考虑到技术和业务需求,将其拆分为子系统(=许多并行维护轨道,每个并行维护轨道的代码库可能不同,显然需要高可修改性等等)。

在划分子系统时,分析变化最大的地方,并将其与不变的部分分开。这应该会显示出问题所在。将最易变化的部分分离到它们自己的模块中(例如dll),这样模块API就可以保持完整,而不需要一直破坏BC。这样,如果需要,您可以为不同的维护分支部署不同版本的模块,同时保持核心不变。

重新设计很可能需要一个单独的项目,试图做一个移动的目标是行不通的。

至于源代码历史,我的意见是:为了新代码忘掉它吧。但是请将历史记录保存在某个地方,以便在需要时进行检查。我打赌你开始之后就不那么需要它了。

对于这个项目,您很可能需要得到管理层的支持。你可以用更快的开发时间、更少的bug、更容易的维护和更少的混乱来反驳。类似于“积极地使我们的关键软件资产具有未来的可靠性和维护可行性”:)

至少这是我开始解决问题的方式。

其他回答

考虑以更合理的方式重写整个应用程序的方法。也许可以重写其中的一小部分作为原型,看看你的想法是否可行。

如果您已经确定了一个可行的解决方案,那么相应地重构应用程序。

如果所有产生更合理架构的尝试都失败了,那么至少您知道解决方案可能是重新定义程序的功能。

这并不是一个大问题的答案,而是一个具体问题的理论解决方案:

Figure out where you want to split the big file into subfiles. Put comments in some special format at each of those points. Write a fairly trivial script that will break the file apart into subfiles at those points. (Perhaps the special comments have embedded filenames that the script can use as instructions for how to split it.) It should preserve the comments as part of the splitting. Run the script. Delete the original file. When you need to merge from a branch, first recreate the big file by concatenating the pieces back together, do the merge, and then re-split it.

另外,如果您想要保存SCC文件历史,我认为最好的方法是告诉您的源代码控制系统各个片段文件都是原始文件的副本。然后,它将保存该文件中保存的部分的历史,当然,它也将记录大部分被“删除”。

下面是我所想到的解决这些问题的唯一办法。所述方法的实际增益是演化的累进性。这里没有革命,否则你很快就会陷入麻烦。

在原来的主类上面插入一个新的cpp类。目前,它基本上会将所有调用重定向到当前的主类,但目标是使这个新类的API尽可能清晰和简洁。

一旦完成了这些,就可以在新类中添加新功能。

至于现有的功能,当它们变得足够稳定时,您必须逐步将它们移动到新的类中。对于这段代码,您将失去SCC帮助,但是对此没有太多办法。只要选择合适的时机。

我知道这并不完美,但我希望它能有所帮助,这个过程必须适应您的需要!

额外的信息

注意,Git是一个SCC,它可以从一个文件跟踪代码片段到另一个文件。我听说过关于它的好东西,所以它可以帮助你逐步转移你的工作。

Git是围绕blob的概念构建的,如果我理解正确的话,blob表示代码文件的片段。在不同的文件中移动这些片段,Git会找到它们,即使您修改了它们。除了下面评论中提到的Linus Torvalds的视频之外,我还没有找到关于这个问题的一些清楚的东西。

我认为最好创建一组映射到mainmodule.cpp的API点的命令类。

一旦它们就位,您将需要重构现有的代码库,以通过命令类访问这些API点,一旦完成,您就可以自由地将每个命令的实现重构为新的类结构。

当然,对于一个11 KLOC的类,其中的代码可能是高度耦合和脆弱的,但是创建单独的命令类比任何其他代理/外观策略都更有帮助。

我并不羡慕这项任务,但随着时间的推移,如果不加以解决,这个问题只会变得更糟。

更新

我建议Command模式比Facade更可取。

在一个(相对)单一的Facade上维护/组织许多不同的命令类是可取的。将一个Facade映射到一个11 KLOC文件本身可能需要分解成几个不同的组。

为什么要费心去弄清楚这些门面组呢?使用命令模式,你将能够对这些小类进行有机分组和组织,因此你有更多的灵活性。

当然,这两种选择都比单一的11 KLOC和不断增长的文件要好。

我的0.05欧分:

重新设计整个混乱的系统,考虑到技术和业务需求,将其拆分为子系统(=许多并行维护轨道,每个并行维护轨道的代码库可能不同,显然需要高可修改性等等)。

在划分子系统时,分析变化最大的地方,并将其与不变的部分分开。这应该会显示出问题所在。将最易变化的部分分离到它们自己的模块中(例如dll),这样模块API就可以保持完整,而不需要一直破坏BC。这样,如果需要,您可以为不同的维护分支部署不同版本的模块,同时保持核心不变。

重新设计很可能需要一个单独的项目,试图做一个移动的目标是行不通的。

至于源代码历史,我的意见是:为了新代码忘掉它吧。但是请将历史记录保存在某个地方,以便在需要时进行检查。我打赌你开始之后就不那么需要它了。

对于这个项目,您很可能需要得到管理层的支持。你可以用更快的开发时间、更少的bug、更容易的维护和更少的混乱来反驳。类似于“积极地使我们的关键软件资产具有未来的可靠性和维护可行性”:)

至少这是我开始解决问题的方式。