Thursday, October 9, 2008

Please Hold on the Interfaces

I just got my first Notable Question badge over on stackoverflow.com for what seemed to turn into a rather controversial question. At the time, I was just ranting based on a question I had just read where all the answers suggested the use of an interface, when it didn't really seem to need one. Even more egregious, the interface was basically being proposed just to support testing.

To spare you a little reading, the basic premise of my question was: interfaces are overused, and it sucks when they are being overused, so what is it I'm missing, if anything?

This got some people to go NUTS over it! I mean, literally these people went wildly crazy, spouting nonsense... listen to this one, which was probably one of the worst responses I saw:

An issue with favouring mocking (or any kind of runtime substition) through subclassing, rather than through an interface, is that you can only override the behaviour of virtual members.

Invoking a virtual member requires an additional level of indirection via a Vtable and is slower than a final member. Whereas using an interface adds a compile-time overhead, but using virtual members adds a runtime overhead to every member invocation.

Surely, adding an interface **just to support mocking** is far preferable to slowing down your entire app **just to suport mocking**?

My preference, therefore, is to favour 'final by default'.



Talk about premature optimization!!!! This guy wants to avoid polymorphism because of the runtime costs?!?!? I can't believe how STUPID people can get sometimes! I mean, seriously! I try not to get angry when I'm on the Internet, because flame wars and trolling gets us nowhere, but c'mon now. A v-table call is going to be... what... nanoseconds? Even faster? So small we can't even reliably measure it??? And he thinks he has a net gain by avoiding that cost? I sure wouldn't want to be the one maintaining HIS code!

OK, I'm getting off topic. Interfaces. Those things that pretend to be a class, but have no details whatsoever. I don't mind them. Sometimes they can be quite helpful. However, like all tools, we must stop and analyze why we are going to use the tool, and what will we gain by doing it. If you pound on a screw with a hammer, you might just get it in there, but did you go about it the best way?

There are times when interfaces make a lot more sense in places they don't seem to belong, such as perhaps frameworks... though this guy rightfully pointed out that they also lock you in and restrict change, especially in frameworks (where you can't control who has implemented it).

So here's my biggest beef with interfaces: using one when you have a single implementation class.

That's it. That's the single most spine-curling, eye-gouging use of interfaces that will make me want to vomit all over you if you suggest it.

If you are a lover of interfaces, this may come as shocking news (as I sadly found out). Why is it so bad? You get to increase testability, right? You make your class more extensible, right? You are programming to an interface, right?

WRONG! No, no, no, no.... NO NO NO!

Testability

First of all, testability has nothing to do with whether you have an interface or not. It has to do with whether or not the dependencies you have in your class can be mocked out and altered so that you can ensure that the class works properly regardless of what those dependencies spew at you.

For example, let's say you have an object that represents a customer, which is represented in the database. Perhaps one of the worst things you can do is load the data for that object from the database from within the constructor. At this point, you can't get around constructing your object without depending on the database. Now, if you want to write a test for a DIFFERENT class that uses this customer object, you all of a sudden have to have the database up and running. This is bad because it makes the test a lot more complicated than it needs to be.

Now, if you are in the Interface Camp, you might be thinking... hah! If you define an interface for that class, you can get around that dependency! This is true, but it's also the easy way out. Singletons are also the easy way out to a lot of problems, but you don't hear many people clamoring for singletons everywhere, do you? The easy way out is oftentimes NOT the clean or best way out. Instead of shrouding your class in an evil interface, just move the database initialization to a protected method that the constructor calls. Now you can override the protected method in subclasses or mock classes and no longer depend on the database!

Extensibility...?

I just don't understand why people think classes are less extensible than interfaces. It just isn't true, damnit!! I've been extending classes left and right when I see the need, and I have never had a problem. The trick is, again, to avoid dependencies.

If you are doing something that can't be changed in a subclass, you might be doing something wrong. The constructor is the first place to look... is there behavior in there that does something that might be unwanted in an alternate version of this class? Is there a static initializer that is doing something fundamental to the class that can't be changed in a subclass? As long as you have only virtual methods (believe me, the "performance hit" is worth it... and it's why I love Java's default virtual and hate C#'s default final), and your constructors and static initializers are clean, you can reimplement the entire class as if it had been an interface all along! It's really not that hard, and if you are active with Test Driven Development, you will find the classes often come out that way anyways.

Programming to an INTERFACE....?!?!

Someone else said it better. I don't remember who, and I don't remember where. What do I look like, google? Find it for your own damn self! Well... the gist is, "programming to an interface" does not mean literally to a programming language construct called an interface... it means programming to a contract between you and users of your class... i.e. the publicly visible methods, fields and constructors agreed upon between you and clients of your class.

Just because "interface" is a keyword in some programming languages, doesn't mean we can't speak about "interface" as an English word used to describe what we are exposing.

Appropriate Uses??

I'm not going to lay out a bunch of rules on when you should use an interface. Deciding what tool to solve a particular problem is often somewhat of an art more than an algorithm, so you really have to look at the problem and just decide for yourself. You may end up using interfaces in an inappropriate time... but hey, we all make mistakes! Refactor it when you find a better way... you got all those tests to deal with it, right?

Without going into too much detail, I think a good rule of thumb for when to use an interface effectively is to use it when the thing you are trying to build doesn't lend itself to a default implementation, or you literally HAVE to do it... such as the case when you absolutely need to extend 2 classes (pick one, and extract an interface). However, there can be ways around needing the interface in these cases, but if the interface is cleaner, go for it.

You WILL Regret it Later!

No, you won't, but some claim you will, like this guy:

Sure, sometimes you may not ever have an alternate implementation of ISomeFoo in which case it might have been a waste for that particular component. But if you ever DO need to have an alternate implementation, going and changing those 50 references to concrete PetrolSomeFoo to concrete HydrogenSomeFoo will hurt really bad, especially if someone of the changes involve other applications or integration scenarios.

So, my argument is to let the IDE do the work for you. Extracting an interface and replacing all references is not all that hard of a task, especially given the help of a good IDE. If you are developing a framework where you don't control client code... this is one of the few cases where more interfaces might make sense, unless you have the balls to break backwards compatibility. If you have the ability to only use a tool when you need it, I say save on using that tool unless it really solves your immediate problem cleaner than other solutions.

Finish Already!

So the next time you reach for the interface keyword, stop and consider to yourself... is this really the best solution? Am I really solving this problem cleanly and elegantly with interfaces, or am I just hacking around a problem without considering how else I might solve it?

No comments: