Evolutionary design of interfaces and the IClass pattern

My previous post on the IClass pattern where, for example, class Tree has an interface ITree and Tree is the only class implementing ITree, sparked a small debate in the comments section on whether creating an interface for every class
  • affects coupling (I don't think it makes a difference)
  • makes it easier to design in an evolutionary manner (I think it actually runs counter to principles of evolutionary design)
A significant number of my readers disagreed, so I started to respond in a comment - but it grew so big I figured I might as well make a post of it. I'm looking forward to feedback so I can refine my understanding and correct any misconceptions I may have had.

BTW, here are the exceptions I'd mentioned where creating an interface per class makes sense:
  • you are developing a framework where you may have just one class, but third parties may wish to implement functionality in the future in ways you can't predict
  • you are forced to do so by a framework you're using like an IoC framework or certain mocking frameworks
  • and a new one from refactoring.com: several clients use the same subset of a class' interface
Basically, I'm trying to say that we're talking about OO in isolation without limitations imposed from outside. So...

If there is a 1:1 mapping between a class and an interface, then using the interface instead in no way increases or decreases the level of OO coupling. Indeed, you try to decrease coupling for a reason, right? It's so you can polymorphically swap classes in and out at runtime without disturbing higher layers of abstraction. When there is no polymorphism (just one class), what benefit do we get?
Only if there are two or more classes implementing that interface, or multiple clients seeing the same subset of a classes' interface does creating and using the Interface instead of the implementors make a difference to the way you'd write and think about your code.

When you define an interface for a single class you're imposing a perception of the ways in which higher layers of abstraction will see that class in the future, without actually knowing what behaviour it will share with its sibling classes, because the siblings don't exist yet. The idea is to wait until a sibling exists, then extract an interface based on the way the two classes are being seen by higher layers. That is how I evolve interfaces at the moment.

If there is ever any need to introduce a second class which does the same things but in a different way, then I identify the common bits and run the 'extract interface' refactoring. This creates an interface signature based on how I'm actually using the interface as opposed tempting me to predict how it may be used in the future.

Otherwise, I cannot think of a single instance where I would use the class any differently from the interface in my code. Of course the interface makes stubbing easier, but that's a limitation of Java and is easily solved by using a good mocking framework. The test is to see if you need interfaces in other languages in the same sort of situation. Does the lack of interfaces in Ruby increase coupling? Not really. Then why should it make a difference in Java?

Can someone give me an example where creating an interface for a class (with a 1:1 mapping) makes a difference to the way you write your code, without any external influences (including external frameworks)?
Post a Comment