Design Patterns and Cyclomatric Complexity



What is Cyclomatic Complexity?

Cyclomatic complexity is a software metric used to measure the complexity of a program. These metric, measures independent paths through program source code. Independent path is defined as a path  that has atleast one edge which has  not been traversed before in any other paths. Cyclomatic complexity can be calculated with respect to functions, modules, methods or classes within a program.
In the graph, Nodes represent processing tasks while edges represent control flow between the nodes.
Below  are Flow diagrams for statements like if-else, While, until and normal sequence of flow.



Mathematical representation:
Mathematically, it is set of independent paths through the graph diagram. The complexity of the program can be defined as –
V(G) = E – N + 2
Where,
E – Number of edges
N – Number of Nodes
V (G) = P + 1
Where P = Number of predicate nodes (node that contains condition)
Simple Example:
Below is a simple program as an example:
    IF A = 354
    THEN IF B > C
THEN A = B
ELSEA= C
ENDIF
ENDIF
Print A

The control flow shows seven nodes (shapes) and eight edges (lines), thus using the formal formula the cyclomatic complexity is 8-7 + 2 = 3. In this case there is no graph called or subroutine. Alternatively one may calculate the cyclomatic complexity using the decision points rule. Since there are two decision points, the cyclomatic complexity is 2 + 1 = 3.





Second Example
01.i = 0;
02. 
03.n=4; //N-Number of nodes present in the graph
04. 
05.while (i<n-1) do
06. 
07.j = i + 1;
08. 
09.while (j<n) do
10. 
11.if A[i]<A[j] then
12. 
13.swap(A[i], A[j]);
14. 
15.end do;
16. 
17.i=i+1;
18. 
19.end do;
Flow graph for this program will be

Computing mathematically,
  • V(G) = 9 – 7 + 2 = 4
  • V(G) = 3 + 1 = 4 (Condition nodes are 1,2 and 3 nodes)
  • Basis Set – A set of possible execution path of a program
  • 1, 7
  • 1, 2, 6, 1, 7
  • 1, 2, 3, 4, 5, 2, 6, 1, 7
  • 1, 2, 3, 5, 2, 6, 1, 7

Complexity Number V(G)
Meaning
1-10
Structured and well written code
High Testability
Cost and Effort is less
10-20
Complex Code
Medium Testability
Cost and effort is Medium
20-40
Very complex Code
Low Testability
Cost and Effort are high
>40
Not at all testable
Very high Cost and Effort

Tools for Cyclomatic Complexity calculation:

Examples of tools are
  • OCLint – Static code analyzer for C and Related Languages
  • devMetrics – Analyzing metrics for C# projects
  • Reflector Add In – Code metrics for .NET assemblies
  • GMetrics – Find metrics in Java related applications
  • NDepends – Metrics in C# and Java applications

Design patterns and their impact on cyclomatic complexity

A design pattern describes a solution to a recurring software engineering problem at the design level. Design patterns aim to promote reusability of successful designs and architectures.
Table 1 lists the design patterns with the two classifications mentioned above.
Pattern
Classification on Purpose
Classification on Intent
Abstract Factory
Creational
Construction
Builder
Creational
Construction
Factory Method
Creational
Construction
Prototype
Creational
Construction
Singleton
Creational
Responsibility
Adapter
Structural
Interface
Bridge
Structural
Interface
Composite
Structural
Interface
Decorator
Structural
Extension
Façade
Structural
Interface
Flyweight
Structural
Responsibility
Proxy
Structural
Responsibility
Chain of Responsibility
Behavioural
Responsibility
Command
Behavioural
Operation
Interpreter
Behavioural
Operation
Iterator
Behavioural
Extension
Mediator
Behavioural
Responsibility
Memento
Behavioural
Construction
Observer
Behavioural
Responsibility
State
Behavioural
Operation
Strategy
Behavioural
Operation
Template Method
Behavioural
Operation
Visitor
Behavioural
Extension

Although design patterns focus on reusability and extensibility, most design patterns, particularly behavioural patterns, can assist in the reduction of cyclomatic complexity. This is accomplished by organising participants such that each solves a part of the problem resulting in simpler control flows within each participant hence lowering their cyclomatic complexity.

Chain of Responsibility:
For Example, A calculator could be implemented in single method (say, Calculate(double FirstValue, double SecondValue, string Operator) like this:
Code A:
        switch(operator){ 
        case '+': 
          result = operand1 + operand2; 
          break; 
        case '-': 
          result = operand1 - operand2; 
          break; 
        case '*': 
          result = operand1 * operand2; 
          break; 
        case '/': 
          if (Math.abs(operand2) > 0.0){ 
            result = operand1 / operand2; 
          } else { 
            throw new ArithmeticException( 
               "Numerator is zero."); 
          } 
          break;  
        default: 
          throw new IllegalArgumentException( 
             operator + " unknown."); 
        } 
        return result; 
This code could be refectored into a chain of Responsibitlity, as show below:
Chain of Responsibility consists of a chain of loosely coupled objects with responsibilities between objects kept specific and minimal. These include knowing the task they can perform and the next object in the chain to which a message can be propagated if they cannot process the message. Client objects need not know which object in the chain has to be sent a message to perform a particular task. Instead, clients only know of the object at the head of the chain and they send the message to it. That object processes the message if it can otherwise it passes it on to the next object in the chain.
Code B:
Processor Class:
public abstract class Processor {
      protected Processor successor;  
      public Processor(){  
        successor = null;  
      }  
 
      public void setSuccessor(Processor successor){  
        this.successor = successor;  
      }  
 
      protected abstract boolean canProcess(char operator);  
      protected abstract double process(double operand1, double operand2);  
      public double calculate(double operand1,double operand2, char operator)  
      {  
        double result;  
        if (canProcess(operator))
          result = process(operand1, operand2);  
        else 
        {
          if (null != successor)
            result = successor.calculate(operand1, operand2, operator);  
          else
            throw new Exception("No successor set");  
        }
        return result;  
      }  
    }

Inherited Adder , Subtractor, Multiplier and Divider classes .
public class Adder : Processor 
{  
      protected boolean canProcess(char operator) 
      {  
        return operator == '+';  
      }  
      
      protected double process(double operand1,double operand2) 
      {  
        return operand1 + operand2;  
      }  
}  
 
public class Subtractor : Processor 
{  
      protected boolean canProcess(char operator) 
      {  
        return operator == '-';  
      }  
      protected double process(double operand1,double operand2) 
      {  
        return operand1 - operand2;  
      }  
    } 
 
public class Multiplier : Processor 
{  
      protected boolean canProcess(char operator) 
      {  
        return operator == '*';  
      }  
      
      protected double process(double operand1,double operand2) 
      {  
        return operand1 * operand2;  
      }  
}  
    
public class Divider : Processor 
{  
      protected boolean canProcess(char operator) 
      {  
        return operator == '/';  
      }  
      
      protected double process(double operand1, double operand2) 
      {  
        double result;  
        if (Math.abs(operand2) > 0.0)  
          result = operand1/operand2;  
        else   
          throw new ArithmeticException("Divide by zero.");  
          
        return result;  
      }  
}

Here is Calculator Class.
public class Calculator 
{  
      private Processor processor;  
      public Calculator()
      {  
        processor = null;  
      }  
 
      public void setProcessor(Processor processor)
      {  
        this.processor = processor;  
      }  
 
public double calculate(double operand1,double operand2,char operator)                 {  
        return processor.calculate(operand1,operand2, operator);  
      } 
}

In addition to Chain of Responsibility, Processor and its subclasses also implement the Template Method pattern. calculate method is a concrete method in the Processor base class. However, both canProcess and process methods are abstract methods, specialised implementations of which exist in the subclasses of Processor.
The code “Code B” results in more classes than the code in “Code A” but these classes are more cohesive and have lower individual cyclomatic complexities. The cyclomatic complexities of all methods of Adder, Subtractor and Multiplier classes are 1 whereas that of the process method of the Divider class is 2. The cyclomatic complexities of all instance methods of the Calculator class are also 1. The main method of the Calculator class and the calculate method of the Processor class have the highest cyclomatic complexities of 3.

Strategy Desing Pattern:
The Strategy pattern allows the definition of a family of algorithms such that they are interchangeable within an application. Thus it lets algorithms vary independently from the clients that use it. Strategy is typically used to configure a class with one of many behaviours, when different variants of an algorithm are needed or when a class defines may behaviours and these appear as multiple conditional statements in its operations
Folllowing is the class diagram of the calculator application implemented using a variation of the Strategy pattern. The Processor interface represents the abstract strategy in the application:





public interface Processor 
{  
        public double process(double operand1,double operand2);  
}  
 
public class Adder : Processor 
{  
     public double process(double operand1,double operand2) 
     {  
        return operand1 + operand2;  
     }  
}  
 
public class Subtractor: Processor 
{  
     public double process(double operand1,double operand2) 
     {  
        return operand1 - operand2;  
     }  
}  
 
public class Multiplier : Processor 
{  
     public double process(double operand1,double operand2) 
     {  
        return operand1 * operand2;  
     }  
}  
 
public class Divider : Processor 
{  
     public double process(double operand1,double operand2) 
     {  
        double result;  
        if (Math.abs(operand2) > 0.0)  
          result = operand1/operand2;  
         else   
          throw new ArithmeticException("Divide by zero");  
 
        return result;  
     }  
}  
 
Adder, Subtractor, Multiplier and Divider classes (above) contain only one method, process. For Adder, Subtractor and Multiplier, this method has a cyclomatic complexity of 1 whereas for the Divider, it has a cyclomatic complexity of 2.
 
Calculate the Cyclomatric Complexity V(G) for the following:

Comments

Popular posts from this blog

Data Bound Controls in ASP.Net - Part 4 (FormView and DetailsView controls)

ASP.net: HttpHandlers

The Clickjacking attack and X-Frame-Options