Understanding Cyclomatic Complexity — NDepend
Cyclomatic Complexity (or CC) in C# is a code metric that counts the variety of linearly unbiased execution paths by way of a way. Concretely, it’s computed as 1 plus the variety of branching constructs within the technique physique (akin to if, whereas, for, case, &&, ||, ?: and ??). The greater the rating, the more durable the strategy is to learn, take a look at and safely change. A rating of 1 means a single straight path, round 10 is the normal higher sure advisable by Thomas McCabe, and something above 25 is flagged as extreme by Microsoft’s CA1502 analyzer.
This information explains, with C# examples, how Cyclomatic Complexity is calculated, what thresholds matter in observe, find out how to measure and visualize it in actual .NET codebases, and find out how to transcend the uncooked rating by pairing it with take a look at protection and IL-level evaluation.
What is Cyclomatic Complexity?
Cyclomatic Complexity was launched by Thomas J. McCabe in 1976 as a approach to quantify the structural complexity of a bit of code. The concept comes from graph principle: each technique might be represented as a management move graph the place nodes are blocks of statements and edges are jumps between them. On that graph, the Cyclomatic Complexity is given by the traditional formulation:
the place E is the variety of edges, N the variety of nodes, and P the variety of linked parts. For an everyday technique with a single entry and a single exit, this collapses to 1 + the variety of determination factors, which is the shape most instruments really compute.
What this quantity actually tells you is the minimal variety of take a look at instances that you must train each unbiased path by way of the strategy. That is why Cyclomatic Complexity has caught round for nearly half a century: it’s a structural metric, nevertheless it has a really concrete operational that means for everybody who has to take care of or take a look at the code.
Definition of Cyclomatic Complexity in C#
The Cyclomatic Complexity for a C# method is concretely 1 + {the variety of following expressions discovered within the physique of the strategy}:
|
if whereas for foreach case default proceed goto && || catch ternary operator ?: ?? and or |
The following expressions are not counted for CC computation:
|
else do swap strive utilizing throw lastly return object creation technique name area entry |
Two particulars that journey folks up: else doesn’t increment the rating as a result of the choice path was already created by its matching if; and a swap contributes one unit per case (and one for default), not one for the swap key phrase itself. C# pattern-matching constructs (and, or, the trendy swap expression with patterns) additionally add to the rating, the identical method their traditional counterparts do.
Example of Cyclomatic Complexity Impact in C#
Exhibiting a Complex Method
Here is a posh technique with entangled if and else scopes. The key phrase if is used six occasions and && is used as soon as. Hence its Cyclomatic Complexity rating is 8:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public static class OrderLogic { public static void Course ofOrder( int orderId, bool isPriority, bool isInternational, bool isGift, bool isCouponApplied, decimal orderTotal) { if (orderId <= 0) { Console.WriteLine(“Invalid order ID.”); return; }
if (isPriority) { Console.WriteLine(“Processing precedence order.”); if (isInternational) { Console.WriteLine(“Processing global precedence order.”); if (isGift) { Console.WriteLine(“This is a present order.”); } } } else { Console.WriteLine(“Processing customary order.”); if (isInternational) { Console.WriteLine(“Processing global customary order.”); } }
if (isCouponApplied && orderTotal > 100) { Console.WriteLine(“Applying low cost for orders over $100.”); } else { Console.WriteLine(“No low cost relevant.”); } } } |
Eight unbiased paths means at the least eight checks to completely cowl this single technique, plus a non-trivial quantity of head-scratching each time somebody has so as to add a brand new corporate affairs rule. This is precisely the sort of technique the place a regression slips in unnoticed.
Refactoring the Complex Method in Several Simpler Methods
The technique above might be refactored into a number of much less complicated strategies. In the code we use CC to refer to every technique Cyclomatic Complexity rating:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
public static class OrderLogic { public static void Course ofOrder( int orderId, bool isPriority, bool isInternational, bool isGift, bool isCouponApplied, decimal orderTotal) { // CC 2 if (!IsLegitimateOrder(orderId)) return; Course ofOrderKind(isPriority, isInternational, isGift); ApplyDiscountIfEligible(isCouponApplied, orderTotal); } non-public static bool IsLegitimateOrder(int orderId) { // CC 2 if (orderId <= 0) { Console.WriteLine(“Invalid order ID.”); return false; } return true; } non-public static void Course ofOrderKind( bool isPriority, bool isInternational, bool isGift) { // CC 5 if (isPriority) { Console.WriteLine(“Processing precedence order.”); if (isInternational) { Console.WriteLine(“Processing global precedence order.”); } } else { Console.WriteLine(“Processing customary order.”); if (isInternational) { Console.WriteLine(“Processing global customary order.”); } } if (isGift) { Console.WriteLine(“This is a present order.”); } } non-public static void ApplyDiscountIfEligible( // CC 3 bool isCouponApplied, decimal orderTotal) { if (isCouponApplied && orderTotal > 100) { Console.WriteLine(“Applying low cost for orders over $100.”); } else { Console.WriteLine(“No low cost relevant.”); } } } |
Benefits of Refactoring
- Simpler Control Flow: The primary technique now delegates particular duties to smaller, extra centered strategies.
- Easier to Test: You can take a look at every smaller technique independently.
- Lower Cyclomatic Complexity: The complexity is unfold throughout a number of strategies, making every technique simpler to grasp and preserve independently.
- Better Naming: Method names like
IsLegitimateOrderorApplyDiscountIfEligibledoc intent, so a reader doesn’t need to mentally simulate the physique to grasp the high-level move.
Note that the overall Cyclomatic Complexity summed throughout the 4 strategies is definitely barely greater than the unique 8. That is ok and even anticipated. What issues for maintainability is the complexity per technique, as a result of that’s the unit a developer has to purpose about at a time.
Cyclomatic Complexity Thresholds: What Score Is Too High?
There is not any single sacred quantity, however the literature converges across the identical ranges. The desk beneath summarises what most groups and instruments use as a suggestion:
| Cyclomatic Complexity | Risk profile | Practical interpretation |
|---|---|---|
| 1 – 10 | Simple, low threat | McCabe’s unique advice. Easy to check, simple to learn. |
| 11 – 20 | Moderately complicated | Still manageable, however value a second pair of eyes throughout assessment. |
| 21 – 50 | Complex, excessive threat | Hard to check exhaustively. Strong refactoring candidate. |
| > 50 | Untestable | Bug magnets. Often legacy hotspots that should be damaged down. |
Two reference factors are value maintaining in thoughts. McCabe himself advisable splitting modules that exceed a Cyclomatic Complexity of 10. Microsoft’s CA1502 analyzer defines “extreme complexity” as a rating better than 25 by default. Mark Seemann argues for an excellent tighter ceiling of round 7, mirroring Miller’s “magical quantity seven, plus or minus two” for human short-term reminiscence.
In observe the fitting threshold relies on the codebase. A parser, a serializer or a state machine will routinely dwell within the 15-25 vary with out being objectively dangerous. A chunk of corporate affairs logic that scores 25 nearly at all times is.
Measuring Cyclomatic Complexity in C#
You can’t enhance what you don’t measure, so utilizing a device to judge code complexity is important. Calculating this metric helps builders determine areas which may want refactoring to enhance code high quality.
NDepend is a superb possibility for this, because it measures the cyclomatic complexity of strategies in C# code. For occasion, it contains the Search Methods by Complexity function, which helps determine complicated strategies for additional evaluation.
Visual Studio itself ships a “Calculate Code Metrics” command (Analyze > Calculate Code Metrics) that experiences Cyclomatic Complexity per technique, sort and meeting. The CA1502 analyzer might be wired into your construct to really fail on strategies above a configured threshold, which is beneficial for brand new code. Roslyn-based analyzers like SonarAnalyzer.CSharp and third-party instruments akin to ReSharper or CodeRush additionally floor the identical metric contained in the editor.
Ruling C# Cyclomatic Complexity
NDepend presents a number of guidelines like Avoid methods too big, too complex that flag strategies with excessively excessive Cyclomatic Complexity scores, highlighting potential points within the code.
You are most likely working with a big legacy codebase, making it impractical to refactor each complicated technique. This is why it’s important to measure Cyclomatic Complexity in opposition to a baseline, permitting you to deal with new or refactored strategies which are too complicated. There are two guidelines for that:
This baseline-driven method issues greater than any absolute threshold. When you begin monitoring complexity on a well-established codebase, you’ll inevitably discover complicated strategies which have been secure and well-tested for years. The actual threat isn’t the static rating, it’s what occurs when these strategies begin rising. Using NDepend’s CQLinq, you possibly can categorical that concept immediately:
|
// warnif rely > 0 from m in JustMyCode.Methods the place m.CodeWasChanged() && m.OlderVersion().CyclomaticComplexity < m.CyclomaticComplexity && m.OlderVersion().CyclomaticComplexity > 10 choose new { m, PreviousComplexity = m.OlderVersion().CyclomaticComplexity, m.CyclomaticComplexity } |
The question warns each time an already-complex technique (CC > 10) turns into much more complicated between two evaluation snapshots. In different phrases, it surfaces the modifications which are really dangerous, whereas leaving secure legacy untouched.
Visualizing C# Cyclomatic Complexity
A coloured treemap can be utilized to visualize the cyclomatic complexity of your C# strategies. In this visualization, every rectangle represents a way:
- The measurement of the rectangle corresponds to the variety of statements within the technique.
- The shade of the rectangle displays the strategy’s cyclomatic complexity.
The benefit of a treemap over a flat checklist is that complexity hotspots actually leap out of the image: a big, darkish purple rectangle inside an in any other case calm space is precisely the sort of technique that deserves an structure dialog.
C# Cyclomatic Complexity and Tests
Writing checks to your code is these days a necessary observe for each skilled C# developer. Typically, a take a look at covers a single execution path, whereas the Cyclomatic Complexity rating of a way represents the variety of unbiased execution paths. Therefore, Cyclomatic Complexity offers a tough estimate of what number of checks are required to completely take a look at a way.
By working checks, you possibly can decide the code protection for every technique. A technique partially coated signifies that not all its unbiased execution paths are challenged by checks. The rule Methods should have a low C.R.A.P score spots strategies that each have excessive Cyclomatic Complexity scores and are poorly examined (C.R.A.P stands for Change Risk Analyzer and Predictor). The matched strategies clearly point out ache factors in your code and must be examined and refactored.
The CRAP score defines a selected mathematical formulation to mix complexity and protection. Expressed in CQLinq, that formulation is:
|
// from m in JustMyCode.Methods
let CC = m.CyclomaticComplexity let uncov = (100 – m.PercentageCoverage) / 100f let CRAP = (CC * CC * uncov * uncov * uncov) + CC
choose new { m, CRAP } |
The CRAP rating scales with the sq. of complexity and the dice of uncovered share, then provides the uncooked complexity as a ground. The sensible takeaway: a way with CC = 30 and 100% protection is way much less of a legal responsibility than a way with CC = 12 and 0% protection. The second information level of protection exhibits that not all complexity is created equal.
Going Beyond Cyclomatic Complexity
Cyclomatic Complexity is a superb begin for reasoning about your code’s complexity, not the tip of the dialog. Two extensions are value understanding about.
Pair Complexity with Branch Coverage
If you could have two strategies with the identical Cyclomatic Complexity, and one is totally coated by department checks whereas the opposite has none, the danger profile is wildly totally different. A CQLinq question that captures this concept:
|
// warnif rely > 0 from m in JustMyCode.Methods the place m.CyclomaticComplexity > 10 && m.PercentageBranchCoverage < 100 choose new { m, m.PercentageBranchCoverage, m.CyclomaticComplexity } |
It raises a warning for any complicated technique with out complete department protection, which is a way more nuanced view of threat than “this technique has CC > 10”.
IL Cyclomatic Complexity for Third-Party Code
Any non-trivial C# venture drags in third-party libraries. Most of the time you deal with them as black bins; typically you remorse it. NDepend’s CQLinq presents a property known as IL Cyclomatic Complexity that applies the identical metric to the .NET Intermediate Language contained in the DLLs you rely on.
This allows you to measure how complicated the strategies of a candidate library really are, not simply how properly their public API is documented. If you analyze a dependency and discover that its inside strategies are routinely above CC = 30 in IL, that could be a sturdy sign it will likely be arduous to debug when one thing goes unsuitable inside it.
How to Reduce Cyclomatic Complexity in C#
Refactoring for decrease Cyclomatic Complexity is usually about extracting selections out of the recent path. The methods beneath come up time and again on actual codebases.
1. Extract Method
The most boring and the best. Pull a contiguous block of selections right into a well-named technique, precisely like within the Course ofOrder instance earlier. Each name web site loses one chunk of complexity; every new technique is sufficiently small to check by itself.
2. Early Return / Guard Clauses
Instead of deeply nesting validation in if blocks, return early on invalid enter. The cyclomatic rely is similar, however the cognitive load drops sharply as a result of each following line can assume the enter is legitimate.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Nested public decimal CalculateCharge(Order order) { if (order != null) { if (order.IsLegitimate) { if (order.Customer != null) { return order.Total * 0.05m; } } } return 0; }
// Guarded public decimal CalculateCharge(Order order) { if (order is null) return 0; if (!order.IsLegitimate) return 0; if (order.Customer is null) return 0; return order.Total * 0.05m; } |
3. Replace Conditionals with Polymorphism
A protracted swap on a sort discriminator is a traditional odor. Each case provides 1 to the rating and the strategy turns into the one place that should change each time a brand new variant seems. Moving the per-variant behaviour into derived lessons (Strategy, Template Method, or easy subclass overrides) sometimes collapses the central technique to CC = 1.
4. Use Modern C# Pattern Matching and Switch Expressions
Switch expressions are nonetheless counted by analyzers, however they encourage flatter, side-effect-free code than chains of nested ifs. Combined with sample matching, they typically change a CC of 8-10 with a single, declarative expression:
|
public static decimal Low costFor(Customer c) => c swap { { IsVip: true, YearsActive: >= 5 } => 0.20m, { IsVip: true } => 0.10m, { YearsActive: >= 10 } => 0.08m, { YearsActive: >= 1 } => 0.03m, _ => 0m }; |
5. Use Lookup Tables for Pure Mappings
If a way is usually an inventory of “enter X maps to output Y”, a Dictionary or a static readonly array is sort of at all times preferable to a sequence of ifs. The dictionary lookup is CC = 1, no matter what number of entries it holds.
6. Boolean Parameters Are a Code Smell
A technique that takes a number of bool flags nearly at all times hides a number of strategies in a trench coat. Splitting SendEmail(bool html, bool pressing, bool dryRun) into extra particular strategies reduces each the per-method complexity and the possibility {that a} caller passes the unsuitable mixture of flags.
Frequently Asked Questions
What is an efficient Cyclomatic Complexity rating in C#?
Below 10 is taken into account secure, between 10 and 20 wants consideration, above 25 is what Microsoft’s CA1502 rule flags as extreme. McCabe’s unique advice, nonetheless broadly quoted, is to refactor any technique that exceeds 10.
Does the else key phrase improve Cyclomatic Complexity?
No. The else department is already implied by its matching if, so it doesn’t add a brand new unbiased path. Only the if itself counts.
Does a swap assertion rely as soon as or per case?
Per case (and per default). The swap key phrase itself doesn’t increment the rating. A swap with 6 instances plus a default contributes 7 to the strategy’s Cyclomatic Complexity.
Does Cyclomatic Complexity equal the variety of unit checks I want?
It is a helpful decrease sure, not a contract. Cyclomatic Complexity provides you the variety of linearly unbiased paths, which is the minimal variety of checks required for full path protection. In observe you might want fewer (some paths are infeasible) or extra (information combos inside a single path can nonetheless misbehave).
What is the distinction between Cyclomatic Complexity and Cognitive Complexity?
Cyclomatic Complexity measures the variety of paths. Cognitive Complexity, popularised by SonarSource, additionally weighs nesting depth and boolean operator combos as a result of they make code more durable to learn even when they don’t add new paths. The two metrics are complementary: low cyclomatic, excessive cognitive is uncommon; low cognitive, excessive cyclomatic can also be uncommon; strategies which are dangerous on one are normally dangerous on the opposite.
How do I measure Cyclomatic Complexity in Visual Studio?
In Visual Studio, go to Analyze > Calculate Code Metrics > For Solution. The ensuing window lists Cyclomatic Complexity per technique, sort and venture. For steady enforcement, allow the CA1502 analyzer and configure its threshold by way of a CodeMetricsConfig.txt extra file.
Does Cyclomatic Complexity work on async or LINQ code?
Yes. The C# compiler rewrites async/await right into a state machine, however most instruments (NDepend, the Roslyn analyzers, Visual Studio’s metrics) compute Cyclomatic Complexity on the source-level technique. await itself doesn’t rely, however the if, whereas and catch constructs surrounding it do. LINQ question operators are technique calls, which don’t rely both, however lambdas handed to them are analyzed as their very own strategies.
Conclusion
Cyclomatic Complexity is likely one of the oldest code metrics nonetheless in lively use, and the reason being easy: it captures one thing that maps on to real-world ache. A excessive rating means extra paths to purpose about, extra checks to write down, extra locations the place a bug can conceal. Keeping it underneath management, particularly on the strategies that change essentially the most, pays for itself inside weeks.
That mentioned, the rating by itself is half the image. A posh however closely examined technique isn’t the one which wakes you up at evening; a reasonably complicated technique with zero protection that will get touched each dash will. Pair Cyclomatic Complexity with protection (or with the CRAP rating), implement a delta-based rule slightly than a flat threshold on legacy code, and use IL Cyclomatic Complexity to sanity-check the libraries you rely on. Combined, these methods flip a Nineteen Seventies metric right into a surprisingly trendy early-warning system for technical debt.
If you need to do that by yourself codebase, download a free trial of NDepend and run an evaluation: the complexity hotspots normally turn out to be apparent inside the first couple of minutes.





