25 Feb 2012

One hundred and one interfaces and implementations

In recent years there has been a surge of blogs and posts discussing design patterns, anti patterns and, in general, how to design your code well. It is great to see so many passionate developers chatting about how they can be creating code that is decoupled, cohesive and just easy to use. Design patterns make it really easy to jump into someone else's code and immediately know what is going on. It makes it faster and easier to know what is going on under the hood. When you get to a statement like this

public MyBuiltClass doSomething(String name, String address) {
  // some code....
  return myBuiltClassBuilder.build(name, address);
}

you don't have to dig through the the MyBuiltClassBuilder to figure out what is going on. But there is a difference to having read a book like Elements of Reusable Object-Oriented Software and understanding the concepts and applying them in the real world. One design pattern that everyone advocates, is to
Program to an 'interface', not an 'implementation'. GoF
and with this statement we can quickly go down the wrong path. Now, the rules to this can vary as to whether your API is publicly exposed or not but what we need to understand is that you don't need to provide a interface for every class that is created. With today's IDEs it becomes less of a problem because they're smart enough to figure out when you have a single implementation of an interface to just display that implementation, but what you can quickly get yourself into is something like the following,


an interface for every implementation. When this begins to happen in large projects, it can be a nightmare for someone who is onboarding to learn your code and traverse through endless interfaces and implementations (and it gets extremely annoying when the implementation class name is just interface name + "impl" a little more about this later on). When deciding on whether to create an interface for your implementation consider why you are creating the interface... TO PROVIDE ENCAPSULATION. Encapsulation is a way to hide implementation details from the end user. David Parnas was an advocate of modular systems that were highly cohesive and loosely coupled and said:
We have tried to demonstrate [...] it is almost always incorrect to begin the decomposition of a system into modules on the basis of a flowchart. We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others. David Parnas "On the Criteria To Be Used in Decomposing Systems into Modules"
Based on the information above, it is fair to say a well designed class can provide the same level of encapsulation as an interface. It can hide design decisions and the difficult knowledge required from the end user. So how do we decide whether to create and interface or not? Like any general philosophy, it can be subjective and depend on the scenario but generally consider the points below
  • Are you providing a complex solution to the end user that they really don't need to care about?
  • Do you ever foresee the possibility of making complex changes or having multiple solutions to the same problem?
If you answered yes to both questions then that is probably a good indicator that you require an interface. In the picture posted above, a well designed CRUD class that contains a DAO would most likely provide the level of encapsulation required. An interface for the DAO makes sense if you think that you may at one stage change the storage method from database to disk.

When creating interfaces and implementations remember to name them with something meaningful. Creating an implementation class name by throwing together the interface name with the four letters "impl" at the end does two things.

  1. Shows that the creator probably didn't think about whether or not an interface was needed.
  2. Provides no context of the actual implementation. Going back to what I was saying earlier, having MyObjectDatabaseDAO immediately tells me what is going on and allows the reader to continue without interruption. A class name like MyObjectDAOImpl could mean you are saving it to disk, database, FTP, etc. The point being it isn't helpful.

Obviously there are other reasons to create interfaces, one being to enforce a contract that allows others to provide unique functionality into your own system, but when creating an interface make sure you know why.

2 comments:

  1. I couldn't agree more, especially about meaningful names.

    Impls are usually a sign that there was no real need for an interface yet. It's quite common to hear "but what if we want to create another implementation later on?". If we're not creating a public API, most IDEs can extract an interface in a few clicks... so we'll see when we get there! Chances are the interface will have to change slightly anyway.

    I think this anti-pattern was probably reinforced a while back when only interfaces could be mocked, but it doesn't make sense now that most frameworks happily mock classes too.

    ReplyDelete
  2. Awesome point. I was thinking about this for a while around 8 years (From starting point of my career), why do people write so many interfaces when they write only single implementation. No answer from anyway. But atleast i could manage to find one person who is supporting my point.

    ReplyDelete