Avoid types with poor cohesion

Rule ND1007 Code Smells

Matches types with Lack Of Cohesion of Methods (LCOM, range [0-1]) higher than 0.84: a poorly cohesive class. A class is utterly cohesive when all its methods use all its instance fields. Only types with enough methods and fields are matched to avoid bias. LCOM metric: https://www.ndepend.com/docs/code-metrics#LCOM

How to fix

Split the type into smaller, more cohesive types implementing the same logic. Right-click a matched type > "Show on the Dependency Graph" to visualize fields usage by methods and plan the refactoring.

Estimated Debt: linear from 5 minutes (low poorCohesionScore) to 4 hours (high).

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 types with poor cohesion</Name>
// <Id>ND1007:AvoidTypesWithPoorCohesion</Id>
warnif count > 0 from t in JustMyCode.Types where 
  t.LCOM > 0.91  && 
  t.NbFields > 10 && 
  t.NbMethods > 10 

  // Don't take account of properties and events accessors and backing fields
  let fields = t.Fields.Where(f => !f.IsStatic && f.ParentProperty == null && f.ParentEvent == null).ToArray()
  let methods = t.Methods.Where(m => m.ParentProperty == null && m.ParentEvent == null).ToArray()
  where fields.Length > 8 && methods.Length > 8

  let poorCohesionScore = 1/(1.01 - t.LCOM)
  orderby poorCohesionScore descending

  select new { 
   t, 
   t.LCOM, 
   methods, 
   fields,
   poorCohesionScore,

   Debt = poorCohesionScore.Linear(5, 5, 50, 4*60).ToMinutes().ToDebt(),

   // The annual interest varies linearly from interest for severity Medium for low poorCohesionScore
   // to 4 times interest for severity High for high poorCohesionScore
   AnnualInterest = poorCohesionScore.Linear(5,     Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes, 
                                             50, 4*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
   
}

//<Expl>
// The *{0}* has a *Lack Of Cohesion of Methods* score of {1}. This means that 
// its methods and fields are loosely related. Identify different responsibilities 
// within the class and split them into separate classes if necessary.
//</Expl>


//<Desc>
// Matches types with **Lack Of Cohesion of Methods** (LCOM, range [0-1])
// higher than 0.84: a **poorly cohesive class**. A class is utterly cohesive
// when all its methods use all its instance fields. Only types with enough
// methods and fields are matched to avoid bias. LCOM metric:
// https://www.ndepend.com/docs/code-metrics#LCOM
//</Desc>

//<HowToFix>
// Split the type into smaller, more cohesive types implementing the same
// logic. Right-click a matched type > "Show on the Dependency Graph" to
// visualize fields usage by methods and plan the refactoring.
//
// Estimated Debt: linear from 5 minutes (low poorCohesionScore) to 4 hours
// (high).
//</HowToFix>

Code Smells: all 10 items