how could I reduce the cyclomatic complexity?

后端 未结 5 2164
感情败类
感情败类 2021-01-04 01:48

Whenever I lint a piece of code I\'m working on I get the This function\'s cyclomatic complexity is too high. (7). But I\'m a bit confused on how I could rewrit

5条回答
  •  花落未央
    2021-01-04 02:10

    Firstly, there are three results your function can have: do nothing, call this.close() or call this.open(). So ideally the resulting function will just have one if statement which determines which result is used.

    The next step is to extract all boolean code into variables. Eg var leftPastCenter = this.content.getBoundingClientRect().left > viewport / 2.

    Finally, use boolean logic to simplify it step by step.

    Here is how I did it:

    Firstly, extract all boolean variables:

    function () {
        var duration = +new Date() - start.time,
          isPastHalf = Number(duration) < 250 && Math.abs(delta.x) > 20 || Math.abs(delta.x) > viewport / 2,
          direction = delta.x < 0,
          leftPastCenter = this.content.getBoundingClientRect().left > viewport / 2,
          positiveDelta = this.isEmpty(delta) || delta.x > 0,
          isPulled = pulled === true; // I'll assume the test is needed rather than just using pulled.
    
        if (!isScrolling) {
            if (isPastHalf) {
                if (direction) {
                    this.close();
                } else {
                    if (leftPastCenter && isPulled) {
                        this.close();
                        return;
                    }
                    this.open();
                }
            } else {
                if (leftPastCenter) {
                    if (positiveDelta) {
                        this.close();
                        return;
                    }
                    this.open();
                    return;
                }
                this.close();
            }
        }
    }
    

    The easiest part to pull out is realizing if isScrolling is true, nothing ever happens. This immediately gets rid of one level of nesting:

        // above same
        if (isScrolling) { return; }
    
        if (isPastHalf) {
            if (direction) {
                this.close();
            } else {
                if (leftPastCenter && isPulled) {
                    this.close();
                    return;
                }
                this.open();
            }
        } else {
            if (leftPastCenter) {
                if (positiveDelta) {
                    this.close();
                    return;
                }
                this.open();
                return;
            }
            this.close();
        }
    }
    

    Now look at the cases this.open() are called. If isPastHalf is true, this.open() is only called when !direction and !(leftPastCenter && isPulled). If isPastHalf is false, then this.open() is only called when leftPastCenter and !positiveDelta:

        // above same
        if (isScrolling) { return; }
    
        if (isPastHalf) {
            if (!direction && !(leftPastCenter && isPulled)) {
                this.open();
            } else {
                this.close();
            }
        } else {
            if (leftPastCenter && !positiveDelta) {
                this.open();
            } else {
                this.close();
            }
        }
    

    Flipping the ifs (so this.close() comes first), makes the code a bit neater, and gives my final version:

        function () {
    
        var duration = +new Date() - start.time,
          isPastHalf = Number(duration) < 250 && Math.abs(delta.x) > 20 || Math.abs(delta.x) > viewport / 2,
          direction = delta.x < 0,
          leftPastCenter = this.content.getBoundingClientRect().left > viewport / 2,
          positiveDelta = this.isEmpty(delta) || delta.x > 0,
          isPulled = pulled === true; // I'll assume the test is needed rather than just using pulled.
    
        if (isScrolling) { return; }
    
        if (isPastHalf) {
            if (direction || (leftPastCenter && isPulled)) {
                this.close();
            } else {
                this.open();
            }
        } else {
            if (!leftPastCenter || positiveDelta) {
                this.close();
            } else {
                this.open();
            }
        }
    }
    

    It is difficult for me to do more, without knowing your codebase. One thing to note is direction and my new variable positiveDelta are nearly identical - you could possible remove positiveDelta and just use direction. Also, direction isn't a good name for a boolean, something like movingLeft would be better.

提交回复
热议问题