Avoid types with too many methods
Matches types with more than 20 methods (constructors, property and event accessors excluded): hard to understand and maintain, symptom of too many responsibilities, maybe a God Class (The Class That Does Everything). Types with only constant fields are skipped: many stateless methods is ok.
How to fix
See HowToFix advices of the default rule Types too Big.
Estimated Debt: linear from 1 hour (20 methods) to 10 hours (200+). Static types with no mutable fields cost less: their static methods are easily moved between types.
Estimated Debt: linear from 1 hour (20 methods) to 10 hours (200+). 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 with too many methods</Name>
// <Id>ND1001:AvoidTypesWithTooManyMethods</Id>
warnif count > 0 from t in JustMyCode.Types
// Optimization: Fast discard of non-relevant types
where !t.IsInterface && // Specially handled by the rule 'Avoid interfaces too big'
t.NbMethods > 20 &&
// Require at least a non-constant field
// because it is ok to have a class with many stateless methods
t.Fields.Any(f => !f.IsLiteral)
// Don't match these methods
let methods = t.Methods.Where(
m => !(m.IsGeneratedByCompiler ||
// m.IsConstructor || m.IsClassConstructor || // ctor/cctor not enumerated through IType.Methods
m.IsPropertyGetter || m.IsPropertySetter ||
m.IsEventAdder || m.IsEventRemover))
where methods.Count() > 20
orderby methods.Count() descending
let isStaticWithNoMutableState = (t.IsStatic && t.Fields.Any(f => !f.IsImmutable))
let staticFactor = (isStaticWithNoMutableState ? 0.2 : 1)
select new {
t,
nbMethods = methods.Count(),
instanceMethods = methods.Where(m => !m.IsStatic),
staticMethods = methods.Where(m => m.IsStatic),
t.NbLinesOfCode,
Debt = (staticFactor*methods.Count().Linear(20, 1, 200, 10)).ToHours().ToDebt(),
// The annual interest varies linearly from interest for severity major for 30 methods
// to interest for severity critical for 200 methods
AnnualInterest = (staticFactor*methods.Count().Linear(
20, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
200, Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
}
//<Expl>The *{0}* has {1} methods. This is too many suggesting
// the need to divide it into multiple smaller implementations,
// each focused on a single responsibility.</Expl>
//<Desc>
// Matches types with more than 20 methods (constructors, property and event
// accessors excluded): hard to understand and maintain, symptom of too many
// responsibilities, maybe a **God Class** (*The Class That Does Everything*).
// Types with only constant fields are skipped: many stateless methods is ok.
//</Desc>
//<HowToFix>
// See *HowToFix advices* of the default rule **Types too Big**.
//
// Estimated Debt: linear from 1 hour (20 methods) to 10 hours (200+).
// Static types with no mutable fields cost less: their static methods are
// easily moved between types.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Code Smells: all 10 items
- Avoid types too big ND1000
- Avoid types with too many methods ND1001
- Avoid types with too many fields ND1002
- Avoid methods too big, too complex ND1003
- Avoid methods with too many parameters ND1004
- Avoid methods with too many overloads ND1005
- Avoid methods potentially poorly commented ND1006
- Avoid types with poor cohesion ND1007
- Avoid methods with too many local variables ND1008
- Avoid unmaintainable code ND1009