Today I decided to do some refactoring on my code, with the main purpose of improving maintainability. As most of you probably know Visual Studio provides some nice tools to indicate which code could use the most improvement. Since Visual Studio 2005, several editions contain Code Metrics. As you run code metrics however, it can be hard to determine how to improve the indicated parts of the code, so that it's Maintainability Index (MI) goes up. In this article I'll try to give some insight into what makes up the MI and how this effects your code.
Let me start by saying that this is in no means a complete and/or exact explanation. The main purpose of this article is to give the insights needed to improve MI numbers on your code.
Second, Microsoft seems to think that an MI of 20 or more is enough. I don't agree and advice any professional development team to set a value that is way higher than this. I've never even written a method that scored lower then 50 and these methods are still not the most clear methods (using recursion, not placing any comments and involving LINQ in a 50 line method).
Also, don't get caught up on this one method in a hundred that you can't seem to improve. If you have a good reason to write a method that still doesn't meet your minimal MI requirement, place some comment stating the reason and leave it alone.
The main components
The MI is made op of several other metrics:
- The Halstead Volumne (HV)
- The Cyclomatic Complexity (CC)
- The number of lines of code in the module (LOC)
Some universities (the Vrije Universiteit in Amsterdam and the Carnagie Mellon University, at least) argue that the percentage of comments in the module should also be included in the calculation of the MI. Unfortunately FxCop calculates the MI based on the IL code, so comments are not taken into account.
So what counts the most in calculating the MI? Well in FxCop, the LOC is actually the most important, reasoning that the less lines of code you have, the easier it is to maintain that code. I would agree to this. The second most important value is the HV, which I will explain in some more detail later.
And to what rate are the LOC and HV more important to the CC in FxCop?
The LOC actually makes up for about 75% of the MI, the HV accounts for about 24% and the CC accounts for the final 1%.
(You can find the actual calculation here)
A close look at the Halstead Volume
As this makes up about 24% of the MI metric, let's have a closer look. I won't bother you with the complete details, as this article is already long enough.
Basicly the HV is based on the assumption that all code is made up of operands and operators.
The calculation involves both the total number of operands and operators and also the distinct number of operands and operators.
Operands are identifiers, types and constants and operators are basicly all the other peaces of code (except comments, of course).
So how do you improve your MI metric? The first priority is to have less lines of code. The second priority is to reduce the amount of different operators and operands in a particular module. Both of these actions usually result in splitting up methods.
Again I would like to state that the MI metric is far from perfect and it should not be a definitive guide to what to refactor. It's only an indication of what to look at and I really think that it would be valuable to have comments taken into account, as well as have a slightly higher role for CC in there.
Please let me know your experiences on this subject trough the comments option below.