A Response To “What Is An Interface” By John Sonmez

this started out as a very lengthy reply to john sonmez’ post on What Is An Interface. There’s enough that I want to say that I think it warrants me posting on my blog instead of blogging in his comment stream.

it’s a good post in general. i completely agree that we are overusing / abusing the interface construct in c# (i’m not a java guy, so no comment there). i have been dong my own exploration of this recently (as evidenced by my own blog posts). however, i think there are a few points of clarification that are needed for john’s post. he hinted around some of them but never quite said them directly. and there are a few things i don’t agree with, too.


Clarifying “Interface” In This Context

to deal with the "interface" of an object does not require an explicit construct. the public methods and attributes (properties in .net language) make up the interface. but "interface" in this context is the explicit interface construct as provided by C# and Java. other languages, like C, C++, Ruby, Python etc. may not provide an interface construct but they do provide an interface to the object.


Interfaces Are Not Strictly “Contracts”

yes, this is a little pedantic and it’s splitting semantic hairs. i’m going to say it anyway.

be careful of using the word "contract" and saying an interface construct means a class "meets certain expectations that other classes can rely on". this crosses over into design-by-contract and we don’t have that in c# (i don’t know about java). an interface may be present in a class, but there is no certainty in the interface implementation. you may receive NotImplementedExceptions. this is bad design and leaky abstractions with lots of principal violations, etc. but it’s the reality that we have to deal with since we don’t have real contracts.

i like how scott bellware describes the interface construct: a protocol. "a convention or standard that controls or enables the connection, communication, and data transfer between computing endpoints" – from wikipedia. it keeps the lines  between design by contract and the interface construct clean.


Header Interfaces and Dependency Inversion

I generally don’t like header interfaces (an interface that describes the entire class implementing it… "class Foo: IFoo"). they are the big problem that john is talking about and i agree with his perspective here.

we can also help resolve the problem of header interfaces by remembering the dependency inversion principle and by using role-specific interfaces (which you talked about already). if ClassA needs some external thing to do work for it, ClassA defines the protocol that it needs. let’s call it IDoSomething. when ClassA needs to change how it communicates with the external piece, it changes IDoSomething and anything that implements IDoSomething changes to match. not the other way around. We don’t change IDoSomething when the implementer changes, forcing ClassA to change how it communicates.

I think Udi Dahan calls this a “role specific interface”, which is a great term for doing interfaces correctly.


DI, Unit Testing, and Abstraction

i am in 100% agreement with john when you say we abuse dependency injection and unit tests as a way to justify excessive amounts of interfaces.  we can partially solve this problem by remembering that testing only requires isolation between parts of the system that need to be verified independently. we don’t have to isolate everything all the time.

but remember: abstraction and isolation do not require an interface all the times. a class is not sealed by default in c# and we can use delegates and even simple data types as abstractions to create testability, at times. of course, this doesn’t negate the problems that john is pointing out. it only gives us a few more options in a few specific scenarios.


Sometimes Isolation Is A Valid Reason For A Interface Construct

this is a very wide, gray area.

there are times when the testability of a system or module is an appropriate reason for an interface construct. the easy scenario in this is to look at external systems like a database, network or file system. it’s obvious that we want isolation from these implementation details. remembering the dependency inversion principle will help us take care of this.

there are times, though, when parts of the same system should be isolated for testing purposes and creating an interface construct (again, using dependency inversion) is appropriate. the typical case for this is when a part of the system is complex, critical, or otherwise needs special attention and must be verified independently of anything that interacts with it, or anything that it interacts with.


In the end…

I agree with the major points john is making. i just wanted to add a few of my own clarifications to give a little larger perspective into some of it. having worked with john for a while now, i doubt that we would disagree on anything important when it comes down to it. whether or not the points i’m bringing up are important… meh, i don’t know. i just felt like getting this out there.

now… this conversation gets even more interesting when we start talking about ruby, python, javascript and other dynamic languages… but that’s an entire book all on it’s own…

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, AntiPatterns, C#, Principles and Patterns, Unit Testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Good post. I agree with you on pretty much all of this.
    Especially the point you make about isolation being a valid reason for an interface construct.

    I didn’t really consider that point when I was writing my original post, but I agree that I would probably justify using an interface there even with only one implementation. For the simple reason of reducing the dependency on an external system.

    Of course there are some other ways we could do that with adapters and wrapper classes, but adding an interface there instead or in addition doesn’t seem like a bad choice to me.

  • Tom Langston

    With all respect, please edit your post to have proper capitalization.

  • Roco

    I agree with you guys, however, neither of you have provided a concrete example of how to reduce the abuse of interfaces that exist solely for the purpose of providing a seam for unit testing. It’s easy to say that interfaces are being abused (quite frankly it’s a limitation of the language, you don’t have the issue in Ruby), but difficult to guide people away from this practice.

    On another note, I agree that occasionally the use of delegates and blocks can help to limit the need for explicit interfaces. However, try replacing all of the interfaces with the delegate approach and see what happens. Talk about reduced readability and increased indirection!

    I’m not disagreeing with your points, just looking for something more practical.

  • @Roco –

    i’m looking for the same thing, really. I haven’t found it yet, in C#. it seems we’re either stuck with the limitations of the language or we are looking at the wrong paradigms for testing (which may also point to language limitations).

    i’m looking… but i’m not finding much.

  • Sometimes you have to sacrifice correct design on the alter of testability. When the objective is to produce working code, testability informs design choices; it doesn’t make the choices bad. Personally I like the results of using interfaces with e.g. MSpec/Moq for BDD but I sure don’t like trawling through my MSpec/Moq definitions to figure out why a test isfailing. Building testability constructs into the language would go a long way to validating discussions about the correct usage of interfaces.

  • Good reminder and some salient points.

    If a class has only responsibility then it’s interface will reflect all of its functionality even its consumer initiated the creation of the class. I’m not sure I see a way around that.

    One other scenario could be when 3rd parties have the ability to literally replace your implementations with theirs (anywhere).

  • Actually, we do have design-by-contract available in the form of Code Contracts. The ability to specify pre- and post-conditions that apply to all implementations is powerful indeed.