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

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

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

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

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

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


当前回答

我不知道这是否解决了您的问题,但我猜您想要做的是将文件的内容迁移到彼此独立的更小的文件中(合计)。 我还了解到,你有大约10个不同版本的软件,你需要在不搞砸的情况下支持它们。

首先,这是不可能的简单,将解决自己在几分钟的头脑风暴。文件中链接的函数对应用程序都非常重要,简单地将它们删除并迁移到其他文件中并不能解决问题。

我认为你只有这些选择:

Don't migrate and stay with what you have. Possibly quit your job and start working on serious software with good design in addition. Extreme programming is not always the best solution if you are working on a long time project with enough funds to survive a crash or two. Work out a layout of how you would love your file to look once it's split up. Create the necessary files and integrate them in your application. Rename the functions or overload them to take an additional parameter (maybe just a simple boolean?). Once you have to work on your code, migrate the functions you need to work on to the new file and map the function calls of the old functions to the new functions. You should still have your main-file this way, and still be able to see the changes that were made to it, once it comes to a specific function you know exactly when it was outsourced and so on. Try to convince your co-workers with some good cake that workflow is overrated and that you need to rewrite some parts of the application in order to do serious business.

其他回答

这个问题在“有效地使用遗留代码”(http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052)一书的其中一章中得到了解决。

我想在这种情况下我该做的就是咬紧牙关

Figure out how I wanted to split the file up (based on the current development version) Put an administrative lock on the file ("Nobody touch mainmodule.cpp after 5pm Friday!!!" Spend your long weekend applying that change to the >10 maintenance versions (from oldest to newest), up to and including the current version. Delete mainmodule.cpp from all supported versions of the software. It's a new Age - there is no more mainmodule.cpp. Convince Management that you shouldn't be supporting more than one maintenance version of the software (at least without a big $$$ support contract). If each of your customers have their own unique version.... yeeeeeshhhh. I'd be adding compiler directives rather than trying to maintain 10+ forks.

跟踪文件的旧更改简单地通过您的第一个签入注释来解决,例如“从mainmodule.cpp分离”。如果你需要回顾最近的东西,大多数人会记得这个变化,如果是2年后,评论会告诉他们从哪里看。当然,回溯到2年前,看看是谁修改了代码以及为什么修改代码,这有多大价值呢?

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

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


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

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

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

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

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

更新

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

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

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

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

我的同情-在我以前的工作中,我遇到过类似的情况,一个文件比你必须处理的文件大几倍。解决方案是:

编写代码详尽地测试程序中的函数。听起来你还没有掌握这个… 确定一些可以抽象为帮助器/实用程序类的代码。不需要很大,只是一些不是你的“主要”类的真正一部分。 重构2中确定的代码。进入一个单独的班级。 重新运行测试,以确保没有损坏。 当你有时间的时候,去2。并根据需要重复以使代码易于管理。

在第3步中构建的类。迭代可能会增加以吸收更多适合于新清除的函数的代码。

我还可以补充:

0:购买Michael Feathers关于使用遗留代码的书

不幸的是,这种类型的工作太常见了,但我的经验是,在保持工作的同时,能够使工作但可怕的代码逐渐变得不那么可怕是有很大价值的。