Visual Studio has been providing static code analysis code metrics for a long time. Maitainability index, cyclomatic complexity, depth of inheritance, lines of code can be calculated within Visual Studio for a given project or solution. From these metrics the most impotant one is maintanablity index which derives from Halstead Volume (another internal metrics), cyclomatic complexity and lines of code. Maintanability index between 0 and 9 is considered to be Red, between 10 and 19 is Yellow and above 20 is Green.

With that said, even midsized development shops interested in improving code quality are faced with these questions:

  • How do we identify code with low maintainablity index across multiple projects
  • How can we see the trends and KPIs (metrics change over time and between branches)
  • How can we effectively report and share the metrics

To deal with some of these issues Microsoft has been providing code metrics power tool which produces XML for a given target. In order to connect the remaining dots I developed code metrics loader utility to load code metrics into a warehouse-like database:

The metrics can be reported on or drive population of SSAS cube:

-- Red / yellow members
SELECT dmt.Tag, dmo.Name as Module, dt.Name as [Type], dm.Name as Method, fm.MaintainabilityIndex, fm.LinesOfCode, fm.CyclomaticComplexity  
FROM FactMetrics fm  
JOIN DimMember dm ON dm.MemberId = fm.MemberId  
JOIN DimType dt ON dt.TypeId = dm.TypeId  
JOIN DimNamespace dn ON dn.NamespaceId = dt.NamespaceId  
JOIN DimModule dmo ON dmo.ModuleId = dn.ModuleId  
JOIN DimTarget dmt ON dmt.TargetId = dmo.TargetId  
WHERE fm.DateId IN (SELECT TOP 1 DateId FROM DimDate ORDER BY DATETIME DESC)  
AND fm.MaintainabilityIndex < 10  
ORDER BY fm.MaintainabilityIndex;

-- Module over time
SELECT TOP 10 dd.[Date], fm.MaintainabilityIndex, fm.CyclomaticComplexity, fm.ClassCoupling, fm.DepthOfInheritance, fm.LinesOfCode  
FROM FactMetrics fm  
JOIN DimDate dd on dd.DateId = fm.DateId  
JOIN DimModule dmo on dmo.ModuleId = fm.ModuleId  
WHERE dmo.Name like '%WebServices.dll'  
ORDER BY dd.[Date] DESC

-- Module over time MDX
SELECT  
{[Module].[Hierarchy].[Module].MEMBERS - [Module].[Hierarchy].[Module].[Unknown]} ON ROWS,
{[Date].[Month-day].[Day Of Month].MEMBERS - [Date].[Month-day].[Day Of Month].[Unknown]} ON COLUMNS
FROM [StatsView]  
WHERE {[Measures].[Maintainability Index]}  

I populate database with this PowerShell script:

$powertool="C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\FxCop\metrics.exe"
$loader="C:\My\CodeMetricsLoader\bin\Debug\CodeMetricsLoader.exe"
$metrics="metrics.xml"
$connection=@'
"Data Source=ql01;Initial Catalog=CodeStats;Integrated Security=yes;"  
'@

$targets = @(
    "C:\My\WebServices\WebServices.dll"
    "C:\My\Account\bin\Debug\Account.dll"
)

foreach($target in $targets)  
{    
    .$powertool /f:$target /o:$metrics
    .$loader --f $metrics --c $connection --t "master"
}