Cyclomatic complexity is the number of possible execution paths inside a given piece of code. As such, the fewer the paths through that code, and the less complex those paths are, the lower the cyclomatic complexity. As a result, the code is easier to read and understand.
In a previous article, we explained code complexity in-depth, giving examples of cyclomatic complexity and why you should measure it. Some benefits of measuring cyclomatic complexity include better tests, reduced risks of defects, lower costs, greater predictability, and it helps developers learn.
Today we’re focusing on how to reduce cyclomatic complexity. You should aim to reduce it because having a too high cyclomatic complexity can mean you have problems with your codebase, or it might cause future issues. So let’s dive in!
#1 – Write small functions
Small functions are generally easier to read and understand, even without in-line comments. Since they have fewer lines of code, they’re also less likely to have bugs or issues because developers can review them in detail faster.
The same is true for cyclomatic complexity. If your function has fewer lines of code, it will also have lower complexity. You should identify the core responsibilities of each function and extract everything else to its own functions. The rule should be one function, one job. This will also help with code reusability.
However, there is a balance between too few lines of code and understandability. As a rule of thumb, you can use 4 as a good cyclomatic complexity, but between 5 and 7 should be acceptable if it makes the code more readable. But don’t forget: the main goal is to have well-scoped functions.
#2 – Delete duplicate code
If each function doesn’t have only one job, you may have duplicate code, that is, pieces of code that do almost or exactly the same thing. Having duplicate code increases your cyclomatic complexity and compromises your code’s readability and efficiency.
There are several ways to go about duplicate code, so choose the one that is better for your projects:
- Extract the common parts of your code into dedicated functions;
- Extract generic functions into packages that your entire organization can reuse;
- Use design patterns and templates that allow you to reuse code.
#3 – Remove dead code
Dead code can be pieces of code that are never executed at run-time or that are executed but whose result is never used and does not affect the rest of the codebase. Either way, dead code wastes computation time and memory.
As such, you should focus on identifying dead code in your codebase and delete it. It will have two clear advantages: it will allow you to lower your cyclomatic complexity, but also it will help increase your code coverage.
#4 – Reduce the number of decision structures
Decision structures, such as if and switch statements, can cause an incredibly high number of branches in your codebase, increasing your cyclomatic complexity. This is where code patterns can help you out.
For example, you can use the decorator pattern instead of flag arguments with an if-statement. This design pattern allows you to add behavior to an individual object without affecting the behavior of other objects from the same class.
For switch statements, you can use the strategy pattern. This design pattern allows you to define a family of algorithms, put them into a separate class, and make their objects interchangeable.
However, there are still cases where using if and switch statements is the best approach. But the point is that, when possible, use strategies that will allow you to lower your cyclomatic complexity.
#5 – Avoid flag arguments in functions
Flag arguments are boolean parameters that you can use when changing how a function works while preserving the old behavior. However, they cause the cyclomatic complexity of your code to increase.
You can use other strategies to achieve the same result, such as refactoring the function by creating a new one, maintaining the original function, and extracting the common parts into a private function. You can also use the decorator pattern, as we saw before.
Reduce your cyclomatic complexity to increase code quality
Cyclomatic complexity is one of the most valuable metrics in software engineering. It has important implications for your code quality, maintenance, and testing. As such, keeping your cyclomatic complexity under control will help you achieve a healthy codebase.
However, remember that no metric should be used in isolation. What’s helpful is to track and improve a group of metrics that, together, can give you the big picture of your codebase health. And you can do that by starting a free 14-day trial of Codacy Quality today!