Improvement of coding practices to reduce cyclomatic complexity
func complexFunction(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int, h: Int, i: Int, j: Int) -> Int {
var result = 0
if a > b {
result += a
} else {
result += b
}
if c > d {
result += c
} else {
result += d
}
if e > f {
result += e
} else {
result += f
}
if g > h {
result += g
} else {
result += h
}
if i > j {
result += i
} else {
result += j
}
return result
}
The above Swift function
complexFunction
is an example of a function with high cyclomatic complexity. Cyclomatic complexity is a software metric used to indicate the complexity of a program. It is a quantitative measure of the number of linearly independent paths through a program's source code.
In the context of the
complexFunction
, it has a cyclomatic complexity of 11 (1 for the function itself + 2 for each of the 5 if-else conditions). This is considered high as it is generally recommended to keep the cyclomatic complexity below 10.
The high complexity in this function comes from the numerous decision points
- the if-else conditions. Each of these conditions adds a new path through the program, increasing the number of test cases needed to achieve full code coverage.
This complexity makes the function harder to understand, maintain, and test, which can lead to errors and potential security vulnerabilities. It can also make it harder to detect and fix existing vulnerabilities.
To reduce the cyclomatic complexity, the code could be refactored to split the functionality into smaller, simpler functions. Additionally, the repeated if-else conditions suggest that the code could benefit from a more general approach, such as a loop or a more sophisticated data structure.
func maxOfTwoNumbers(_ num1: Int, _ num2: Int) -> Int {
return num1 > num2 ? num1 : num2
}
func complexFunction(_ numbers: [Int]) -> Int {
var result = 0
for i in stride(from: 0, to: numbers.count, by: 2) {
result += maxOfTwoNumbers(numbers[i], numbers[i+1])
}
return result
}
The refactored code reduces the cyclomatic complexity by breaking down the complex function into smaller, more manageable functions and using loops instead of multiple if-else statements.
The function
maxOfTwoNumbers
is a helper function that takes two integers as input and returns the maximum of the two. This function is used to replace the multiple if-else statements in the original function.
The
complexFunction
now takes an array of integers as input. It iterates over the array in steps of two, using the
stride
function. For each pair of numbers, it calls the
maxOfTwoNumbers
function and adds the result to the
result
variable.
This refactoring significantly reduces the cyclomatic complexity of the code, making it easier to understand, maintain, and test. It also improves code reuse by separating the logic for finding the maximum of two numbers into a separate function that can be used elsewhere in the code if needed.
The code now adheres to the Single Responsibility Principle, as each function has a single, clear purpose. The use of meaningful function and variable names, as well as the removal of unnecessary conditional statements, improves code readability.
Remember to perform code reviews and use automated code analysis tools to ensure the cyclomatic complexity remains low as the codebase evolves. Consider using functional programming techniques and design patterns to further simplify the code structure and logic.