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)?

12 comments:

Anthony Williams said...

> 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

My latest blog entry on
Using Interfaces for Exception Safety in Delphi covers just such an example. In Delphi, uses of an interface are reference counted, whereas uses of a plain class are not.

WolfDancer said...

Great blog post. Having had argument like that for more than once in real life, I really admire your bravery. :)

The delphi example is interesting. I am totally ignorant here but why cannot delphi do it for class reference as well?

Nirav Thaker said...

I agree with the folk who commented on last entry, I was tempted to comment the same point (but I don't repeat) that for interview submission this might be a good-enough judgment...

As for real life apps, I've seen enough bad-bad code, I even found GOD classes (I mean it, 12k spaghetti LOC in a big fat class) but not IWhatever over engineering so far...

rams said...

In the scenario you describe, I agree that there is no need to create an interface just for the sake of it.

This may be academic, but, implicitly, all classes have an interface. I think in VB6 this happens "magically". An interface is a kind of declaration of what the class is capable of. A contract. Hey look at me, I am a class and I offer these features. By declaring an interface you make that contract or intent explicit. But then you are just writing more code when it may not be necessary.

Sendhil said...

You might also be interested in a netobjectives.com streamzine 'Encapsulating Construction'. It also happens to talk about programming to interfaces. I have posted a summary of the streamzine. I used it for a presentation on where to draw the line with 'Program to an Ineterface' not an implementation. It can be found here http://sendhil.spaces.live.com/blog/cns!30862CF919BD131A!852.entry

Sidu said...

@ramesh,

Exactly my point! Because VB doesn't have an 'interface' keyword does not mean that interfaces don't exist, it's just that all classes define an implicit interface.
And this is true for any OO language. Creating an explicit interface over the implicit one is therefore redundant.
Damn, but you expressed what I was trying to get at in such a clear way...

Jeff Santini said...

You said it yourself that a 1:1 mapping of class to interface is pointless as regards decoupling and OO design.

Interfaces don't exist to benefit the implementer. They benefit the client of implementer. And as a client I probably want an interface that does two or three things. I may be using a class that does 10 things to achieve my goal. In that situation I have an interface of three methods that a 10 method class implements. That 10 method class may also implement 5 other interfaces but as the client I don't care.

Too many people see problems with using interfaces because they are looking at them from the perspective of the service and not the client.

By the way a client doesn't care if there are one or 100 implementers of an interface, so again, from the client perspective you don't create an interface because a couple of classes do the same thing, you do it because the client needs to express its needs. It does this via an interface.

Ajit Balan said...

"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 is a point I totally agree with. Apart from the three points that Sidu has mentioned in his post one can always extract interfaces in a progressive way when required.

Anthony Williams said...

Wolfdancer: The delphi example is interesting. I am totally ignorant here but why cannot delphi do it for class reference as well?

I guess Delphi doesn't do it for plain class references for historical reasons, so as not to break backwards-compatibility. Initially, Delphi didn't have exceptions, so it wasn't too bad to have to explicitly Free objects.

Delphi interfaces are modelled after COM, and can be used as COM interfaces if you specify a GUID, so they had to add the reference counting for those.

Sriram said...

I, for one, love interfaces, and I think that having explicitly defines interfaces is a good idea. But that's probably because I have delivered frameworks for years to customers who wanted the flexibility of specifying implementations at component assembly time or even at run time.

When you compile VB6 components, VB6 generated an interface, and does a whole lot of magic for you. But it sees to it that everything is interface compliant.

I believe that at least for coarse grained components, one should code to interfaces. Just because the original coder cannot think of an alternative implementation at the moment does not necessarily mean that the customer would not have an alternative implementation at a later date. Try telling a customer that he would have to pay you for code changes because you didn't think it necessary for him to have the flexibility to specifying his own implementations.

Again, I write all the above based on my experiences of developing components and frameworks. All this new-fangled "do the simplest thing possible - and let the customer pay us for our short sightedness" is something that I'm hope to never get used to.

rams said...

Sidu, thanks for the compliments. The credit for asking the question, no, for being audacious enough to raise the issue should go to you. Often times, we get so caught up in developing solutions, that we fail to step back and think about why we do some of the things, like create mandatory exlicit interfaces for all classes. I'am reminded of the story of a woman cooking pot-roast and cutting off the ends before placing the roast in the pan. Her daughter asker her, mommy why do cut off the ends? The mom said, honey, I don't know. That's how my mother did it. So they went to the mommy's mommy and asked her why she cut off the ends. She too said her mommy did it, so she just followed it. Then they asked the grand old lady who started it all. She said, Oh, I did that because I had a smaller pan.

Marko Schulz said...

Actually, even the ubiquitous "in frameworks interfaces are very useful" has to be taken with a grain of salt. Just listen to the experience of the eclipse folks. Nowadays they use the following as a rule of thumb:

Use abstract classes instead of interfaces for non-trivial types if clients are allowed to implement/specialize

Why? Because they learned the hard way, that interfaces in Java actually make API evolution very hard. Changing a once published interface is virtually impossible without breaking your clients code. Changing abstract classes still has pitfalls but is much easier.

In many cases (this is where the "non-trivial" comes in) the restriction that you can only inherit from a single class hinders you much less than the restrictions that come from an interface.

They had to use many tricks to still be able to evolve some of the published API that used interfaces (Wiegand’s device, I*Extension2-Interfaces and others).

Some stuff can be found in the following links, but if you get the chance to visit one of them talking about this on an event, listen closely. They have a lot of experience.

http://wiki.eclipse.org/images/8/8c/Eclipse_API_Stories.pdf
http://wiki.eclipse.org/images/e/ee/Designing_Eclipse_APIs.pdf
http://wiki.eclipse.org/index.php/Evolving_Java-based_APIs