Search code examples
javasonarlint

Reducing Cognitive complexity


How do I reduce cognitive complexity of the if statements in the while loop? This is a code for inserting a node to a threaded binary search tree. This is my logic for the operation but the ide is giving me these issues. How do I fix them?

Refactor this method to reduce its Cognitive Complexity from 18 to the 15 allowed. [+11 locations]

Reduce the total number of break and continue statements in this loop to use at most one. [+2 locations]

Here's the code

public class threaded {
    class Node{
        Node left;
        boolean lthread;
        int data;
        boolean rthread;
        Node right;

        Node(int data){
            left = null;
            lthread = true;
            this.data = data;
            rthread = true;
            right = null;
        }
    }

    Node root = null;

    void insert(int data){
        Node ptr = root;
        Node par = null;   // parent of the node to be inserted

        while (ptr != null){
            if (data == ptr.data){
                System.out.println("Duplicate key");
                return;
            }

            par = ptr;

            if (data < ptr.data){
                if (!ptr.lthread){
                    ptr = ptr.left;
                }
                else{
                    break;
                }
            }
            else {
                if (!ptr.rthread){
                    ptr = ptr.right;
                }
                else{
                    break;
                }
            }

            Node tmp = new Node(data);  // creating a new node

            if (root == null){
                root = new Node(data);
            }

            else if (data < par.data){
                tmp.left = par.left;
                tmp.right = par;
                par.lthread = false;
                par.left = tmp;
            }

            else if (data > par.data){
                tmp.left = par;
                tmp.right = par.right;
                par.rthread = false;
                par.right = tmp;
            }

        }

    }

Solution

  • Cognitive Complexity is a measure of how difficult your code is to understand. It is a subjective maintainability check that measures the amount of nesting, and flow breaks there are. It is not the same as cyclomatic complexity (which is forks of logic which require unique test cases to test that branch of code) but very much close cousins. There are still some more static analysis that goes into generating a cognitive complexity score.

    Rule of Thumb

    Think about how many test cases you need to write in order to test your piece of code.

    amount of looping, if/else, switches into their own methods

    if 
    else  // complexity 2 there can be two paths for this methods
    
    if
      if
      else
    else // complexity 4 there are four paths for this method
    

    Now... combine the two... you have a whopping 8 conditions to test all your code paths!

    When measuring the complexity of anything. Think about how many tests you need to write to test that method. You can reduce the cognitive complexity by deferring the complexity to smaller unit methods.

    Some comments on your insert implementation to help you on your journey

    void insert(int data){
        Node ptr = root;
        Node par = null;   // parent of the node to be inserted
    
        while (ptr != null){
            if (data == ptr.data){
                System.out.println("Duplicate key");
                return;
            }
    
            par = ptr;
    
            if (data < ptr.data){
                if (!ptr.lthread){ 
                    ptr = ptr.left;
                }
                else{ // Exit condition can you handle this in your loop conditional?
                    break;
                }
            }
            else {
                if (!ptr.rthread){
                    ptr = ptr.right;
                }
                else{ 
                    break;
                }
            }
    
            Node tmp = new Node(data);  // creating a new node
    
            if (root == null){
                root = new Node(data);
            }
    
            else if (data < par.data){ // Can you do this in a separate method? -- you might even be able to combine it with your conditions above.
                tmp.left = par.left;
                tmp.right = par;
                par.lthread = false;
                par.left = tmp;
            }
    
            else if (data > par.data){ // Can you do this in a separate method? append()? if you combine it with your conditional above -- you can go appendLeft(), appendRight()
                tmp.left = par;
                tmp.right = par.right;
                par.rthread = false;
                par.right = tmp;
            }
    
        }
    
    }
    

    Pseudo code it to figure out how you want to write the methods in your insert loop.