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

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

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

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

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

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


当前回答

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

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

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

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

更新

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

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

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

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

其他回答

我的0.05欧分:

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

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

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

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

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

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

永远不要再碰这个文件和代码! 对待就像你被困住了一样。开始为编码在那里的功能编写适配器。 用不同的单元编写新代码,只与封装怪物功能的适配器对话。 ... 如果以上只有一项是不可能的,那就辞职去找一份新工作。

一个重要的建议:不要将重构和错误修复混合在一起。您需要的是程序的版本与以前的版本相同,只是源代码不同。

一种方法是开始将最小的函数/部分分割到它自己的文件中,然后使用头文件include(从而将main.cpp转换为#includes列表,这本身听起来有点代码味道*尽管我不是c++专家),但至少现在它被分割为文件)。

然后,您可以尝试将所有维护版本切换到“新的”main.cpp或任何您的结构。再次重申:没有其他更改或错误修复,因为跟踪这些是令人困惑的地狱。

另一件事:尽管您可能希望一次性完成整个重构,但您可能会贪多嚼不烂。也许只是选择一两个“部分”,把它们放到所有的版本中,然后为你的客户增加一些更多的价值(毕竟,重构并不会直接增加价值,所以它是一种成本,必须被证明是合理的),然后再选择另外一两个部分。

显然,这需要团队中的一些纪律来实际使用拆分文件,而不是一直向main.cpp中添加新内容,但是,尝试进行一次大规模的重构可能不是最佳的行动方案。

好吧,我理解你的痛苦:)我也参与过一些这样的项目,它并不漂亮。这个问题没有简单的答案。

一种可行的方法是开始在所有函数中添加安全保护,也就是说,检查方法中的参数、前置/后置条件,然后最终添加单元测试,以便捕获源的当前功能。一旦你有了这些,你就可以更好地重构代码,因为如果你忘记了什么,你就会有断言和错误弹出来提醒你。

有时候,重构带来的痛苦可能会大于好处。那么,最好是让原始项目处于伪维护状态,从头开始,然后增量地添加野兽的功能。

合并不会像将来获得30000个LOC文件那样是一个大噩梦。所以:

停止向该文件添加更多代码。 把它。


如果你不能在重构过程中停止编码,你可以暂时保留这个大文件,至少不向它添加更多的代码:因为它包含一个“主类”,你可以从它继承,并将继承的带有重载函数的类保留在几个新的小而设计良好的文件中。