很明显,缺乏测试会让人们在尝试重构代码时感到紧张。任何人都会想知道你的重构是否会破坏应用程序,他们会从哪里获得信心呢?我认为,你会得到大多数答案是“这将非常困难,成功率不高”,这主要是因为你面临着一个巨大的手动任务,而且没有信心得到答案。
只有两种出路。
建立一堆测试。不幸的是,这将花费很多时间,大多数经理看不到任何价值;毕竟,你到现在为止已经没有用到它们。回到信仰的问题并不能帮助你;在有用的事情发生之前,你仍然需要花费很多时间。如果他们让你建立测试,你将面临一个问题,那就是当你重构时如何改进测试;虽然它们可能不会改变功能,但是随着你构建新的 API,测试也必须相应地改变。这是超出了重新构建代码库的额外工作。
自动化重构过程。如果你应用可靠的自动化转换,你可以争辩(通常不成功)说,重构后的代码保留了原始系统的功能。打败失败的论点的方法是编写这些测试(参见第一种方法),并将重构过程应用于应用程序和测试;随着应用程序更改结构,测试也必须进行更改。但从自动化机器的角度来看,它们只是应用程序代码。
很少有人做后者;你从哪里得到可以完成这些事情的工具呢?
实际上,这样的工具是存在的。它们被称为程序转换工具,用于对代码进行大规模的转换。
可以将其视为大规模重构的工具;由于规模较大,它们往往不是交互式的。
配置它们以完成手头的任务需要付出一定的努力;您必须编写自定义规则以实现所需的自定义结果。您可能无法在一周内完成此操作,但这比手动修改大型系统要少得多。您应该考虑到您已经投入了150人年的时间和精力来开发现有软件;制造混乱花费了那么长的时间。因此,花费“一些”相对较小的努力应该是可以接受的。
我只知道有三种工具可能适用于真实代码:TXL,Stratego/XT和我们的工具DMS软件重构工具包。前两者是学术产品(尽管TXL过去曾用于商业活动);DMS是商业产品。
DMS已被广泛用于大规模软件分析和海量转换任务。其中一项任务是
B-2隐形轰炸机语言自动翻译,另一项则更接近于您的重构问题,即将基于遗留专有RTOS组件的C++大型组件化系统实现自动架构转变为CORBA/RT,其中组件API必须从特定结构变为CORBA风格的
facet 和
receptacle 接口,并使用CORBA / RT服务代替遗留RTOS服务。 (这些任务都是由聪明而熟练的DMS人员在1-2年时间内完成的实际工作量)。
仍然存在着测试构建问题(上述这两个示例已经有了很好的系统测试)... 在这里,我要冒一次险。我相信通过在运行代码中添加仪器来收集函数输入输出结果,可以获得自动化测试生成的工具。我们已经为源代码构建了各种仪器(显然,在仪器化之后还需要编译它),并且认为我们知道如何做到这一点。因人而异。
你可以做一些相对不那么雄心勃勃的事情:通过查找代码中已重用的部分来确定代码的可重用性。大多数软件系统包含大量克隆代码(我们的经验是10-20%[我对另一个答案中报告较小数字的PHP感到惊讶;我怀疑他们使用了弱克隆检测器])。克隆代码是应用软件中缺少抽象的提示。如果您可以找到克隆并查看它们的变化方式,则可以很容易地看出如何将其抽象成函数(或其他内容)以使其明确和可重用。
Salion Inc. 进行了克隆检测和抽象化。该论文并未探讨抽象化活动;实际上,Salion定期审查检测到的克隆,并手动修复那些极其严重或有意义的克隆,将它们转换为(通常是库)方法。最终结果是代码库实际上缩小了,并且程序员变得更加有效,因为他们拥有更好(“更可重用”)的库。
他们使用了我们的CloneDR,这是一种利用程序语法作为指南查找克隆的工具。CloneDR可以找到精确的克隆和近似匹配(替换标识符或语句),并提供特定的克隆位置和克隆参数列表,无论布局和注释如何。您可以在链接中查看多种语言的克隆报告。(我是CloneDR的发起人和作者,身兼多职)。
关于在另一个答案中讨论的 PHP 项目的“小克隆百分比”:我不知道使用了什么克隆检测器。我所知道的唯一专注于 PHP 的克隆检测器是
PHPCPD,但我认为它是一个糟糕的克隆检测器;如果我理解正确,它只能找到完全相同的克隆。请参考我们网站上的 PHP 示例进行比较。