Cyclomatic what now?

 There are plenty of articles, blogs and forum posts related to Cyclomatic Complexity (CC) – usually covering an explanation of what CC actually is, how and why it is valuable, the methods for calculating CC, and some guidance on how to decrease complexity of code. Albeit, from what I have seen, this is usually language agnostic, and/or using fairly simplistic examples.

So, why do I feel the need to add yet another hit to search results to the perpetually increasing glut of information available on the internet? Why not? Don’t we all deserve the chance to add our “me too!” voices to the ether?

Well, um, no. Not really.

My intent here is to provide practical guidance on managing CC within C#, using real world examples from past projects that I have worked on (sanitized to protect IP, of course). This includes being able to recognize when you should, or shouldn’t, refactor code to reduce complexity, and how to do it.

A brief summary

You may be asking yourself, “What is Cyclomatic Complexity, and why do I care?” Ignoring the fact that you are talking to yourself in front of a computer screen, let me try and answer that question as simply as possible without making anything more confusing.

Cyclomatic Complexity, simply put, is a Code Quality metric that measures the potential (wait for it) complexity of a program, based on the hierarchical structure of the control logic. Meaning, specifically, the number of decisions, or execution paths, contained within the code.

As to why you should care about complexity, well, just a couple of points:

  • Complex code can perform poorly
  • Adds difficulty to understanding and troubleshooting
  • Harder to maintain
  • Can be an indication of the likelihood of producing errors
  • Increases testing effort
    • Specifically that you need an individual test case for each potential path
CCRisk
1-4Low
5-10Low
11-20Moderate
21-50High
>50Very high

So, how is CC calculated? Magic.  Pure, unadulterated, pixie magic that has been harnessed by software quality tools to produce a numerical value that can be tracked, monitored, graphed, examined, and used in order to identify areas that could lead to future issues.

Actually, thankfully, calculating CC is fairly easy. Again, keeping things simple, you count the total number of decision points in a block of code (see list below), starting with a minimum value of 1 for no decisions.

  • if, else if (“else” does not impact complexity, as the decision occurs during the “if”)
  • case (“switch” does not impact complexity, since the decision occurs at each “case” statement)
  • for/foreach
  • do…while
  • while
  • catch

Alternate calculations
There are 3 types of calculations I am aware of for CC. “Standard” (as above), “Extended” and “Modified”. The differences are only in what is counted as an individual decision.

  • “Extended”: complexity increases by one for each Boolean operator in a decision
    • if(a && b) has a complexity of 2
  • “Modified”: entire select block is counted as one, as opposed to each individual case statement

Sample 1: (snipped heavily for brevity)

This code is extracted from a method which is intended to update the visual appearance of the cursor icon based on state. It gets the screen details, does a screen buffer and some other things before it “paints” the element. I have switched out some of the code that is not applicable to this conversation with placeholder text. Where there are multiple case or if statements with nothing in between, it is because the same basic steps that are performed in each section have been combined to the final item in that list.

Based on the methods above the code sample has a complexity of:

switch (state)
case PushButtonState.Hot:
case PushButtonState.Default:
case PushButtonState.Normal:
case PushButtonState.Pressed:
case PushButtonState.Disabled:
backColor = Color.Transparent;
outlineColor = BackColor;
arrowFillColor = Color.Gray;
arrowOutlineColor = Color.Black;

if (!draw || parent == null) {
if (parent != null)
DoSomething…
Else
if (s != null && (s.Width != width || s.Height != height))
DoSomething…

if (s == null)
DoSomething…

if (arrowDirection == ArrowDirection.Left || arrowDirection == ArrowDirection.Up)
DoSomething…
else if (arrowDirection == ArrowDirection.Right || ArrowDirection == ArrowDirection.Down)
DoSomething…

if (arrowDirection == ArrowDirection.Left || arrowDirection == ArrowDirection.Right) {
for (var x = 0; x < this.bb.Width; ++x) {
if (arrowDirection == ArrowDirection.Left)
DoSomething…
for (var y = 0; y < this.bb.Height; ++y)
DoSomething…

else if (arrowDirection == ArrowDirection.Up || arrowDirection == ArrowDirection.Down)
for (var x = 0; x < this.bb.Width; ++x)
for (var y = 0; y < this.bb.Height; ++y)
DoSomething…

switch (arrowDirection) {
case ArrowDirection.Right:
case ArrowDirection.Up:
case ArrowDirection.Down:
case ArrowDirection.Left:
A= new PointF(inset, height / 2);
B= new PointF(width - inset, (height - size) / 2);
C= new PointF(width - inset, (height + size) / 2);

if (arrowDirection == ArrowDirection.Down)
while (left < right)
DoSomething…

if (reverseArrowColors)
DoSomething…
  • Standard – 26
  • Extended – 33
  • Modified – 17 OR 24 (depending on whether you want to count each Boolean operator)

Introduce Parameter Object and Extract Method Patterns

There are a couple of areas where we can improve both readability and testability by introducing new variables and extracting code into separate methods. From one perspective this is just moving existing code to a different spot so that it does not count against the original method’s complexity – however, it makes it easier to read and test.

var arrowDrawColor = GetArrowDrawColor(state);

if (!draw || parent == null)
if (parent != null)
DoSomething…
else {
if (s != null && (s.Width != client.Width || s.Height != client.Height))
DoSomething…
if (s == null)
DoSomething…

SetAlphaValues(out start, out end);

if (arrowDirection == ArrowDirection.Left || arrowDirection == ArrowDirection.Right)
for (var x = 0; x < this.bb.Width; ++x)
if (arrowDirection == ArrowDirection.Left)
DoSomething…

for (var x = 0; x < this.bb.Width; ++x)
DoSomething…
else if (arrowDirection == ArrowDirection.Up || arrowDirection == ArrowDirection.Down)
for (var x = 0; x < this.bb.Width; ++x)
DoSomething…

var pointList = GeneratePointList(size);

if (arrowDirection == ArrowDirection.Down)
while (left < right)
DoSomething…

if (reverseArrowColors)
DoSomething…

New methods:

ArrowDrawColor GetArrowDrawColor(PushButtonState state)
var arrowColor = new ArrowDrawColor();

switch (state)

return arrowColor;

SetAlphaValues(out int start, out int end)
if (arrowDirection == ArrowDirection.Left || arrowDirection == ArrowDirection.Up)
start = 0, end = 255;
else if (arrowDirection == ArrowDirection.Right || ArrowDirection == ArrowDirection.Down)
start = 255, end = 0;

IList GeneratePointList(int size)
var list = new PointList();

switch (arrowDirection)

return list;

Walk-through: The main thing we did here was to replace the two switch statements with new variables, extract code blocks to new method, as well as completely pulling some of the work out to separate classes.

Created a new method SetAlphaValues(), which sets the referenced values as appropriate

Create a new class called ArrowDrawColor with 4 fields: BackColor, OutlineColor, ArrowFillColor, ArrowOutlineColor.  The values are assigned using same code in original switch statement:

Create a new class called PointList with three fields called A, B and C (just for ease of reference), again, values assigned using the same code in original switch statement

Our new complexity is:

  • Standard – 13
  • Extended – 20
  • Modified – same as standard, since there are no switch statements
    • However, if we alter the lines [] in our new code to be a switch statement instead of the multiple conditional ifs, we can reduce the complexity by 2, or 3

It can be argued that all we have done is to move the complexity into new methods, and there is no real gain. However, what we have also done is to increase the readability and testability for the code as a whole.  This way when we do more refactoring to improve the new methods we can have focused tests to ensure that we do not lose intended functionality.

Sample 2:

The intent of the following code is to sort a list based on the column name, and direction. The first set of case statements all perform the same basic function, so I have snipped them from the sample. The next two are handled slightly different so I have kept them (mostly) as-is.

public void SortList(ref List rptList, ISession session = null, IInfoRepository infoRepository = null)
switch (SortColumn)
case "ScheduleDate":
case "ScheduleTime":
case "Frequency":
case "Output":
case "Format":
case "Status":
case "LastRunTime":
case "NextRunTime":
case "JobName":
( etc...)
rptList = SortDirection.Equals("ASC") || string.IsNullOrEmpty(SortDirection)
? rptList.OrderBy(x => x.ReportScheduleName).ToList()
: rptList.OrderByDescending(x => x.ReportScheduleName).ToList();
case "ReportName":
session = session ?? ActiveSession.GetCurrent();
var reportService = new ReportService(session);
infoRepository = infoRepository ?? reportService;
rptList = (SortDirection.Equals("ASC") || string.IsNullOrEmpty(SortDirection))
? rptList.OrderBy(x => infoRepository.RetrieveReport(x.reportId).Name).ToList()
: rptList.OrderByDescending(x => (infoRepository.RetrieveReport(x.reportId)).Name).ToList();
break;
case "Recipients":
rptList = SortDirection.Equals("ASC") || string.IsNullOrEmpty(SortDirection)
? rptList.OrderBy(x => reportRepository.GetRecipientNameArray(x.reportId)[0, 1]).ToList()
: rptList.OrderByDescending(x => reportRepository.GetRecipientNameArray(x.reportId)[0, 1]).ToList();
break;

Again, the above code sample has a complexity of:

  • Standard – 25 (method + 11 case statements + 1 conditional in each case)
  • Extended – 36 (method + 11 case statements + 2 boolean operators conditional in each case)
  • Modified – 15 (method + 1 switch + 1 conditional in each case)
  • Modified “2” – 26 (depending on whether you want to count each Boolean operator)

New Extension Method and simplified logic.

There are a couple of options here. Simplify the logic so that you are only comparing the sortdirection onc, etc

The solution that I used to refactor this piece of code ended up significantly reducing not only the CC, but also the total lines of code. Which greatly increased maintainability and comprehension.

This was done by creating a new extension method to dynamically generate the appropriate query to order the list.  This allows us to replace complete switch statement with:

rptList = rptList.SortBy(SortColumn, SortDirection).ToList()

New Enum + New Extension Method:

enum SortDirection
ASC,
DSC

public static IEnumerable SortBy(this IEnumerable list, string sortBy, SortDirection direction)
var param = Expression.Parameter(typeof(T), "item");
var sortExpression = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(param, sortBy), typeof(object)), param);

if (direction == SortDirection.ASC)
return list.AsQueryable().OrderBy<T, object>(sortExpression).ToList();

return list.AsQueryable().OrderByDescending<T, object>(sortExpression).ToList();

Our New Complexity?

In this case the value will be the same no matter which calculation method is used.

1 for original method, and 2 for the new extension.

HOWEVER…  There are a couple of small problems with this solution, and that is that the SortColumn field used in the switch statement is not always the exact same as the Column name. Especially with the ReportName case, where the actual value being used is retrieved via an additional method call.
In this case we will still need to have an abbreviated conditional before ordering the list to ensure we are using the correct value.

var sortBy = SortColumn;

switch (SortColumn)
case "ScheduleDate":
sortBy = "ScheduledDateTime.Date.Value";
case "ScheduleTime":
sortby = "ScheduleDateTime.TimeOfDay";
( etc...)
case "ReportName":
session = session ?? ActiveSession.GetCurrent();
var reportService = new ReportService(session);
infoRepository = infoRepository ?? reportService;
sortBy = infoRepository.RetrieveReport(reportId)).Name;
break;
case "Recipients":
sortBy = reportRepository.GetRecipientNameArray(reportId)[0, 1]);
break;

rptList = rptList.SortBy(sortBy, SortDirection).ToList()

After this change our CC will have increased slightly:
• Standard – 7 (method + 4 case statements + 2 conditional in one case)
• Extended – same as Standard
• Modified – 4 (method + 1 switch + 2 conditional in one case)

In a later post I think I will expand upon this topic in relation to Unit Tests and ensuring that refactor work does not break what you are working on

Leave a comment