Cyclomatic complexity - ligurio/openbsd-tests GitHub Wiki

OpenBSD complexity metrics

There are at least two tools to measure cyclomatic code complexity on OpenBSD: devel/py-mccabe and lizard in Python PIP. I have used second one because with my patches it can generate nice HTML reports.

python ../lizard/lizard.py --exclude "./distrib/*" --exclude "./etc/*" --exclude "./games/*" --exclude "./gnu/*" --exclude "./include/*" --exclude "./libexec/*" --exclude "./regress/*" --exclude "./share/*" --html --working_threads 5 . > src_`uname -r`.html

python ../lizard/lizard.py --exclude "./data/*" --exclude "./dist/*" --exclude "./distrib/*" --exclude "./doc/*" --exclude "./etc/*" --exclude "./font/*" --exclude "./share/*" --html --working_threads 5 . > xenocara_`uname -r`.html

Description

The term is used to measure complexity of a function. Complex functions are usually evil, because they are hard to maintain, hard to test, etc.

The complexity M is then defined as M = E − N + 2P where

E = the number of edges of the graph
N = the number of nodes of the graph
P = the number of connected components (exit nodes).

For example, we can find in Linux kernel coding style:

Now, some people will claim that having 8-character indentations makes the code move too far to the right, and makes it hard to read on a 80-character terminal screen. The answer to that is that if you need more than 3 levels of indentation, you’re screwed anyway, and should fix your program. ... Functions should be short and sweet, and do just one thing. They should fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24, as we all know), and do one thing and do that well.

The maximum length of a function is inversely proportional to the complexity and indentation level of that function. So, if you have a conceptually simple function that is just one long (but simple) case-statement, where you have to do lots of small things for a lot of different cases, it’s OK to have a longer function.

However, if you have a complex function, and you suspect that a less-than-gifted first-year high-school student might not even understand what the function is all about, you should adhere to the maximum limits all the more closely. Use helper functions with descriptive names (you can ask the compiler to in-line them if you think it’s performance-critical, and it will probably do a better job of it than you would have done).

Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong. Re-think the function, and split it into smaller pieces. A human brain can generally easily keep track of about 7 different things, anything more and it gets confused. You know you’re brilliant, but maybe you’d like to understand what you did 2 weeks from now.

In JPL Institutional Coding Standard for the C Programming Language:

Functions should be no longer than 60 lines of text and define no more than 6 parameters.

A function should not be longer than what can be printed on a single sheet of paper in a standard reference format with one line per statement and one line per declaration. Typically, this means no more than about 60 lines of code per function. Long lists of function parameters similarly compromise code clarity and should be avoided.

Each function should be a logical unit in the code that is understandable and verifiable as a unit. It is much harder to understand a logical unit that spans multiple screens on a computer display or multiple pages when printed. Excessively long functions are often a sign of poorly structured code.

Compute cyclomatic complexity of functions using lizard. Lizard is an extensible cyclomatic complexity analyzer for many imperative programming languages including C.

References