Interface segregation principle

The interface segregation principle (ISP) states that clients should not be forced to depend on methods they do not use. The remedy it prescribes is to split fat interfaces into several smaller, client-specific ones, so that each consumer depends only on the operations it actually calls.

A fat interface bundles together methods that serve unrelated clients. Any class implementing that interface must provide every method, even the ones its particular role does not need, which often means stubbing them out or raising "not supported" errors. That bloats implementations and couples every consumer to the full surface area of the interface, even the parts it never touches. The result is accidental coupling. A change to a method that one client uses forces a recompile or redeploy of every other client, simply because they share the same interface type.

The canonical illustration is a Worker interface with work() and eat() methods. A Robot that implements Worker is forced to provide eat(), which it can only stub or raise on, just to satisfy the type. Splitting Worker into a Workable interface for human and robot workers and an Eatable interface for the humans who also take lunch removes the burden. Each client — the scheduler that calls work() and the cafeteria that calls eat() — now depends only on the operations it actually uses.

The principle is stated from the client’s perspective. An interface should be shaped by the code that calls it, not by the code that implements it. Splitting by role produces interfaces that have strong cohesion, since each one groups only the operations a single client cares about. This dovetails with the single responsibility principle, which asks that a module answer to one actor. A client-specific interface does exactly that, with the actor being the client rather than the implementer.

The interface segregation principle is the I in SOLID, a family of design principles for object-oriented programming, popularized by Robert C. Martin.

Trade-offs

Segregation is a matter of granularity, and the wrong granularity cuts in both directions. Splitting per method, one interface per operation, yields interface explosion. Clients depend on a swarm of single-method types and the design gains indirection without insight. The useful unit is the client or role, not the individual method. Two clients that call the same cluster of operations should share one interface. A client that calls a distinct subset should get its own.

Some languages soften the cost of a fat interface without addressing the design problem. Java default methods, C# extension methods, and traits or mixins in Scala and Rust let an interface supply a fallback implementation, so an implementer is no longer forced to stub methods it does not need. But the underlying coupling remains. The client still depends on a type that names operations it never calls, and a change to those operations still ripples to it.

See also

References

  • Martin, Robert C. (1996). The Interface Segregation Principle. C++ Report.
  • Martin, Robert C. (2002). Agile Software Development, Principles, Patterns, and Practices. Pearson.