Namespace-level metrics

On top of complexity metrics for individual functions, codebeat also looks at some aggregate metrics on the namespace level. This article describes each of these along with the rationale why we believe it to be important.

Note that for Go all of these are only calculated for struct receivers, in Swift for classes, structs and enums, in Objective-C for implementations and in Python for classes.

Total complexity

Total complexity represents aggregate Assignment Branch Condition size of the entire namespace. High total complexity indicates a namespace that contains too much logic and should probably be broken down into smaller elements. It can also indicate that the few existing functions are each too busy and they need to be individually refactored. One way or another being dinged for total complexity is a signal that some thought should be put into higher-level refactoring of the namespace.

Defaults

codebeat allows the total complexity score to be up to 75 with no penalty, 75-150 will trigger an INFO-level issue, 150-250 will trigger a WARNING, 250-350 - an ERROR and anything above that will lead to a CRITICAL issue. The default setting is thus [75, 150, 250, 350].

The default setting is somewhat more relaxed ([100, 180, 280, 400]) for Objective-C which is a less terse language.

Lines of code

This represents the total length (code-wise) of a namespace. It is probably the most naive metric among the ones that we report on but can nevertheless provide substantial value. Ideally a single logical unit of code (class, module, etc.) should fit on one screen, without the need for scrolling. Longer namespaces are harder to navigate and understand, making your code less maintainable.

codebeat allows the total size of a namespace to be up to 150 lines of code with no penalty, 150-200 will trigger an INFO-level issue, 200-300 will trigger a WARNING, 300-400 - an ERROR and anything above that will lead to a CRITICAL issue. The default setting is thus [150, 200, 300, 400].

Defaults

This default setting is more strict ([100, 140, 200, 350]) for Ruby where the community strongly encourages small classes and less strict for Objective-C and Java ([180, 240, 320, 420] and [200, 250, 320, 450] respectively) where method definitions and calls often span multiple lines.

Number of functions

Number of functions is another high-level complexity metric. It is designed to encourage smart composition and modularity instead of refactoring code by multiplying private methods. We believe that a namespace with more than 15 (private and public) functions is a good candidate for breaking up into multiple independent modules each with it's own set of data.

Defaults

codebeat allows up to 14 functions with no penalty, 15-19 will trigger an INFO-level issue, 20-29 will trigger a WARNING, 30-50 - an ERROR and anything above that will lead to a CRITICAL issue. The default setting is thus [15, 20, 30, 50].

Number of instance variables

Number of instance variables is a metric designed to detect classes that carry too much state. Since every instance variable has an impact on the overall of status of the object the more instance variables you have the more possible states your object can have and this number grows exponentially as you keep adding instance variables. It is up to the programmer to ensure that they understand all possible combinations of different values of instance variable in order to avoid unexpected behavior. Too many instance variables will quickly lead to an untestable, unmaintainable class.

Defaults

codebeat allows up to 4 instance variables with no penalty, 5 will trigger an INFO-level issue, 6 and 7 will trigger a WARNING, 8-10 - an ERROR and anything above that will lead to a CRITICAL issue. The default setting is thus [5, 6, 8, 11].