重构此方法以将其认知复杂度从 21 降低到允许的 15.如何重构和降低复杂度 [英] Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed. How to refactor and reduce the complexity

查看:131
本文介绍了重构此方法以将其认知复杂度从 21 降低到允许的 15.如何重构和降低复杂度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何降低给定代码的复杂度?我在 Sonarqube 中收到此错误--->重构此方法以将其认知复杂度从 21 降低到允许的 15.

how to reduce the complexity of the given piece of code? I am getting this error in Sonarqube---> Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

this.deviceDetails = this.data && {...this.data.deviceInfo} || {};
    if (this.data && this.data.deviceInfo) {
      this.getSessionInfo();
      // tslint:disable-next-line: no-shadowed-variable
      const { device, driver, ipAddress, port, active, connectionType } = this.data.deviceInfo;
      this.deviceDetails = {
        name: device.name || '',
        manufacturer: device.manufacturer || '',
        deviceType: device.deviceType || '',
        model: device.model || '',
        description: device.description || '',
        managerId: device.deviceManager && device.deviceManager.managerId || null,
        locationId: device.location && device.location.locationId || null,
        active: device.active,
        connectionType: connectionType || null,
        driver_id: driver && driver.driverId || null,
        ipAddress: ipAddress || '',
        port: String(port) || '',
        connectionStatus: active,
      };
      this.oldDeviceDetails = {...this.deviceDetails};
      this.deviceLocation = device.location && device.location.locationId || null;
    } else {

推荐答案

关于认知复杂性如何工作以及为什么要保持低水平的一些信息

首先,重要的是要了解认知复杂性"是如何产生的.与Cyclomatic Complexity"相比更有效.认知复杂性考虑了人脑感知的复杂性.这就是为什么它不简单地表示条件路径的数量(简化了条件的数量加 1 用于 return 语句).

First of all it is important to understand how "Cognitive Complexity" works as compared to "Cyclomatic Complexity". Cognitive complexity takes into account the complexity perceived by the human brain. This is why it does not simply indicate the number of conditional paths (simplified the number of conditionals plus 1 for the return statement).

认知复杂度指标还考虑嵌套条件(例如 if 中的 if,if 语句中的 if),这使得阅读和理解来自人类的视角.

The cognitive complexity metric also considers nested conditions (e.g. an if inside an if, inside an if statement) which makes it even harder to read and understand the code from a human's perspective.

SonarQube 文档中的以下示例 (https://www.sonarsource.com/docs/CognitiveComplexity.pdf) 概述了我要解释的内容:

The following sample from the SonarQube documentation (https://www.sonarsource.com/docs/CognitiveComplexity.pdf) outlines what I'm trying to explain:

if (someVariableX > 3) { // +1
    if (someVariableY < 3) { // +2, nesting = 1
        if (someVariableZ === 8) { // +3, nesting = 2
            someResult = someVariableX + someVariableY - someVariableZ;
        }
    }
}

因此请注意,二元运算会增加复杂性,但嵌套条件甚至会为每个嵌套条件加 1 分.这里认知复杂度为 6,而圈复杂度仅为 4(每个条件一个,返回路径一个);

So be aware that binary operations add to the complexity but nested conditions even add a score of plus 1 for each nested condition. Here the cognitive complexity would be 6, while the cyclomatic complexity would only be 4 (one for each conditional and one for the return path);

如果您使您的代码对人类来说更具可读性,例如通过从包含条件的行中提取方法,您可以获得更好的可读性和更低的复杂性.

If you make your code more readable for a human, e.g. by extracting methods from lines that contain conditionals you achieve both, better readability and less complexity.

虽然您提供的代码没有嵌套条件,但我认为首先了解圈和认知复杂度计算的工作原理以及为什么将其保持在较低水平是一个好主意很重要.

Although the code you provided does not have nested conditionals I think it is important to first understand how cyclomatic and cognitive complexity calculation works and why it is a good idea to keep it low.

[TL;DR] 一种可能的方法来将您的代码重构为一个不太复杂且可读性更好的版本

让我们首先看看注释中概述的代码的复杂性计算是如何完成的:

Let's first look how the complexity calcuation is done for your code as outlined by the comments:

this.deviceDetails = this.data && {  ...this.data.deviceInfo } || {}; // +2
if (this.data && this.data.deviceInfo) { // +1 for the if condition, +1 for the binary operator
    this.getSessionInfo();

    const { device, driver, ipAddress, port, active, connectionType } =             
    this.data.deviceInfo;
    this.deviceDetails = {
        name: device.name || '', // +1 for the binary operator
        manufacturer: device.manufacturer || '', // +1 for the binary operator
        deviceType: device.deviceType || '', // +1 for the binary operator
        model: device.model || '', // +1 for the binary operator
        description: device.description || '', // +1 for the binary operator
        managerId: device.deviceManager && device.deviceManager.managerId || null, // +2 for the varying binary operators
        locationId: device.location && device.location.locationId || null, // +2 for the varying binary operator
        active: device.active,
        connectionType: connectionType || null, // +1 for the binary operator
        driver_id: driver && driver.driverId || null, // +2 for the varying binary operator
        ipAddress: ipAddress || '', // +1 for the binary operator
        port: String(port) || '', // +1 for the binary operator
        connectionStatus: active,
    };
    this.oldDeviceDetails = { ...this.deviceDetails };
    this.deviceLocation = device.location && device.location.locationId || null; // +2 for the varying binary operator
} else { // +1 for the else path 
    // some statement
}

所以假设我的数学是正确的,这总结为 SonarQube 报告的 21 的认知复杂度.

So assuming my math is correct, this sums up to the cognitive complexity of 21 as reported by SonarQube.

以下代码示例展示了如何将您的代码重构为应该将认知复杂度降低到 12 的版本.(请注意,这只是手动计算.)

The following code sample shows how your code can be refactored to a version which should lower the cognitive complexity down to 12. (Please be aware that this is just a manual calculation.)

这可以通过应用 简单的重构 来完成,例如 extract 方法 和/或 move 方法(另见 Martin Fowler,https://refactoring.com/catalog/extractFunction.html).

It can be done by applying simple refactorings such as extract method and/or move method (see also Martin Fowler, https://refactoring.com/catalog/extractFunction.html).

this.deviceDetails = this.data && { ...this.data.deviceInfo } || {}; // +2
if (deviceInfoAvailable()) { // +1 for the if statement
    this.getSessionInfo();
    // tslint:disable-next-line: no-shadowed-variable
    const { device, driver, ipAddress, port, active, connectionType } = this.data.deviceInfo;
    this.deviceDetails = {
        name: getInfoItem(device.name), 
        manufacturer: getInfoItem(device.manufacturer),
        deviceType: getInfoItem(device.deviceType),
        model: getInfoItem(device.model),
        description: getInfoItem(device.description), 
        managerId: getManagerId(device),
        locationId: getDeviceLocation(device),
        active: device.active,
        connectionType: getInfoItem(connectionType), 
        driver_id: getDriverId(driver), 
        ipAddress: getInfoItem(ipAddress), 
        port: getInfoItem(port), 
        connectionStatus: active,
    };
    this.oldDeviceDetails = { ...this.deviceDetails };
    this.deviceLocation = getDeviceLocation(device);
} else { // +1 for the else
    // some statement
}

function getDriverId(driver) {
    return driver && driver.driverId || null; // +2 for the binary operators
}

function getDeviceLocation(device) {
    return device.location && device.location.locationId || null; // +2 for the binary operators
}

function getManagerId(device) {
    return device.deviceManager && device.deviceManager.managerId || null; // +2 for the binary operators
}

function deviceInfoAvailable() {
    return this.data && this.data.deviceInfo; // +1 for the binary operator
}

function getInfoItem(infoItem) {
    return infoItem || ''; // +1 for the binary operator
}

通过简单的提取方法重构大量重复(参见 getInfoItem() 函数)被消除以及 这使得降低复杂性和增加复杂性变得容易可读性.

With the simple extract method refactorings lots of duplications (see getInfoItem() function) got eliminated as well which makes it easy to reduce the complexity and increase the readability.

老实说,我什至会更进一步,对代码进行更多重构,以便在提供设备详细信息时检查空项目和设置默认值(此处为空字符串)的逻辑由设备完成类或设备详细信息类本身,以更好地凝聚数据和对该数据进行操作的逻辑.但由于我不知道其余的代码,这个初始重构应该会让你更进一步,以提高可读性和降低复杂性.

To be honest, I would even go some steps further and restructure your code even more so that the logic for checking for empty items and setting a default value (here an empty string) when providing the device details is done by the device class or a device details class itself to have better cohesion of the data and the logic that operates on that data. But as I don't know the rest of the code this inital refactoring should get you one step further to better readability and less complexity.

这篇关于重构此方法以将其认知复杂度从 21 降低到允许的 15.如何重构和降低复杂度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆