A new CC metric that takes nesting into account
Opened this issue · 9 comments
By definition, the CC metric does not take into account the nesting levels of the method. For example, consider the following Python source code:
public int getPayAmount() {
int result = 0;
if (isDead)
result = deadAmount();
else {
if (isSeparated)
result = separatedAmount();
else {
if (isRetired)
result = retiredAmount();
else
result = normalPayAmount();
}
}
return result;
}
By refactoring this code, we get:
public void getPayAmount() {
if (isDead) return deadAmount();
if (isSeparated) return separatedAmount();
if (isRetired) return retiredAmount();
return normalPayAmount();
}
As you can see, By applying a popular technique named Replace Nested Conditional with Guard Clauses, the source code structure would improve a lot. However, the CC metric does not change (by definition).
Some researchers have proposed a few solutions. Surprisingly, the best solution (in my opinion) has the minimum citation link .
I will not classify this as a bug, as I think this is actually a possible new metric to CK!
Would you be willing to implement it yourself? I can help you by giving you tips and feedback in a PR!
@mauricioaniche
I have tried this before but I failed. I don't know how can I access the depth of a method. The new metric is computed as follows:
MWMC(m) = d(m) + WMC(m)
where d(m) denotes the depth of the method m. For example, consider the following code:
public int getPayAmount() {
int result = 0;
if (isDead)
result = deadAmount();
else {
if (isSeparated)
result = separatedAmount();
else {
if (isRetired)
result = retiredAmount();
else
result = normalPayAmount();
}
}
return result;
}
The depth of the method (d(m)) is 3. Indeed, if the depth of a method is implemented as a new metric, the modified WMC will be automatically computed.
Is d(m)
the max depth that can be found in a method? If so, we have the MaxNumberOfNestedBlocks
as a metric already: https://github.com/mauricioaniche/ck/blob/master/src/main/java/com/github/mauricioaniche/ck/metric/NumberOfMaxNestedBlock.java
Is that it?
Not exactly. For any nested blocks, the max depth of that block added to d(m)
. Consider the following code:
public int m1(){
statement 1;
for(int i=0; i< 10; i++){
statement 2;
if(cond)
statement 3;
}
statement 4;
if(cond2) {
statement 5;
statement 6;
if(cond3) {
statement 7;
}
}
if(cond4) {
statement 8;
statement 9;
if(cond5) {
statement 10;
}
}
statement 11;
return 100;
}
The max depth is 2. However, the d(m)
is 3 (see statement 3,7,10).
@mauricioaniche
In fact, the aforementioned paper says:
"Identify the second, the third, the fourth, and subsequent levels of nesting constructs and assign each occurrence with one unit of complexity. "
I did not read the paper yet, so, sorry for my questions!
But isn't then d(m) = max_nested_blocks + 1
?
No. Although most of the cases are true, there are some situations that d(m) != max_nested_blocks + 1
.
When a method consists of two independent nesting blocks, that equation does not hold anymore.
From the paper, it seems that, all we need to do in the WMC implementation is to give a weight of 1, if the nesting(node) = 1
, or a weight of 2, if the node is nesting(node)>1
.
(There's also the corner case of a block returning early, then, next ones in that nested block should be considered 1 again)
Does that make sense to you?
Yes. This is exactly what I understood from the paper.