1

我们的团队已经获得了一个遗留系统,用于进一步的维护和开发。因为这是真正的“遗留”东西,所以测试的数量真的非常少,而且大部分都是废话。这是一个带有 Web 界面的应用程序,因此既有容器管理的组件,也有普通的 Java 类(不绑定到任何框架等),无论何时何地,它们都是“新版”的。

当我们使用这个系统时,每次我们接触给定的部分时,我们都会尝试将所有这些东西分解成更小的部分,发现和重构依赖关系,推送依赖而不是在代码中拉取它们。

我的问题是如何使用这样的系统,打破依赖,使代码更易测试等?何时停止以及如何处理?

让我给你看一个例子:

public class BillingSettingsAction {

    private TelSystemConfigurator configurator;
    private OperatorIdDao dao;

    public BillingSettingsAction(String zoneId) {
        configurator = TelSystemConfiguratorFactory.instance().getConfigurator(zoneId);
        dao = IdDaoFactory.getDao();
        ...
    }

    // methods using configurator and dao
}

这个构造函数肯定做的太多了。另外为了测试它以进一步重构它需要使用 PowerMock 等做魔术。我要做的是将其更改为:

public BillingSettingsAction(String zone, TelSystemConfigurator configurator, OperatorIdDao dao) {
    this.configurator = configurator;
    this.dao = dao;
    this.zone = zone;
}

或仅使用依赖项的设置器提供构造函数设置区域。

我看到的问题是,如果我在构造函数中提供依赖项,我仍然需要在某个地方提供它们。所以它只是将问题向上移动一个级别。我知道我可以创建工厂来连接所有依赖项,但是触摸应用程序的不同部分会导致每个工厂都有不同的工厂。我显然不能一次重构所有应用程序并在那里引入例如 Spring。

暴露设置器(可能提供了默认实现)是相似的,而且它就像只为测试添加代码。

所以我的问题是你如何处理这个问题?如何使对象之间的依赖关系更好、更易读、更可测试,而无需一次性完成?

4

2 回答 2

3

我最近才开始阅读 Michael Feathers 的“有效使用遗留代码”。这本书基本上是对您的问题的回答。它提供了非常可操作的“块”和技术,以逐步对遗留系统进行测试并逐步改进代码库。

导航可能有点混乱,因为本书通过指向特定技术来引用自己,几乎从第 1 页开始,但我发现到目前为止的内容非常有用。

我不隶属于作者或类似的东西,只是我面临类似的情况,发现这是一个非常有趣的资源。

高温高压

于 2012-04-16T21:29:45.587 回答
2

我会尝试建立一个类似于童子军规则的规则:当你触摸一个文件时,你必须对其进行一些改进,除了实现你想要实现的东西。

为了支持你可以

  • 同意这样的改进的固定时间预算,例如 2 小时的功能工作,我们允许 1 小时的清理。

  • 有可见的指标显示随时间的改进。通常像平均文件大小和测试覆盖率这样简单的事情就足够了

  • 列出您至少要针对较大的内容进行更改的内容列表,例如“摆脱 TelSystemConfiguratorFactory”跟踪您已经在工作的任务,并优先处理已经开始的事情而不是新事物。

无论如何,请确保管理层同意您的方法。

在更技术方面:您展示的方法很好。在许多情况下,我会考虑提供所有依赖项的第二个构造函数,但通过带有参数的新构造函数。弃用额外的构造函数。当您接触该类的客户时,请让他们使用新的构造函数。

如果您要使用 Spring(或其他一些 DI 框架),您可以首先通过从 Spring 上下文中获取实例作为中间步骤替换对静态工厂的调用,然后再通过 spring 实际创建它并注入所有依赖项。

于 2012-04-16T19:27:05.307 回答