Avoid types too big

Rule ND1000 Code Smells

Matches types with more than 200 lines of code (JustMyCode methods only): extremely complex to develop and maintain. Maybe a God Class: a class controlling too many others, grown into The Class That Does Everything. NbLinesOfCode metric: https://www.ndepend.com/docs/code-metrics#NbLinesOfCode

How to fix

Split into smaller types. Refactoring a God Class takes patience:

- Split the logic into smaller classes (possibly private nested ones the God Class becomes composed of).

- Partition by responsibilities: look for subsets of methods strongly coupled with subsets of fields.

- If mostly logic (few states), consider static classes with only pure static methods (no field read/assigned), which are easily testable.

- Keep the God Class interface at first, delegating to the extracted classes, until it is a pure facade; then keep or discard it.

- Write tests for each method before extracting it.

Estimated Debt: linear from 1 hour (200 loc) to 10 hours (2.000+ loc). Static types with no mutable fields cost less: their static methods are easily moved between types.

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 too big</Name>
// <Id>ND1000:AvoidTypesTooBig</Id>
warnif count > 0 from t in JustMyCode.Types where 

   // First filter on type to optimize 
   t.NbLinesOfCode > 200 
   // # IL Instructions is commented, because with LINQ syntax, a few statements can compile to hundreds of IL instructions.
   // || t.NbILInstructions > 3000

   // What matters is the # lines of code in JustMyCode
   let locJustMyCode = t.MethodsAndConstructors.Where(m => JustMyCode.Contains(m)).Sum(m => m.NbLinesOfCode)
   where locJustMyCode > 200

   let isStaticWithNoMutableState = (t.IsStatic && t.Fields.Any(f => !f.IsImmutable))
   let staticFactor = (isStaticWithNoMutableState ? 0.2 : 1)

   orderby locJustMyCode descending
select new { 
   t, 
   locJustMyCode, 
   t.NbILInstructions,
   t.Methods, 
   t.Fields,
   
   Debt = (staticFactor*locJustMyCode.Linear(200, 1, 2000, 10)).ToHours().ToDebt(),

   // The annual interest varies linearly from interest for severity major for 300 loc
   // to interest for severity critical for 2000 loc
   AnnualInterest = staticFactor*(locJustMyCode.Linear(
                          200,  Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes, 
                          2000, Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
}

//<Expl>
// The *{0}* has {1} statements considered as handcrafted code.
// This is too large suggesting the need to split it into multiple 
// smaller implementations, each dedicated to a specific responsibility.
// </Expl>

//<Desc>
// Matches types with more than 200 lines of code (**JustMyCode methods
// only**): extremely complex to develop and maintain. Maybe a **God Class**:
// a class controlling too many others, grown into *The Class That Does
// Everything*. NbLinesOfCode metric:
// https://www.ndepend.com/docs/code-metrics#NbLinesOfCode
//</Desc>

//<HowToFix>
// Split into smaller types. Refactoring a *God Class* takes patience:
//
// - Split the logic into smaller classes (possibly private nested ones the
// *God Class* becomes composed of).
//
// - Partition by responsibilities: look for subsets of methods strongly
// coupled with subsets of fields.
//
// - If mostly logic (few states), consider static classes with only pure
// static methods (no field read/assigned), which are easily testable.
//
// - Keep the *God Class* interface at first, delegating to the extracted
// classes, until it is a pure facade; then keep or discard it.
//
// - Write tests for each method before extracting it.
//
// Estimated Debt: linear from 1 hour (200 loc) to 10 hours (2.000+ loc).
// Static types with no mutable fields cost less: their static methods are
// easily moved between types.
//</HowToFix>

Code Smells: all 10 items