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

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

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

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

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

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


当前回答

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

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

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

其他回答

一种不太危险的方法是对所有的线变化进行历史性的观察。有没有特定的函数比其他函数更稳定?可以说是变化的热点。

如果某一行在几年内没有被更改过,你可以将它移到另一个文件中,而不用太担心。我会看一下用最后一次修改注释的源代码,看看是否有任何函数可以提取出来。

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

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

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

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

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

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

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

如果这个大的SWITCH(我认为是有的)成为主要的维护问题,你可以重构它,使用字典和命令模式,并从现有的代码中删除所有的开关逻辑到加载器,加载器填充该映射,即:

    // declaration
    std::map<ID, ICommand*> dispatchTable;
    ...

    // populating using some loader
    dispatchTable[id] = concreteCommand;

    ...
    // using
    dispatchTable[id]->Execute();

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

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


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