Why Flyable and Eater Stay Two Separate Interfaces
Even when every flying bird also happens to eat, merging Flyable and Eater into one interface is a trap. This is the Interface Segregation Principle.
The previous post split flying and eating into two separate interfaces, Flyable and Eater. That split is about to get tested by a tempting shortcut.
The Tempting Shortcut
Suppose, in this zoo, every bird that flies also eats. Crow flies and eats. Pigeon flies and eats. Sparrow flies and eats.
The obvious move looks efficient: why keep two interfaces when one would do? Merge them into a single FlyableEater, with fly() and eat() both inside it.
That's exactly the trap to avoid. It has a name: the Interface Segregation Principle, the I in SOLID.
Why the Merge Breaks Later, Not Now
The merged interface doesn't fail today. It fails on an assumption that only holds today.
Flying and eating aren't related behaviors. One is about movement, the other about consumption. They only look mergeable because, by coincidence, every bird in this zoo happens to do both. That's a fact about this one zoo, not about what flying and eating actually mean.
The moment a new bird shows up that flies but can't eat, say one with damaged digestion, it can't implement FlyableEater. Implementing it means promising both behaviors, and it only has one.
Fixing that means unmerging the interface everywhere it's used, for a mistake that was avoidable from the start.
The Rule: Keep Interfaces Light
The Interface Segregation Principle states it directly: interfaces should be as light as possible. A light interface just means few methods, ideally exactly one.
Two or more methods belong in the same interface only when they're genuinely, logically inseparable, not merely convenient to bundle together. The test isn't "do these things happen to go together right now." The test is "does one of these stop making sense without the other."
Flyable and Eater. Every bird today happens to do both, but flying and eating describe two unrelated capabilities. Nothing about "can fly" implies or requires "can eat."
A Stack interface with push() and pop(). Neither one is a complete stack without the other, they define what a stack is, together.
A List interface follows the same reasoning: add(), remove(), length(), and similar methods all belong together because a list genuinely needs all of them to mean "list." That's a real, structural relationship, not a coincidence that happens to hold today and might not tomorrow.
Ten Interfaces Beat Two Interfaces That Might Break
There's a natural worry hiding in this rule: doesn't splitting everything into single-method interfaces just create a different kind of explosion?
No. Ten independent behaviors need ten small interfaces, one per behavior, full stop. The class-per-combination version of this same problem needed 1,024 classes. A handful of extra interfaces is a different scale of problem entirely, and none of them break when a new bird doesn't fit the old assumption.
Keep reading