Avoid adding instance fields to a type that already had many instance fields
Runs only in diff mode (baseline defined). Lists types that already had more than 15 fields at baseline and got new ones. Such types are hard to maintain, symptom of too many responsibilities. Constants, static-readonly fields and enumerations are not counted.
How to fix
Group subsets of fields into smaller types and dispatch the methods logic into them.
Estimated Debt: 10 minutes per field added. Severity is High: fix these issues now, before such code gets released in production.
Estimated Debt: 10 minutes per field added. Severity is High: fix these issues now, before such code gets released in production.
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 adding instance fields to a type that already had many instance fields</Name>
// <Id>ND1107:AvoidAddingInstanceFieldsToATypeThatAlreadyHadManyInstanceFields</Id>
warnif count > 0
let getFieldsProc = new Func<IType, IList<IField>>(
t0 => t0.Fields.Where(f =>
!f.IsLiteral &&
!f.IsGeneratedByCompiler &&
!f.IsStatic).ToArray())
from t in JustMyCode.Types where
!t.IsEnumeration &&
t.IsPresentInBothBuilds()
// Optimization: fast discard of non-relevant types
where t.OlderVersion().NbFields > 15
let oldFields = getFieldsProc(t.OlderVersion())
where oldFields.Count > 15
let newFields = getFieldsProc(t)
where newFields.Count > oldFields.Count
let addedFields = newFields.Where(f => f.WasAdded())
let removedFields = oldFields.Where(f => f.WasRemoved())
orderby addedFields.Count() descending
select new {
t,
nbOldFields = oldFields.Count,
nbNewFields = newFields.Count,
addedFields,
removedFields,
Debt = (10*addedFields.Count()).ToMinutes().ToDebt(),
AnnualInterest = addedFields.Count().Linear(
1, Severity.High.AnnualInterestThreshold().Value.TotalMinutes,
100, 4*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
}
//<Expl>
// The *{0}* previously contained {1} instance fields
// in the baseline and now has {2} instance fields.
// This increase is indicative of excessive complexity,
// suggesting the necessity of breaking it down into multiple
// smaller implementations, each dedicated to a single
// responsibility.
//</Expl>
//<Desc>
// Runs only in *diff mode* (baseline defined). Lists types that already had
// more than 15 fields at baseline and got new ones. Such types are hard to
// maintain, symptom of too many responsibilities. *Constants*,
// *static-readonly* fields and enumerations are not counted.
//</Desc>
//<HowToFix>
// Group subsets of fields into smaller types and dispatch the methods logic
// into them.
//
// Estimated Debt: 10 minutes per field added. Severity is **High**: fix
// these issues **now**, before such code gets released in production.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Code Smells Regression: all 9 items
- From now, all types added should respect basic quality principles ND1100
- From now, all types added should be 100% covered by tests ND1101
- From now, all methods added should respect basic quality principles ND1102
- Avoid decreasing code coverage by tests of types ND1103
- Avoid making complex methods even more complex ND1104
- Avoid making large methods even larger ND1105
- Avoid adding methods to a type that already had many methods ND1106
- Avoid adding instance fields to a type that already had many instance fields ND1107
- Avoid transforming an immutable type into a mutable one ND1108