寻求重新设计界面的建议

时间:2010-06-03 14:58:31

标签: c++ unit-testing refactoring interface legacy-code

作为维护大量遗留代码的一部分,我们需要更改部分设计,以使其更易于测试(单元测试)。我们需要解决的问题之一是组件之间的现有接口。两个组件之间的接口是仅包含静态方法的类。

简化示例:

class ABInterface {

    static methodA();
    static methodB();
    ...
    static methodZ();
};

接口由组件A使用,以便不同的方法可以使用ABInterface :: methodA()来准备一些输入数据,然后在组件B中调用适当的函数。

现在我们正在尝试重新设计此界面,原因有多种:

  • 扩展我们的单元测试覆盖率 - 我们需要解决组件之间的这种依赖关系,并且要引入存根/模拟

  • 这些组件之间的接口与原始设计不同(即,在此接口类之外创建了许多用于组件间i / f的新功能)。

  • 代码陈旧,随着时间的推移发生了很大的变化,需要重构。

此更改不应对系统的其他部分造成破坏。我们尝试限制在生产代码中留下许多需要测试的工件。性能非常重要,重新设计后应该没有(或非常小)降级。代码是C ++中的OO。

我正在寻找一些想法采取什么方法。有关如何有效地做到这一点的任何建议?

3 个答案:

答案 0 :(得分:1)

最简单的答案是将具有静态接口的旧库包装在外观中,然后重构代码以调用新的外观而不是旧的库。这个新的楔形应允许替换库以进行单元测试。首先在一个方法上测试它,看看如何实现它。

当一个问题被“表现问题”所污染时,真正困扰我的是什么。我们都编写了性能关键代码,没有人刻意建议编写性能不佳的代码。我发现这些“顾虑”通常来自诋毁每一个变化的反对者,并且真的不知道为什么某个变化会或不会表现良好。请记住,唯一有效的性能证明来自测试。运行性能测试并建立基线。进行更改。在新代码中再次运行性能测试。展示实际影响。只有这样,您才能决定变更的实际影响。你应该从不允许超过周期的狡辩来支配你的设计,直到证明不是这样。

听起来你的项目中有一个重要的是一位老C程序员*很久以前就听到过一些咆哮声说“让C ++快速运行的唯一方法就是使用静态方法”。问题是他仍然相信它。 20年前,大声喧哗可能是正确的,但编制者和优化者在这20年中已经有了很大的改进。所以试试你的改变。

如果您使用的是现代编译器,优化器无论如何都会删除目标代码中的额外解引用,这很有可能,这意味着您根本不会添加任何运行时影响。

如果性能至关重要但您没有性能测试,或者您没有使用现代编译器,或者您没有调整所有发布 - 构建优化(使用Profile Guided Optimization,例如,那么你有更大的工程问题,在担心额外的抽象层的性能之前,你需要花很长时间。

  • 注意:我也是一位老C程序员,过去常常说过像20年前那样的蠢事。不同之处在于我已经了解到一些优化比其他优化更为重要,并且新编译器非常善于自己解决大多数问题。我过早地“优化”事物的尝试通常以昂贵的维护代码结束,通常不会超过库存编译器设置。

答案 1 :(得分:0)

如果methodsA-Z是非静态和虚拟的,你可以轻松地做到这一点,对吗?因此,如果静态方法A-Z调用非静态虚拟方法A-Z,您将能够覆盖行为。知道了这一点,然后需要一种方法来更改包含非静态版本的实例进行测试。

或者,您可以使用要重构的两个类,并使它们使用此静态类的包装器。然后两者可以根据需要发散。

这是关于我所有的想法,而没有看到真正的问题。

答案 2 :(得分:0)

感谢您的回答和评论。

在审阅了Working Effectively with Legacy Code一书中的“依赖性依赖技术”一章之后,以下两种技术的组合实际上似乎是我们问题的解决方案:

  • Instance Delegator - 使用新的虚拟方法从实用程序类中包装/替换静态方法。
  • 静态Setter - 启用不同实用程序类(生产代码或存根代码)的实例化。

将这两者结合起来可以使我们将被测组件与其余产品代码分离。

我们现在唯一关注的是性能损失(由于使用了虚函数)。