我们使用VC6编译器在C++中实现的非常古老的遗留系统.现在我们正在重构代码.我们还切换到了VC9编译器.
我们使用外部专有框架,这也是遗留代码,而不是单元可测试的.为了使我们的代码单元可测试,我们为框架类引入了接口和包装器(提示:请参阅Martin Fowler的"使用遗留代码"):

现在我们依赖于接口.包装器调用框架方法,我们可以愉快地在单元测试中使用模拟.
在这里,我们来解决我们的问题......
框架类包含许多需要包装和模拟的方法.为了实现这一目标,我们的供应商团队编写了一个API,它使用C++宏生成接口,包装器和模拟器实现.
包装头文件的示例:
class PlanWrapper : public IPlan
{
// ...
WRP_DECLARE_DEFAULTS(FrameworkPlan); // macro
WRP_DECLARE_CSTR_ATTR(FrameworkPlanLabel); // macro
// ...
};
Run Code Online (Sandbox Code Playgroud)
宏WRP_DECLARE_CSTR_ATTR的定义如下:
#define WRP_DECLARE_CSTR_ATTR(AttrName) \
virtual bool set##AttrName (LPCTSTR Value_in); \
virtual bool get##AttrName (CString& Value_out); \
virtual bool unset##AttrName (); \
virtual bool isSet##AttrName ()
Run Code Online (Sandbox Code Playgroud)
包装器cpp文件的示例:
#include "StdAfx.h"
using namespace SomeNamespace;
WRP_IMPLEMENT_MODDICOM_DEFAULTS(FrameworkPlan)
WRP_IMPLEMENT_W_CSTR_ATTR (FrameworkPlan,FrameworkType1, FrameworkPlanLabel)
// ...
Run Code Online (Sandbox Code Playgroud)
宏WRP_IMPLEMENT_W_CSTR_ATTR的定义如下:
#define WRP_IMPLEMENT_W_CSTR_ATTR(ClassName,AtrTypeObj,AttrName) \
bool ClassName##Wrapper::set##AttrName (LPCTSTR Value_in) { \
AtrTypeObj aValue = Value_in; \
FrameworkLink<ClassName> convertedObj …Run Code Online (Sandbox Code Playgroud) 好的我在哪里工作,我们在过去的几十年中编写了相当多的系统.
系统多种多样,多个操作系统(Linux,Solaris,Windows),多个数据库(oracle,sybase和mysql的几个版本),甚至多种语言(C,C++,JSP,PHP和许多其他语言)都是用过的.
每个系统都是相当自治的,即使以将相同数据输入多个系统为代价.
管理层最近决定,我们应该调查让所有系统愉快地互相交流和共享数据所需的内容.
请记住,虽然我们可以对任何单个系统进行软件更改,但任何一个系统(或更多)的完全重写都不是管理层可能会接受的.
这里几个开发人员的第一个想法是直截了当:如果系统A需要来自系统B的数据,它应该只连接到系统B的数据库并获得它.同样,如果需要提供B数据,则应将其插入B的数据库中.
由于使用的数据库(和版本)混乱,其他开发人员认为我们应该有一个新的数据库,结合所有其他系统的表,以避免不得不兼顾多个连接.通过这样做,他们希望我们能够整合一些表并摆脱冗余数据输入.
这是关于我对整个烂摊子的看法.
使用数据库作为系统通信手段的整个想法对我来说很有趣.业务逻辑必须放在多个系统中(如果系统A想要向系统B添加数据,它在插入之前更好地理解B关于数据的规则),几个系统很可能必须进行某种形式的数据库轮询才能找到对数据的任何更改,持续维护将是一件令人头疼的事情,因为对数据库模式的任何更改现在都会传播到多个系统.
我的第一个想法是花时间为不同的系统编写API /服务,一旦编写就可以很容易地来回传递/检索数据.许多其他开发人员认为这比使用数据库过多而且工作量大得多.
那么让这些系统相互通信的最佳方法是什么?
我们有相当多的代码只是跳转到Java 5.我们一直在那些针对Java 5版本发布的组件中使用泛型,但剩下的代码当然是充满原始的类型.我已经设置编译器为原始类型生成错误并开始手动清除它们,但是按照目前的速率,它需要很长时间才能完成它(大约有2500个错误).这是Eclipse的有用的Infer Generic Type快速修复,它总是摆脱错误,但经常生成需要进一步工作的代码.
有没有更好的方法来处理这个?有没有比Eclipse更好的自动化工具?有没有办法将重构应用于所有出现而不是一个一个地进行重构?或者你只是忽略警告?
有没有人有将FxCop引入遗留代码的经验?如果有人引入违反规则的代码,我们希望我们的构建失败.但就目前而言,这是不可能的,因为遗留代码有超过9000个违规行为.
抑制我所知错误的唯一方法是通过SuppressMessage属性,但这只适用于方法和GeneratedCodeAttribute.最后一个可以用于类和命名空间(如果我没记错的话),但不应该用于非生成的代码(参见这里).
现在,我们每天花一些时间来删除违规行为,但新的违规行为仍在继续,因为我们的构建不会失败.
有任何想法吗?
我试图在一些遗留代码中跟踪执行流程.我们正在访问一份报告
http://site.com/?nq=showreport&action=view
Run Code Online (Sandbox Code Playgroud)
这就是谜题:
index.php没有$_GET['nq']或$_GET['action'](也没有
$_REQUEST),index.php或其包含的任何来源,不包括showreport.php,.htaccess没有网址重写然而,showreport.php被执行.
我可以访问服务器上的cPanel(但没有apache配置文件),这是实时代码,我不能随意使用.
有什么可以让这种情况发生?我应该在哪里看?
更新
有趣的事情 - 在状态更新中向客户端发送此问题的链接以使他保持循环; 几分钟后,所有访问权被撤销,客户通知我项目被取消.我相信我已经采取了足够的谨慎措施,不要在代码实际存在的地方留下任何痕迹......
我感到宽慰,现在已经取消了我,但我也很想知道它是什么!
谢谢大家的时间和帮助.
调试遗留代码,我有一个奇怪的问题.遗留代码正在转移到PHP 7.2.我不知道它最初是为哪个版本的PHP编写的,但它确实可以在PHP 5.6中运行.
以下是我的问题示例......
$variable = '';
$variable['key'] = 'Hello World!';
echo $variable['key'] // H
Run Code Online (Sandbox Code Playgroud)
当我回显时$variable['key'],它只从值中获取第一个字符.我现在知道它是因为$variable最初声明为字符串.
但为什么这在PHP 5.6中有效?如果不拖曳数千行代码,我该怎么做才能在7.2中完成这项工作?
是否有strict_types我可以使用的指令?
我偶尔不幸有需要修改,很旧,差的 不是记录并不佳 不是设计的代码.
通常需要花费很长时间才能进行简单的更改,因为现有代码的结构并不多,而且我真的必须先阅读大量代码才能了解事情的发展方向.
我认为在这种情况下会有很多帮助的工具可以让人们可以看到代码的概述,然后甚至可以深入了解更多细节.我怀疑这样一个工具很难做对,因为它试图找到很少或没有的结构.
我想这不是一个真正的问题,而是一种沉思.我应该把它变成一个问题 - 其他人做了什么来帮助他们了解其他人的代码,好的和坏的?
我必须使用超过100k行代码对现有C++项目进行增强.
我的问题是如何以及从何处开始这些项目?
如果代码没有很好地记录,问题会进一步增加.是否有任何自动化工具可用于研究大型项目的代码流?
感谢名单,
我继承了一些可怕的遗留代码,其中包含大约1000行实用程序类定义,需要出现在源文件中的"真实"代码之前.为了避免与可能还有相关遗留类的其他模块发生冲突,我将实用程序类放入了一个未命名的命名空间:
namespace {
class OldUtils {
OldUtils();
int foo();
double bar();
};
OldUtils::OldUtils() {
// hundreds of lines
}
int OldUtils::foo() {
// hundreds more lines
}
...
}
class ActuallyInteresting {
// uses OldUtils
};
Run Code Online (Sandbox Code Playgroud)
但是我希望ActuallyInteresting人们将(实际上)感兴趣的代码靠近文件的顶部,例如从第50行开始,而不是在底部,例如从第1000行开始.将可怕的实用程序类拆分为单独的编译单位不是一个选项,出于更高层次的原因我不会进入!
所以我想知道是否有可能将短类声明 - 没有方法定义 - 放在文件顶部的未命名命名空间中,并在底部的另一个未命名的命名空间中放置更长的方法定义:
namespace {
class OldUtils {
OldUtils();
int foo();
double bar();
};
}
class ActuallyInteresting {
// uses OldUtils
};
namespace {
OldUtils::OldUtils() {
// hundreds of lines
}
int OldUtils::foo() {
// hundreds more lines
} …Run Code Online (Sandbox Code Playgroud) 我有一个大型(~15k LoC)JS 应用程序(即 NetSuite 应用程序),以旧式全全局方式编写。App由26个文件组成,它们之间的依赖关系完全不清楚。
目标是将应用程序优雅地重构为更小的模块。我所说的优雅是指不要长时间破坏\锁定应用程序,而是以较小的块进行重构,而在完成每个块后应用程序仍然可用。
我的一个想法是将我们现在拥有的所有 JS 文件连接到单文件包中。之后,一些代码可以提取到模块中。遗留代码可以开始导入它。模块和导入应该使用 webpack\whatever 进行转译,而遗留代码仍保持全全局样式。最后,所有这些都被打包到单个 JS 文件中并进行部署。
我的问题是
我尝试了 webpack,但没能从中得到我想要的东西。和不是选项export-loader,resolve-loader因为需要导入\导出的方法\变量数量。
例子
现在代码看起来像
function someGlobalFunction() {
...
}
var myVar = 'something';
// and other 15k lines in 26 files like this
Run Code Online (Sandbox Code Playgroud)
我理想中想要实现的是
function define(...) { /* function to define a module */ }
function require(moduleName) { /* function to import a module */ }
// block with my refactored out module definitions
define('module1', function () {
// extracted …Run Code Online (Sandbox Code Playgroud) legacy-code ×10
c++ ×3
legacy ×2
php ×2
apache ×1
debugging ×1
fxcop ×1
generics ×1
java ×1
javascript ×1
macros ×1
migration ×1
module ×1
namespaces ×1
php-5.6 ×1
php-7.2 ×1
projects ×1
refactoring ×1
templates ×1