Cyclomatic Complexity (CYCLO)
Cyclomatic complexity is a quantitative metric that measures the number of linearly independent paths through a block of code. The metric value gets increased each time the control flow of a function/method/constructor splits resulting in a new conditional branch.
The following statements and expressions affect the metric value:
if(statement and expression),catch,do,while,for(statement and expression)- conditional expressions (
? ... : ...) casein a switch statement or expression (defaultor last case does not count)- null-aware operators (
?[],?.,?..,...?,{?key: value},{key: ?value}) &&and||in binary expressions or patterns??and??=
The base complexity of a function/method/constructor is 1.
This metric is not calculated for abstract methods/getters/setters.
To get real-time analysis for this metric, enable the avoid-high-cyclomatic-complexity rule.
Why Be Cautious
High Cyclomatic Complexity can lead to:
- Difficulty in Testing: More independent paths require more test cases.
- Reduced Readability: Complex code is harder for others to read and understand.
- Error-Proneness: Complex functions are more likely to contain errors due to multiple paths and logic branches.
How to Address High Cyclomatic Complexity?
First, review the code for potential simplifications. For example, some conditions may be excessive (covered by other conditions) or unnecessary.
But the general rule is to split complex declaration into several smaller ones as it both improves readability and allows testing them separately preventing two most significant issues.
Config Example
dcm:
metrics:
cyclomatic-complexity:
threshold: 20
To set multiple threshold or other common config options, refer to the Configuring Metrics page.
Example
To view what contributes to the metric value, generate an HTML report.
❌ Bad: High Cyclomatic Complexity
// CYCLO: 10
void processOrder(Order order) {
if (order.isPaid) {
if (order.hasStock) {
if (order.isEligibleForDiscount) {
applyDiscount(order);
}
if (order.requiresShipping) {
if (order.isInternational) {
calculateInternationalShipping(order);
} else {
calculateDomesticShipping(order);
}
switch (order.shipping.status) {
case .pending:
...
case .processed:
...
case .failed:
...
case _: // not counted
}
} else if (order.pickupLocation != null) {
arrangePickup(order);
}
} else {
throw Exception('Out of stock');
}
} else {
logPaymentPending(order);
}
}
✅ Good: Low Cyclomatic Complexity
// CYCLO: 3
void processOrder(Order order) {
if (!order.isPaid) {
logPaymentPending(order);
return;
}
if (!order.hasStock) {
throw Exception('Out of stock');
}
applyDiscountIfEligible(order);
processShipping(order);
}
// CYCLO: 2
void applyDiscountIfEligible(Order order) {
if (order.isEligibleForDiscount) {
applyDiscount(order);
}
}
// CYCLO: 4
void processShipping(Order order) {
if (order.requiresShipping) {
if (order.isInternational) {
calculateInternationalShipping(order);
} else {
calculateDomesticShipping(order);
}
} else if (order.pickupLocation != null) {
arrangePickup(order);
}
}