Reducing Cyclomatic Complexity Using Delegates

In the previous post we looked at what Cyclomatic Complexity is and why it is important to write programs with low Cyclomatic Complexity. Here I would like to show an example of reducing Cyclomatic Complexity with the use of Delegates.

This post is going to be extremely code intensive so buckle up guys!

Let’s start.

Say we have a few Math functions as below:


private static void Add(int x, int y)
{

}

private static void Subtract(int x, int y)
{

}

private static void Divide(int x, int y)
{

}

private static void Multiply(int x, int y)
{

}

And based on our user’s input, we would like to make proper requests to these methods:


private void Execute()
{
Console.WriteLine("Basic Math Operations");

Console.WriteLine("Enter value 1: ");
var x = Console.ReadLine();

Console.WriteLine("Enter value 2: ");
var y = Console.ReadLine();

Console.WriteLine("Enter operation type: ");
Console.WriteLine("Type A for Add, S for Subtract, D for Divide, M for multiply");

var operationRequested = Console.ReadLine();

if (operationRequested != null)
{
switch (operationRequested.ToUpper())
{
case "A":

break;
case "S":

break;
case "D":

break;
case "M":

break;
}
}
}

This “Execute” function already has Cyclomatic Complexity of 6 because of the 4 switch statements and 1 if condition.

Let’s add some more complexities to this code now.

First to check whether user inputs are proper data type of integer or not I have introduced validation “IsNumeric” which gets executed once.

I have also introduced another validation to check whether user is authorized to make a request or not with “IsUserAuthorized“. This has to be called for each switch case scenario.

So, our code looks like this:


private static void Execute()
{
Console.WriteLine("Basic Math Operations");

Console.WriteLine("Enter value 1: ");
var x = Console.ReadLine();

Console.WriteLine("Enter value 2: ");
var y = Console.ReadLine();

if (!IsNumeric(x) || !IsNumeric(y))
{
Console.WriteLine("Error!! Please enter integer values");
Execute();
}

Console.WriteLine("Enter operation type: ");
Console.WriteLine("Type A for Add, S for Subtract, D for Divide, M for multiply");

var operationRequested = Console.ReadLine();

if (operationRequested != null)
{
switch (operationRequested.ToUpper())
{
case "A":
if (IsUserAuthorized("A"))
{
Add(Convert.ToInt32(x), Convert.ToInt32(y));
}
else
{
Console.WriteLine("User not authorized");
}
break;
case "S":
if (IsUserAuthorized("S"))
{
Add(Convert.ToInt32(x), Convert.ToInt32(y));
}
else
{
Console.WriteLine("User not authorized");
}
break;
case "D":
if (IsUserAuthorized("D"))
{
Add(Convert.ToInt32(x), Convert.ToInt32(y));
}
else
{
Console.WriteLine("User not authorized");
}
break;
case "M":
if (IsUserAuthorized("M"))
{
Add(Convert.ToInt32(x), Convert.ToInt32(y));
}
else
{
Console.WriteLine("User not authorized");
}
break;
}
}
}

These additions have increased the Cyclomatic Complexity level for our code to 12! If we had more switch statements, the complexity would have grown much more higher.

Let’s try to bring down the complexity with the use of Delegates now.

As per MSDN,

“A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.”

Basically, a delegate allows us to pass a method as a parameter to another function which is very useful as we can see below:

Since all of our math functions have same signature, we can create a delegate for them like this:


private delegate void HandleRequest(int x, int y);

Next, let’s add a generic request handler function:


private static void CallRequestHandler(HandleRequest request, string requestType, int x, int y)
{
if (IsUserAuthorized(requestType))
{
request(x, y);
}
else
{
Console.WriteLine("User not authorized");
}
}

The “CallRequestHandler” takes a delegate and request type along with “x” and “y” values as parameters for executing the user requests.

Now all we need to do is use this function in our switch statements by passing proper Math functions as parameters:


switch (operationRequested.ToUpper())
{
case "A":
CallRequestHandler(Add, operationRequested.ToUpper(), Convert.ToInt32(x), Convert.ToInt32(y));
break;
case "S":
CallRequestHandler(Subtract, operationRequested.ToUpper(), Convert.ToInt32(x), Convert.ToInt32(y));
break;
case "D":
CallRequestHandler(Divide, operationRequested.ToUpper(), Convert.ToInt32(x), Convert.ToInt32(y));
break;
case "M":
CallRequestHandler(Multiply, operationRequested.ToUpper(), Convert.ToInt32(x), Convert.ToInt32(y));
break;
}

This drops down the Cyclomatic Complexity of the Execute function to 8 from 12.

Benefit? We are left with much cleaner and easily testable code!

Alright. That’s about it for this post. I hope you guys found it useful and hope to see you incorporate this kind of practice on your coding.

Please pass the comments/feedback/queries as comments below.

Thanks!

Tags: