【问题标题】:Log statements prevent refactoring: how to help this?日志语句阻止重构:如何解决这个问题?
【发布时间】:2011-03-22 04:58:15
【问题描述】:

我想重构一些相对较大的遗留方法。它符合 Michael Feathers 的“有效地使用旧代码”中指定的“项目符号方法”类型,因此可以以相当直接的方式将其拆分为多个顺序方法。但是它的每个连续步骤都会输出一些日志消息,并且形成该消息需要比步骤本身更多的数据。所以当我尝试提取方法时,我最终得到的方法有 6 个参数。如果我删除了这些日志语句,我将拥有只有 1 个参数的方法。所以我实际上无法重构任何东西。而且我不能只删除日志语句。

方法的一部分是这样的:

// much of code before
Device device = getDevice(deviceID);
boolean isFirstRegistration = false;

if (device == null) {
    /*logger.trace(
            "DeviceId", deviceID,
            "ADM", adminCode,
            "Phone", clientData.getPhone()
    );
    logger.info("First registration of the device. Device ID - " + deviceID);*/
    isFirstRegistration = true;
} else {
    /*logger.trace(
            "DeviceId", deviceID,
            "ADM", adminCode,
            "Phone", clientData.getPhone()
    );
    logger.info("Device ID - " + deviceID
            + " has been previously registered by adminCode: "
            + device.getAdminCode());*/
}
// much of code after

如您所见,注释掉了日志语句。在这种情况下,我可以提取方法boolean isFirstRegistration(String deviceId)。但是当它们未注释时,签名会膨胀到boolean isFirstRegistration(String deviceId, String adminCode, ClientData clientData)。这不是最极端的情况,只是第一眼看到的情况。你有什么想法我应该如何重构这种方法?

【问题讨论】:

  • 我们可以看看吗?您可以让日志辅助方法获取额外数据,并返回一个字符串/对象,然后将其传递给您的方法进行日志记录。或者将登录所需的所有项目放入单个数组或哈希中并将其传入。
  • 你想通过重构来完成什么?
  • 我会尝试编写类似于该方法的部分的sn-p。
  • @Peter Ruderman:测试它并引入新功能,而不是进一步破坏代码库。

标签: logging refactoring legacy


【解决方案1】:

芽类。将日志记录移交给帮助程序类,并在需要时为其提供所需的所有数据。

更新:使用提供的示例变量,我会在设备填充后立即调用myLogger.setDevice(device); adminCode、clientData 等类似。提供像traceDeviceAdminCodeAndPhone()logFirstRegistration() 这样的记录器日志方法,它使用自己的实例变量。在变量发生变化的任何地方,将它们再次提供给记录器。现在,将记录器传递给您正在提取的方法,以及新方法直接需要的任何参数(但仅此而已),您的记录器仍然可以从提取的方法中报告它需要什么。

另外,如果您的记录器开始看起来与您的方法过于亲密,另一种方法是将方法提取到一个新类中并将一些局部变量转换为实例变量;然后记录器可以简单地向新类询问值,而不是自己保留它们。但是作为助手的 logger 类可能是一个更小、影响更小的重构。这是好是坏取决于你想去哪里。

【讨论】:

  • 确实如此。谢谢你。
【解决方案2】:

Carl 的回答当然是正确的,但我认为至少还有另一个不错的选择。

一些日志框架支持所谓的Mapped Diagnostic Context。您可以在其中存储键值对,然后框架可以按照您在其配置文件中指定的格式将它们添加到日志行中。正如您似乎通常记录相同的数据(至少在跟踪中),我认为它非常适合您的需求。

支持它的一些框架是 Log4J、SLF4J,但我想类似的东西也应该存在于“非 Java”世界中。

我认为您至少可以将它用于/代替跟踪消息,并且会收获很多:

  • 更少,更简洁的代码
  • 无需传递仅记录所需的参数
  • 统一记录的消息(由框架根据您提供的模式格式化)
  • 更灵活 - 记录的内容/时间/方式在记录配置(它所属的位置)中进行控制。

需要注意的一点:键/值对通常存储在线程局部变量中,这会导致一些可能的陷阱:

  • 如果你经常切换线程,它可能不太好/不好用
  • 通常清理(删除不需要的值)是您的任务,框架不会自动完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 1970-01-01
    • 1970-01-01
    • 2022-12-07
    • 2014-10-07
    • 1970-01-01
    相关资源
    最近更新 更多