Avoid methods too big, too complex

Rule ND1003 Code Smells

Matches methods where ILNestingDepth > 2 and CyclomaticComplexity > 17: hard to understand and maintain, maybe a God Method (The Method That Does Everything, grown by adding ifs instead of new methods). Metrics: https://www.ndepend.com/docs/code-metrics#CC https://www.ndepend.com/docs/code-metrics#ILNestingDepth

How to fix

Split into smaller methods or even new classes. Question each local variable's scope: it may become an instance field of the new class(es). Large switch…case can become types implementing a common interface, polymorphism replacing the switch cases tests. Write tests for each method before extracting it.

Estimated Debt: 20 minutes to 3 hours, linear in a weighted complexity score.

CQLinq source

This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.

// <Name>Avoid methods too big, too complex</Name>
// <Id>ND1003:AvoidMethodsTooBigTooComplex</Id>
warnif count > 0 from m in JustMyCode.Methods where 

   // Don't match async methods here to avoid 
   // false positives because of special compiler tricks.
  !m.IsAsync &&

   m.ILNestingDepth > 2 &&
   m.CyclomaticComplexity > 17 

  let complexityScore = m.NbLinesOfCode/2 + m.CyclomaticComplexity + m.ILCyclomaticComplexity/3 + 3*m.ILNestingDepth

  orderby complexityScore descending,
          m.CyclomaticComplexity descending,
          m.ILCyclomaticComplexity descending,
          m.ILNestingDepth descending
select new { 
   m, 
   m.NbLinesOfCode,
   m.CyclomaticComplexity, 
   m.ILCyclomaticComplexity,
   m.ILNestingDepth,
   complexityScore,

   Debt = complexityScore.Linear(30, 20,    400, 3*60).ToMinutes().ToDebt(),

   // The annual interest varies linearly from interest for severity minor 
   // to interest for severity major
   AnnualInterest = complexityScore .Linear(30,     Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes, 
                                            200, 2*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
   
}

//<Expl>
// The *{0}* has a high *cyclomatic complexity* score of {2} and should be refactored into a set of smaller methods.
//</Expl>

//<Desc>
// Matches methods where *ILNestingDepth* > 2 and *CyclomaticComplexity* > 17:
// hard to understand and maintain, maybe a **God Method** (*The Method That
// Does Everything*, grown by adding *if*s instead of new methods).
// Metrics: https://www.ndepend.com/docs/code-metrics#CC
// https://www.ndepend.com/docs/code-metrics#ILNestingDepth
//</Desc>

//<HowToFix>
// Split into smaller methods or even new classes. Question each local
// variable's scope: it may become an instance field of the new class(es).
// Large *switch…case* can become types implementing a common interface,
// polymorphism replacing the *switch cases tests*. Write tests for each
// method before extracting it.
//
// Estimated Debt: 20 minutes to 3 hours, linear in a weighted complexity
// score.
//</HowToFix>

Code Smells: all 10 items