Hacker News new | past | comments | ask | show | jobs | submit login
GNU complexity 1.5 (gnu.org)
86 points by lelf on March 2, 2016 | hide | past | favorite | 25 comments

How has this been here for 30+ minutes and no one has posted the complexity of the Linux kernel, gcc compiler, and of course the complexity program itself?

http://www.cnx-software.com/2016/03/01/gnu-complexity-comman... looks at part of the Linux kernel using this specific version of GNU complexity.

Complexity analysis of this sort is decades old. McCabe complexity is from 1976. So it's not like no one has done something like this before.

Some papers which have done a complexity analysis of the Linux kernel are: http://oai.dtic.mil/oai/oai?verb=getRecord&metadataPrefix=ht... and http://www.cs.huji.ac.il/~feit/papers/MCC12ICPC.pdf . For more examples, see https://scholar.google.com/scholar?q=complexity+of+the+Linux... .

The documentation includes an example of running the complexity program on itself. http://www.gnu.org/software/complexity/manual/complexity.htm...

If it's that interesting to you, why not do it for yourself and report the results.

Well I had to try this on JOE, the highest score is:

   1613     359     325   regex.c(1260): joe_regexec
The manual has:

    ‘50-99’ Unmaintainable code. 
    ‘100-199’ Crazy making difficult code. 
    ‘200+’ I only wish I were kidding.
    Score | ln-ct | nc-lns| file-name(line): proc-name
     4707    3815    2838   lib/vasnprintf.c(1747): VASNPRINTF

The golang compiler should include this technology and refuse to compile files which it decides are too complex for you to maintain.

Doesn't go compile itself now?

How is your comment 24 minutes old and you haven't done it yourself? ;)

Ha... I started on the kernel, but it couldn't parse it, so I gave up :-(

Naive question: What the practical usage of this? Detect complex functions in huge code base?

When you're estimating the maintainability of a codebase over time and identifing modules that are overly complex (i.e., buggy), these kinds of tools are invaluable.

I dunno, often spaghetti code (long functions with plenty of scopes and conditionals) gets high complexity scores while ravioli code (lots of short functions with simple and almost-flat control flow calling each other - "lots" as in "you can't quite remember who calls who and why you're looking at this here function right now") gets low scores; while personally I'd rather have a bowl of spaghetti over a bowl of ravioli if I'm forced to choose one of the two on any day. So I'm not a huge fan of these tools. (Assigning higher complexity to longer programs does help; but then to me, wc -l is the ultimate complexity score...)

I came here to post this comment, and I fully concur.

The lightbulb moment for me came when I got a job working on a compiler and had to start maintaining some long files with some very large functions. Being able to read linearly through a long, fairly flat function easily beats hopping hither and tither trying to remember which bit does what and piece the whole thing together.

The real complexity in code isn't from the code itself, of course; it's in the data it works with, how it modifies the data, and how far apart bits of code that may touch the same bit of data in interleaved sequences are.

It's also one of the reasons I prefer reading recursive algorithms that use pattern matching, or in a pinch, switch statements, over and above dynamic dispatch from polymorphic references. If code doesn't need to be open to extension, it's much better off exposing an enum or some other easily flat-switched thing, than implementing a recursive algorithm in almost any other form.

I agree. Ravioli code is particularly nasty because it fulfills "DRY" in the small but hurts the ability to make further changes. In both the spaghetti and ravioli situations a cyclical attack of "factor/inline/factor/inline" flushes away the worst stuff and reveals opportunities for more substantial changes, but it's easier to start from the case where there's too much inline code than to fumble through a deep callstack.

That said, if your functions are pure functions, they won't contribute much to overall complexity. It's a much different situation from having a do_the_thing() method that does some mutability magic.

I found fancy metrics like cyclomatic complexity rather useless for 1MLoC. Large, simple functions were unfairly maligned, while tangled webs of short functions ran wild and free. Simply reviewing bugs and talking to developers provides a better picture of problem areas.

People like metrics - even if they are meaningless or straight out wrong - nothing says "I'm a smart dude" like having graphs in your PPT under titles such as "cyclomatic complexity" and "measured metrics over time".

You mean, for example, running this once a month and keep stats to follow how complexity increase over time or when, in time, it suddenly increase to detect badly merged code?

It's common practice to run tools to calculate complexity as a CI (continuous integration) task.

For example, at the company I work for, we check code complexity every time someone pushes to certain branches in our repositories, and mark the build as unstable if the score is too high. In that case, the only acceptable solution is refactoring; all builds must be stable before the task associated with the change can be considered complete.

It's not reasonable to run it once a month or longer---by then we've moved on, context and focus have been lost, and refactoring is considerably more expensive (both for development and because it has to go back through QA) than if it were done immediately.

Huh, that's pretty cool. Do you have any links to more information? Ideally a write-up/blog post about your environment and how you achieve this?

Not OP but we use Jenkins for our CI which has a plugin[1] which fails builds if a threshold is not met.

[1] https://wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugi...

Yes, this is what we use as well.

Got it in one. Another example: http://betterembsw.blogspot.com/2014/06/avoid-high-cyclomati... Keep in mind that these sorts of practices are often used in serious-minded projects where development is intentional and the people doing the work are reflective on the process.

Our codebase has commit hooks that detects methods and classes with high complexity and forces you to refactor. There are very few things that cannot be refactored (parsers tend to be one of those things).

Why would you run it only once a month?

Measuring the effectiveness of refactoring.

assumed it was going to have something to do with computational complexity

is there similar software that one can pass source code to and get a detailed look at the overall and individual computational complexity?

Is there anything like this for Javascript?

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact