From now, all methods added should respect basic quality principles

Rule ND1102 Code Smells Regression

Runs only in diff mode (baseline defined), on methods added since baseline (easily modified to also match refactored methods).

Matched methods violate basic quality principles: too large, too complex (many if, switch case, loops…), too many variables, parameters or overloads.

How to fix

Split the method 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.

Constant 5 minutes Debt: the fix effort is already estimated by the Code Smells rules. But severity is High, higher for new methods: the time to improve them is now, before the next production release.

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>From now, all methods added should respect basic quality principles</Name>
// <Id>ND1102:FromNowAllMethodsAddedShouldRespectBasicQualityPrinciples</Id>
warnif count > 0

// Gather typesMoved, types whose parent namespaces changed since baseline:
// the methods of such a type are added on one side and removed on the other, not new.
let typesRemoved = context.CompareContext.OlderCodeBase.Application.Types
   .Where(t => t.WasRemoved()).Select(t => t.Name).ToHashSetEx()
let typesMoved = Application.Types
   .Where(t => t.WasAdded() && typesRemoved.Contains(t.Name)).ToHashSetEx()

// Gather methodsMoved keys: a method removed from a type of the baseline and added, with the
// same name (signature embedded), lines of code and IL size, to another type is relocated
// code (a class split into helpers), not a new method.
let methodsRemovedKeys = context.CompareContext.OlderCodeBase.Application.Methods
   .Where(m => m.WasRemoved() && m.NbILInstructions >= 10)
   .Select(m => m.Name + "|" + m.NbLinesOfCode.ToString() + "|" + m.NbILInstructions.ToString()).ToHashSetEx()

from m in JustMyCode.Methods where

   // Only match methods added since Baseline.
   // Uncomment this line to match also refactored methods since Baseline.
   // (m.WasAdded() || m.CodeWasChanged()) &&
   m.WasAdded() &&

  // Don't match methods in types moved, nor methods relocated to another type
  !typesMoved.Contains(m.ParentType) &&
  !methodsRemovedKeys.Contains(m.Name + "|" + m.NbLinesOfCode.ToString() + "|" + m.NbILInstructions.ToString()) &&

  // Don't match async methods here to avoid
  // false positives because of special compiler tricks.
  !m.IsAsync &&
  !m.IsAbstract &&
 
   // Only match methods with enough statements
  m.NbLinesOfCode > 20 &&    
 
  // Low Quality methods// Metrics' definitions
 ((m.CyclomaticComplexity >= 12 &&   // https://www.ndepend.com/docs/code-metrics#CC
   m.ILNestingDepth >= 4) ||         // https://www.ndepend.com/docs/code-metrics#ILNestingDepth
   m.NbParameters >= 8)             // https://www.ndepend.com/docs/code-metrics#NbParameters

   
   // Don't match methods considered as new because its parameters changed
&& (!m.ParentType.IsPresentInBothBuilds() ||
    !m.ParentType.OlderVersion().MethodsAndConstructors.Any(m1 => m1.WasRemoved() && m1.SimpleNameEquals(m.SimpleName)))

select new { 
   m, 
   m.NbLinesOfCode,
   m.CyclomaticComplexity, 
   m.ILCyclomaticComplexity,
   m.ILNestingDepth, 
   m.NbParameters,

   // Constant Debt estimation, since for such method rules in category "Code Smells" 
   // accurately estimate the Debt.
   Debt     = 5.ToMinutes().ToDebt(),

   // The Severity is higher for new methods than for refactored methods
   AnnualInterest= (m.WasAdded() ? 3 : 1) *
                   Severity.High.AnnualInterestThreshold()
}  

//<Expl>
// The new *{0}* doesn't meet quality standard detailed in other issues.
//</Expl>
//<Desc>
// Runs only in *diff mode* (baseline defined), on methods added since
// baseline (easily modified to also match refactored methods).
//
// Matched methods violate basic quality principles: too large, too complex
// (many *if*, *switch case*, loops…), too many variables, parameters or
// overloads.
//</Desc>

//<HowToFix>
// Split the method 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.
//
// Constant 5 minutes Debt: the fix effort is already estimated by the
// **Code Smells** rules. But severity is **High**, higher for new methods:
// the time to improve them is **now**, before the next production release.
//</HowToFix>

Code Smells Regression: all 9 items