From now, all types added should respect basic quality principles
Runs only in diff mode (baseline defined), on types added since baseline (easily modified to also match refactored types).
Matched types violate basic quality principles: too many methods, too many fields, or too many types used — often symptoms of too many responsibilities. Constructors, property/event accessors, constant and static-readonly fields, and enumerations are not counted.
Matched types violate basic quality principles: too many methods, too many fields, or too many types used — often symptoms of too many responsibilities. Constructors, property/event accessors, constant and static-readonly fields, and enumerations are not counted.
How to fix
Split the type into smaller types implementing the same logic together.
Constant 10 minutes Debt: the fix effort is already estimated by the Code Smells rules. But severity is High, higher for new types: the time to improve them is now, before the next production release.
Constant 10 minutes Debt: the fix effort is already estimated by the Code Smells rules. But severity is High, higher for new types: 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 types added should respect basic quality principles</Name>
// <Id>ND1100:FromNowAllTypesAddedShouldRespectBasicQualityPrinciples</Id>
warnif count > 0
// Gather typesMoved, types whose parent namespaces changed since baseline:
// removed on one side and added on the other, such a type is not a new type.
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()
from t in JustMyCode.Types where
// Only match types added since Baseline.
// Uncomment this line to match also refactored types since Baseline.
// (t.WasAdded() || t.CodeWasChanged()) &&
t.WasAdded() &&
// Don't match types moved from one namespace to another
!typesMoved.Contains(t) &&
// Eliminate interfaces, enumerations or types only with constant fields
// by making sure we are matching type with significant code.
t.NbLinesOfCode >= 50 &&
// Optimization: Fast discard of non-relevant types
t.Fields.Count() >= 7 &&
t.Methods.Count() >= 18
// Count instance fields and non-constant static fields
let fields = t.Fields.Where(f =>
!f.IsLiteral &&
!(f.IsStatic && f.IsInitOnly))
// Don't match these methods
let methods = t.Methods.Where(
m => !(// m.IsConstructor || m.IsClassConstructor || // ctor/cctor not enumerated through IType.Methods
m.IsGeneratedByCompiler ||
m.IsPropertyGetter || m.IsPropertySetter ||
m.IsEventAdder || m.IsEventRemover))
let typesUsed = t.TypesUsed.ExceptThirdParty().ToArray()
where
// Low Quality types Metrics' definitions are available here:
// https://www.ndepend.com/docs/code-metrics#MetricsOnTypes
( // Types with too many methods
fields.Count() >= 7 &&
methods.Count() >= 18 &&
// Complex Types that use more than 40 application other types
typesUsed.Length >= 40
)
select new {
t,
t.NbLinesOfCode,
t.MaintainabilityIndex,
instanceMethods = methods.Where(m => !m.IsStatic),
staticMethods = methods.Where(m => m.IsStatic),
instanceFields = fields.Where(f => !f.IsStatic),
staticFields = fields.Where(f => f.IsStatic),
typesUsed,
// Constant Debt estimation, since for such type rules in category "Code Smells"
// accurately estimate the Debt.
Debt = 10.ToMinutes().ToDebt(),
// The Severity is higher for new types than for refactored types
AnnualInterest= (t.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 types added since baseline
// (easily modified to also match refactored types).
//
// Matched types violate basic quality principles: too many methods, too many
// fields, or too many types used — often symptoms of too many
// responsibilities. Constructors, property/event accessors, constant and
// static-readonly fields, and enumerations are not counted.
//</Desc>
//<HowToFix>
// Split the type into smaller types implementing the same logic together.
//
// Constant 10 minutes Debt: the fix effort is already estimated by the
// **Code Smells** rules. But severity is **High**, higher for new types:
// the time to improve them is **now**, before the next production release.
//</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