Avoid interfaces too big

Rule ND1200 Object Oriented Design

Matches interfaces with more than 14 methods, properties or events (a property or event counts as one member). Interfaces should have a single responsibility; overly large ones have too many.

The Interface Segregation Principle (ISP) warns that a large interface used by consumers each needing only specific methods couples those consumers unnecessarily. Large interfaces also lead to larger classes handling too many unrelated tasks.

How to fix

Refactor into smaller single-responsibility interfaces, e.g. split IFoo handling read and write into IFooReader and IFooWriter. A large public interface with many clients may make splitting impactful or unfeasible.

Estimated Debt: linear from 20 minutes (10 methods) to 7 hours (100+), halved if the interface is not publicly visible (only the current project is impacted).

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 interfaces too big</Name>
// <Id>ND1200:AvoidInterfacesTooBig</Id>
warnif count > 0 

from i in JustMyCode.Types
where i.IsInterface && i.NbMethods >= 14 // Optimization  First threshold

// Don't count property or event accessors within the sequence methods
let methods = i.Methods.Where(m => !m.IsPropertyGetter && !m.IsPropertySetter && !m.IsEventAdder && !m.IsEventRemover)
let membersCount = methods.Count() + i.Properties.Count() + i.Events.Count()
where membersCount >= 14
let publicFactor = i.IsPubliclyVisible ? 1 : 0.5
orderby membersCount descending
select new {  
   i, 
   Members= methods.Concat<IMember>(i.Properties).Concat(i.Events),
   Events = i.Events,
   membersCount,
   Debt = (publicFactor*membersCount.Linear(10, 20,   100, 7*60)).ToMinutes().ToDebt(),
   // The annual interest varies linearly from interest for severity Medium for an interface with 10 methods
   // to interest for severity Critical for an interface with 100 methods and more
   AnnualInterest = (publicFactor*membersCount .Linear(
                       10,  Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
                       100, Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes))
                     .ToMinutes().ToAnnualInterest()
}

//<Expl> The *{0}* has {3} members. It is too large and it might indicate 
// the need to split it into several smaller interfaces that each, 
// handles a single responsibility.</Expl>

//<Desc>
// Matches interfaces with more than 14 methods, properties or events (a
// property or event counts as one member). Interfaces should have a single
// responsibility; overly large ones have too many.
//
// The *Interface Segregation Principle* (ISP) warns that a large interface
// used by consumers each needing only specific methods couples those
// consumers unnecessarily. Large interfaces also lead to larger classes
// handling too many unrelated tasks.
//</Desc>

//<HowToFix>
// Refactor into smaller *single-responsibility* interfaces, e.g. split *IFoo*
// handling read and write into *IFooReader* and *IFooWriter*. A large public
// interface with many clients may make splitting impactful or unfeasible.
//
// Estimated Debt: linear from 20 minutes (10 methods) to 7 hours (100+),
// halved if the interface is not publicly visible (only the current project
// is impacted).
//</HowToFix>

Object Oriented Design: all 14 items