46

Software Engineering Answer: This is just one of the many cases where simply counting beans that are simple to count will make you do the wrong thing. Its not a complex function, don't change it. Cyclomatic Complexity is merely a guide to complexity, and you are using it poorly if you change this function based on it. Its simple, its readable, its ...


32

The core thing here: "brain capacity". You see, one of the main functions of code is ... to be read. And code can be easy to read and understand; or hard. And having a high CC simply implies a lot of "levels" within one method. And that implies: you, as a human reader will have a hard time understanding that method. When you read source code, your brain ...


16

Thanks to @JimmyHoffa, @MichaelT, and @GlenH7 for their help! Python First things first, you should really only accept known prefixes, that is either 'H' or 'h'. If you have to accept both, you should perform some operation to make it consistent to save room in your map. In python you could create a dictionary. EXTRACTION_MAP = { 'S': ExtractSecond, ...


15

As you have already noticed, bunching up control logic to reduce indentation is totally counter-productive. The problem is not actually with levels of indentation, or number of lines. Those things are just indicators of the actual problem: doing too much in one piece of code. The solution is to refactor nested, complicated loops into separate methods so ...


14

My guess is that you just divided/moved the complexity. It decreased because you doesn't count the implementation of .where() in your CC. The overall CC hasn't really moved, your own code's CC decreased, only because it's now moved to the framework's code. I'd say it's more maintainable. When it's a feature of the language, use it. It's no a "ohh, I see, ...


13

Inverted If Most developers think in terms of nested logic. It's difficult for them to invert their logic to reduce nesting. Deeply nested code is more difficult to read, and to reduce nesting you often have to invert your logic. When a programmer writes code they write in a logical tree structure like this. bool function publish(Document doc) { if(...


13

Some remarks on this that I idly write up... Specifically, for the Wikipedia equation of M = E − N + 2P That equation is very wrong. For some reason, McCabe indeed uses it in his original paper ("A Complexity Measure", IEEE Transactions on Software Engineering, Vo.. SE-2, No.4, December 1976), but without justifying it and after actually citing the ...


12

If your article "says the CC is 3 as there are three possible paths" then the article is missing some of the detail. The wikipedia definition of cyclomatic complexity defines it in terms of the number of nodes and edges in the graph of the function: M = E − N + 2P. This is the graph of your function: (+) | (if) |\ | (stmt) |/ ...


12

You're performing identical tests on two independent sets of values. Factor out a function that performs those tests on a single set of values, and then call it twice: int DateInvalid (int d, int m, int y) { return y < 2000 || !(m >= 1 && m <= 12) || !(d >= 1 && d <= DaysInMonth(m)) || (m == 2 &...


11

All you are doing is highlighting a flaw in cyclomatic complexity as a metric, the complexity of the code really hasn't changed. You have an explicit branch in the first example and need to understand there is an implied branch in the second. The second is clearer and easier to understand provided you understand the syntax, and since it uses less basic ...


9

When I understood this correctly, the Cyclomatic Complexity of main is 8 - that is the number of linearly independent paths through the code. You either get an exception at one of the seven lines, or none, but never more than one. Each of that possible "exception points" corresponds exactly to one different path through the code. I guess when McCabe ...


9

Measure technical debt in terms of the amount of work required to eliminate the debt: if it'll take you and your team 3 months to get your code to the shape you'd like it to be in, you've got 3 team-months of debt. The cost of carrying the debt, like interest on a loan, is the amount of extra work that you incur due to the debt: if 50% of the work your team ...


9

Unless you really need that performance, always prefer better readability. The biggest performance wins do not come from micro-optimizations, but from algorithmic complexity improvements, and from other ways to avoid doing unnecessary work. Not doing something is always faster than doing something as fast as possible. Cleaner code makes it easier to spot ...


8

Regarding the formula: nodes represent states, edges represent state changes. In every program, statements bring changes in the program state. Each consecutive statement is represented by an edge, and the state of the program after (or before...) the execution of the statement is the node. If you have a branching statement (if for example) - then you have ...


8

The paper posted in John R. Strohm's answer is somewhat misleading. Although I don't disagree that there is a relationship between cyclomatic complexity and lines of code, it looks like cyclomatic complexity has been misused by applying cyclomatic complexity at the project level. First, cyclomatic complexity should be applied at a method level, not a ...


7

In each connected component of a graph the number of edges must be at least greater or equal to the number of nodes minus 1 (that follows by induction, a component with one node does not need any edge, but whenever you add an additional node to a component, you need another edge to connect it with the previous ones: two nodes need at least one edge, three ...


6

Being 'the other guy', I'll answer here, and be precise about what I say (which I was not particularly precise with over on other formums). Using the code example above, I calculate the cyclomatic complexity as 8, and I have comments in the code to show how I calculate that. To describe the paths I will consider a successful loop through all the thro() ...


6

Consider the following: define dispatch_message (message_id, message_contents) if (message_id == MESSAGE_ID_1) FirstMessageId(message_contents).dispatch() else if (message_id == MESSAGE_ID_2) SecondMessageId(message_contents).dispatch() ... else if (message_id == MESSAGE_ID_N) NthMessageId(message_contents).dispatch() ...


6

There are no software quality metrics that are good - at least none are known yet. Years of research hasn't provided us with any good one yet. So the answer whether any of your suggested metrics is a good metric for software quality is a disappointing "no." There are some metrics that are reasonable indicators of bad software. But the lack of signs of bad ...


6

The idea behind these guidelines is that, when you find yourself in a situation such as yours, that there is most likely (not always, mind you, but still more often than you think) something wrong with your algorithm, and you should step back and rethink it. I actually don’t think that refactoring will help you much, if it’s indeed an O(n²) or O(n³) ...


6

The first sample is just wrong. Not wrong in terms of the result, but the style is terrible. It is repetitive and error prone. The second sample is actually the step to do to obtain the readable, well written code. It's not a hack. It's just badly written code rewritten correctly. The fact that it reduces cyclomatic complexity doesn't surprise me, since ...


6

In order to answer the question objectively, we'd need some sort of metric for maintainability. Cyclomatic complexity itself isn't a measure of maintainability, but it is a component of some metrics that purport to measure maintainability. For example, the formula for the Maintainability Index is: MI = 171 - 5.2 * ln(V) - 0.23 * (G) - 16.2 * ln(LOC) where ...


6

C.C, like all other rules of thumb for code smells, is a heuristic. It's not a fail-safe criterion that tells you an absolute truth. If it were, the reasonable thing to do would be simply to make such methods illegal in the language and force people to achieve their ends in another way. But that isn't the way indicators work. Most of the time their function ...


6

Function Reuse First and formost, functions are a prinicple means of abstraction (SICP) not necessarily a means of reuse. The main problem within software engineering is tackling complexity in the application domain. By limiting function complexity (either cyclomatic, by lines of code (LOC) length or other measures), it provides readers of the code with a ...


5

Cyclomatic complexity is one of the multiple measurements of code complexity. For example, in Visual Studio, the maintainability index depends on: Cyclomatic complexity, Depth of inheritance, Class coupling, Lines of IL code (IL code being the source code compiled to Intermediary Language which is then JIT-compiled). Every of those measurements, as well as ...


5

Extracting code to sub-functions does not lower the cyclomatic complexity of a program. It may of course lower the the cyclomatic complexity of an individual function if some complexity is extracted to a separate function, but this just moves the complexity around, which doesn't improve your program in itself. A high cyclomatic complexity of a function ...


5

Let's back out the excessive negation, which makes the logic much harder to read. The same tests can be written using only disjunction instead of as disjunction of negated conjunctions. return y < 2000 || m < 1 || m > 12 || d < 1 || d > DaysInMonth(m,y); where int DaysInMonth(m,y) { return DaysInNonLeapYearMonth(m) + (m == 2 &...


5

I don't think cyclomatic complexity is affected by exit points. It is related to the number of code paths, which will correlate to the number of decision points. One way to look at it is "how many unit tests would I need to write to obtain 100% code coverage?" In your example, you would need two tests, in both cases. As for design patterns that reduce ...


4

The story of equals() combines several unfortunate design decisions that are now impossible to change, and that every Java user just has to live with one way or another: it is deeply woven into the semantics of the standard container types, it is automatically inherited by every user-defined class but with a behaviour that is usually not what you want, and ...


4

I am not convinced your control flow graph is correct because it shows two terminal nodes 9 and 12. Instead, there should be a single terminal node for the return. A difficulty with your code is that it contains many irrelevant details for the purpose of calculating cyclomatic complexity. So let's strip it down to the relevant control flow: f() { ...; ...


Only top voted, non community-wiki answers of a minimum length are eligible