For the longest time I have thought I was crazy, because I just didn’t see the benefit of programming to an Interface. I agreed it was good from a design perspective, but as an implementation I saw no need to add the extra code for what amounted to zero benefit. I have finally come to the conclusion that a good chunk of people have absolutely lost their mind. I base that conclusion on the fact that I have found smart people that agree with me, to counter the smart people that lost their mind.
What am I talking about? I will cut straight to the point, when the GoF suggested programming to an interface not an implementation in their classic book, I don’t think they meant a Java Interface. Mostly because the book was based on C++ and Java Interfaces weren’t around, but also because I think they are smarter than that.
Like so many things in the Java community, I think they took a really great idea and twisted it until it no longer made sense. I don’t think they do this on purpose, I believe they are just gluttons for theories. But, before I get to far into this rant, let me substantiate this claim with a few points of interest.
- Almost all languages at the time of the GoF publication did not have the notion of an interface as a first class citizen.
- The examples in the book were written in C++ which did not have the notion of an interface, although you can fake it.
- Patterns are supposed to be reusable bits of object oriented goodness, and since all object oriented languages don’t include interfaces as first class citizens it might not be essential to use these ideas.
Now let me switch into argument mode, I agree with the notion of programming to an interface. I admit that doesn’t sound like a very good argument, but hear me out. I will address each of the popular arguments individually, so what are they?
If you don’t use an Interface you are programming to the implementation not the interface.
So the point here is that you should be loosely coupling your classes in your application. When designing your systems you should always think about the interface (coupling) between your components and make sure they make sense. I firmly believe the best way to make a maintainable system is to create loose coupling and high cohesion as a wise man once taught me. But this can and is done in many languages, and at many shops without the need for the Java Interface.
So what am I saying? I am saying if I showed you the following code:
public class BankDelegate {
public void debit(Account account, Amount amount) {
account.debit(amount);
}
}
you would have no idea if account was an Interface, Abstract Class, or Concrete Class. And furthermore, I would suggest that it doesn’t matter. Let’s say my bank only has a single account type. This would work great. Now what happens when I need to add a second account type? I can either create a base class, that both my accounts extend from, or I can create an Interface. Either solution will work, and I don’t need to change the code in my delegate. Which means my interface has remained the same.
That is what it means to program to an interface. Because if I had originally wrote the BankDelegate class like this:
public class BankDelegate {
public void debit(CheckingAccount account, Amount amount) {
account.debit(amount);
}
}
Then my interface is only good for classes that are of type CheckingAccount. So let’s apply the same logic as before. I could write this as an Interface, Abstract Class, or Concrete Class and you would have no idea based on the above code. But of course, had I written it as an Interface it would be loosely coupled, and therefore I would be able to change it extremely easy at a later time…Oh wait, errrrr…It doesn’t make sense for a SavingsAccount to extend Checking account. I need to add a new base class or interface of Account and extend that. It will take the same amount of work to change this to accept a SavingsAccount regardless of what notation I used to create the CheckingAccount type.
Because of that I would argue that programming to an interface is more about thinking about the names of your classes and methods than using a special notation to declare them.
Why would you tie down your domain with unnecessary dependencies?
This is the argument that if I don’t create an interface, I will be importing unnecessary third party dependencies into my domain. The example I have seen suggests if you are creating a store, and you need to keep track of sales, you should create a SalesLedger interface. That way you can create a HibernateLedger that implements the SalesLedger, so as to not couple the Hibernate libraries to your domain. I agree with the idea of not coupling your domain with hibernate, but I don’t see how adding an Interface solves this. Even if I make the Interface I could make it rely on hibernate functionality, especially if it is the first and only implementation I do. Futhermore, the argument seems to suggest that I would have created the class HibernateLedger in place of SalesLedger if I had not created the Interface. That is probably true from the implementation standpoint, but form the interface standpoint, the methods would be identical to SalesLedger, the Interface. Am I missing something?
More importantly however, it is not unnecessary from a runtime perspective, which is essentially the only time you are ‘importing the dependency’ because without the Hibernate classes your code won’t work, no matter how many Interfaces you placed in between.
How else can you change the implementation in the future?
I am sorry, but this is ridiculous? Let’s break this down into what that really means.
1. If you mean changing it at runtime…that has more to do with the strategy pattern and your runtime environment, that a Java Interface. If you needed to change an implementation at runtime, you simply extend the original class, change the behavior you need, and inject your new object.
2. If you mean changing it for a future build…just re-write the code. Will you need the old code? Do you like keeping an archive of all your classes? If you need to change your SalesLedger to use a web service, instead of hibernate, go for it. You wouldn’t be using both at the same time.
So you ask, what if I need the old code in the future? I would say, isn’t that what version control is for.
What if we need to change the parameters in the future?
This is the one that I find most disheartening. The idea here is doing something like this
public void myMethod(IMyParameterInterface request) {
...
}
instead of this
public void myMethod(String param1, Integer param2) {
...
}
Talk about working around language features. What if you need to change the parameters in the future you ask? I don’t know change the parameters. I know, the response is, well then your interface has changed, and you need to go update everyone consuming that interface. Yeah, well guess what you just added a new parameter, that they probably need to send, and if they don’t, you can just overload the method and pass a null, which you would have to check for in your Interface based system as well.
So there you have it…
I recognize that Java Interfaces are essential to the language, because Java is a static typed language, and doesn’t allow multiple inheritance, Interfaces are the only way to create libraries like the collections API. I think it is unfortunate that the word ‘interface’ has been overloaded so much, that in this case it was taken literally becase and Interface type existed, instead of just treating it in the more generic term, of interface between two components or systems.
In conclusion, I hope I have enlightened, and annoyed a few people with this article. And maybe I don’t know what I am talking about, but just incase I haven’t been able to convince you, read this interview with Eric Gamma, I think you will find it enlightening.