Do not start with an Interface

A few years back when I first started reading about design patterns, refactoring, OO principles etc. I got it into my head that I should "Always program to an interface not an implementation". So whenever I needed to create a new class/abstraction I used to start of with an interface IThis, IThat etc. over a period of time I saw that most of my interfaces were only ever implemented by one class. This started becoming a pain to maintain as adding a new method meant that the method needed to be added to both the interface and the implementation class, further since there was only one implementation of the interface some developers started substituting one for the other and freely casting between the interface and the implementation. This became a source of constant code review changes and eyesores in code, with some methods expecting interfaces and others expecting the implementation class. Of course with strict code reviews we would never have got into this situation, but I've been working in startup companies all this time where getting something out there to earn $$$ has much higher priority than clean code.

Over the last few months I had to introduce some new features into our product which required that an abstraction that previously only had one implementation should now have 3, this was one of the cases where the class did not implement an interface. Contrary to what I had expected, refactoring the class and extracting an abstract class from it which was then subclassed by the different implementations lead to a very clean and satisfying design. This experience has taught me that unless you are writing code that interacts with something that is not under your control (a component or library for e.g.) it's never a good idea to start with an interface.

On the other hand another feature that required extending an interface that was already defined became a big mess as a lot of the methods did not have a reasonable implementation under the new scheme and had to throw NotImplementedException's. It was also difficult to refactor the interface as there were a huge number of dependencies. This could have been avoided if the Interface had been extracted on a need to need basis, further this would have lead to much more granular and cohesive set of interfaces rather than one huge bloated interface.

Starting with an interface on inward facing code means that you are making certain assumptions about how your code will evolve, in my experience these asumptions are almost always wrong and you end up supporting an interface that was never required in the first place. So now I start off with a concrete class and extract interfaces from the class as and when required, this has lead to much cleaner code and reduced the overhead of redundant definitions.

What have been your experiences in this matter?

6 Comments

  • The most common reason to use Interfaces is to mete out functionality so that the functionality doesn't need to follow a class hierarchy. This represents about 90% of my interface usage.

    The other 10% are as marker interfaces and as nouns.

    There's no point in making something like an "IDog" interface. An "IWalk" interface would be more useful. If the interface word isn't a verb, seriously reconsider why you're making an interface.

  • I agree mostly, but I think that the interface design is a good way to design applications when you have a similarity in classes. For example, when you are making your application open to plugins etc.
    But as you say, one should not start with an interface, you should start with a pen and paper :-) and from that derive your needs for an interface based design.

    Just my two cents
    /WW

  • I disagree. I most often start with an interface IF I want to use interfaces for that type, then implement it. You see: the interface is a type definition, not a type implementation, so if you define types first, you can think through the application without actually building it.

    It has been very successful to me :)

    (and of course, agile-fanatics disagree with me, as refactoring sucks with interfaces but IMHO: who cares what agile-fanatics say).

    Interfaces are essential for multiple-type inheritance, and therefore are an essential element in your class model in a single-implementation inheritance environment like .NET.

  • > Always program to an interface not an implementation
    > it's never a good idea to start with an interface

    Both are wrong of course.

  • The most common cause for such Interface rigidity discussed above is when developers create an interface that mirrors your type (much like many COM interfaces), rather than using interfaces to enforce a contract.

    Avoid doing this:

    public class Foo : IFoo
    {
    public DoFoo()
    {
    ...
    }

    public DoBar()
    {
    ...
    }
    }

    And try something more like:

    public class Foo : IFooable, IBarable
    {
    public DoFoo()
    {
    ...
    }

    public DoBar()
    {
    ...
    }
    }

    Where IFooable & IBarable each enforce single finite bits of behavior. IFooable => DoFoo() and IBarable => DoBar()

    That way, when you need to add a new feature or want to refactor, you can simply add your functionality (with an interface or not)) without affecting the existing interfaces. Alternatively, you might decide that your class violates the single responsibility principal and do an extract class refactor so that the IFooable and IBarable behaviors are separate.

    Keep in mind that each interface doesnt "define" your whole class, it simply defines a contract that your class must minimally enforce.

    ~Lance

  • I agree with Frans Bouma

    Sure using Interfaces just because you think one day you'd might want to extend them is not a good reason
    However, Interfaces are essential for other purposes
    For example, Using interfaces you can mock non-existing (yet) classes and enhance the unit tests.
    Another example for using Interfaces is to increase loose coupling (e.g. by techniques like dependency injection - take a look at Spring.net)
    etc.

    Arnon

Comments have been disabled for this content.