145

At the company I work at, every service class has a corresponding interface.
Is this necessary?

Notes:

  • Most of these interfaces are only used by a single class
  • We are not creating any sort of public API

With modern mocking libraries able to mock concrete classes and IDEs able to extract an interface from a class with two or so clicks, is this just a holdover from earlier times?

Ahmed Nabil
  • 109
  • 5
Bob Roberts
  • 1,777
  • 2
  • 11
  • 12
  • 2
    Maybe they were produced from some code generating tool? – FrustratedWithFormsDesigner May 24 '12 at 15:59
  • 1
    Whenever I see case like you describe, I expect there to be a doc / comment to justify it, or, better yet, a unit test that demonstrates the need. When there's no such stuff, well I think that's a serious problem – gnat May 24 '12 at 16:16
  • @gnat How can a unit test demonstrate the (lack of) need for interfaces? The test either fails or passes, unrelated to code style or architectural decisions. – Andres F. May 24 '12 at 16:18
  • @AndresF. you'll see it when you need it. I wrote such tests 2 or maybe 3 times. `Class.forName` along with `instanceof`, quite easy - verify that there is expected class and that it implements expected interface. Plus, **naturally**, javadocs explaining purpose of the test – gnat May 24 '12 at 16:33
  • 9
    @gnat - that no more demonstrates the necessity of the design choice than testing that a class implements a "foo" function demonstrates the necessity of that function being called "foo". By writing the tests you describe you're checking that a certain protocol is being implemented, not that this protocol was needed. If, as the OP claims, you could just as easily write the program without the interface your tests would be just as valid or invalid depending only upon the choices made by the architect. – Edward Strange May 24 '12 at 17:17
  • @gnat I remain unconvinced. Your tests don't check whether there are better or cleaner ways to enforce your protocol; they simply test your current implementation. – Andres F. May 24 '12 at 18:04
  • @CrazyEddie I don't know what made you think my test is intended to demonstrate "design necessity" and other high-brow stuff. Failure of the tests I mentioned meant that application will fail, too - with _class not found_ or _instantiation_ error, simple as that – gnat May 24 '12 at 18:22
  • 2
    @AndresF. see my explanation in comment to CrazyEddie; tests simply protect current implementation from being broken (by myself first of all - because when I see in internal API an interface with single implementation, my first instinct is to get rid of that). – gnat May 24 '12 at 18:24
  • @gnat - OK, then I beg you to please make sense of your first comment because I can't make any given this new information (that you're not claiming there should be a unit test demonstrating the need and that the test you described isn't meant to). Otherwise I'm baffled as to what your point must be. Thanks. – Edward Strange May 24 '12 at 18:30
  • @CrazyEddie failure of unit test means failure of application => that "demonstrates the need" to me. If you feel this is not so I am sorry – gnat May 24 '12 at 18:34
  • 2
    @gnat - again then, how do you demonstrate the need to have an interface between two classes rather than coupling them directly? I simply don't see how just checking that a class does implement an interface demonstrates the need for that abstraction. You've claimed that there should be a unit test demonstrating the need for it first. You've yet to make any sense of that claim. – Edward Strange May 24 '12 at 18:37
  • 9
    What is a "service class"? –  May 24 '12 at 21:28
  • @ThorbjørnRavnAndersen a class comprised of multiple related methods and usually sitting between the controller and the dao – Bob Roberts May 25 '12 at 00:20
  • 1
    @gnat and CrazyEddie If you wish to argue this further then please take it to chat. – maple_shaft May 25 '12 at 02:13

6 Answers6

120

Given your question I assume that the reasons for this kind design are not documented.

Unjustified usage of an interface with single implementation is plain wrong since this violates YAGNI. In my experience, this also has been pretty damaging maintenance-wise, mostly because methods implementing interface are forced to be unnecessarily public. After you gather more refactoring experience, you'll probably learn to appreciate modest charm of private and package private access modifiers allowing one to focus attention within a single class / package.

As for undocumented justified usage of this idiom, it is in my eyes about as bad - first of all because it doesn't allow a maintainer to "tell good from bad". As a result, this leaves one between not quite appealing options. Options are, either you keep the questionable public stuff as-is, thus repeatedly decreasing productivity every time you need to change the code, or you make risky changes by blindly "collapsing" the single-implementation into easier to maintain POJO - exposing self to the risk to painfully discover that this is wrong way, that some other (God forbid, remote) module out of your sight expects the interface.

I've been through "revelations" caused by erroneous collapse of single-implementation-interface few times. Each time it has been quite an educative experience but I would not really want to get there again. Thing is, this happens at late testing, at integration or even at user acceptance and rolling back / fixing the mistake made long time ago at this stage is quite cumbersome.


  • An option that shouldn't be left without mentioning is to investigate whether the undocumented use is justified (and, after that, collapse or document respectively) right at the moment you find it.
     
    To me, this one has been quite counter-productive. This approach essentially forces one to go full-round integration testing which is probably one of the most efficient ways to break a flow in the middle of some complicated fix / refactoring.
     
    https://i.stack.imgur.com/tBUBG.jpg

I just couldn't see the practicality... the interfaces are used one-to-one like com.company.service.foo and com.company.service.foo.impl

Well below is about how I typically handle cases like that.

  1. Create a ticket in issue tracker, like "PRJ-123 Undocumented questionable use of interface with single implementation in Foo / FooImpl".
    Add to ticket description or to comment an explanation that this hurts maintainability and point out that without documentation this looks like overengineering. Add a comment suggesting to fix the issue by "collapsing" this into a POJO, for easier maintainability.
  2. Wait for some time just in case if someone comes to explain things. I'd wait a week or two at least

    • If someone explains the purpose, a) put that to the ticket, b) add to Foo javadocs something like purpose of interface explained in ticket PRJ-123, c) close the ticket, d) skip next three steps.
    • Otherwise, ...
  3. Come to team lead or manager to ask what would they think if I fix the ticket as suggested.
    Pick an adviser having sufficient authority to stand the "scream test" in case if suggested fix turns out wrong.
  4. Collapse to POJO as per suggested fix, arrange code review if that's possible (in slippery cases like that it won't hurt to cover your back).
  5. Wait until the change passes the full testing and update the ticket depending on its outcome - add the information on whether the change passed testing or not.
  6. Create and handle a new issue tracker ticket to deal with remaining similar cases based on the outcome of your pilot ticket (PRJ-123): either document the purpose, or collapse to POJO.

gnat
  • 21,442
  • 29
  • 112
  • 288
  • 4
    It is true that methods are forced to be public, but interfaces themselves can be public, protected, package private, or private. I could imagine creating a private interface (nested inside another class) that is implemented by 2 or more classes (also nested inside the same other class). If you are only going to have 1 implementation class, why bother. But a private interface would escape the productivity trap you described. – emory May 24 '12 at 23:59
  • @emory great minds think alike; I am quite huge fan of private / package private interfaces. One thing that makes these particularly great is that one can figure their purpose looking only within class / package – gnat May 25 '12 at 08:28
  • 19
    YAGNI is not universally accepted as a valid principle, even in combination with the supporting practices – Oscar Mar 12 '13 at 16:52
  • I guess one might be more productive than gadding about the code finding interfaces and eliminating them. – user1455836 Jan 23 '15 at 09:50
  • 2
    gaggling has nothing to do with this. Harm done by unjustified usage is for real: methods implementing interface are forced to be unnecessarily public -> as a result, one can not figure their purpose looking only within class / package. Going through whole large project instead of looking into single class or package is quite substantial productivity hit – gnat Jul 07 '16 at 07:02
117

Your company is following the SOLID principles and targeting an interface rather than concrete class adds zero overhead to the program. What they're doing is a very moderate amount of extra work that can pay back volumes when the assumptions that you are making end up being false...and you can never tell what assumption that's going to be. What you're recommending while slightly less work, can cost many, many, many hours of refactoring that could have just been done ahead of time by simply following basic OO design principles.

You should be learning from these guys and consider yourself lucky. Wish I worked in such an environment where solid design was a priority goal.

yannis
  • 39,547
  • 40
  • 183
  • 216
Edward Strange
  • 9,172
  • 2
  • 36
  • 48
  • Oh, I love where I work, I just couldn't see the practicality. I suppose that is just my inexperience though. – Bob Roberts May 24 '12 at 17:31
  • 9
    Just because there's no seeming utility *today* doesn't mean it has no utility. – DaveE May 24 '12 at 18:21
  • 11
    There may be utility already. I don't know if they're doing so, but a single implementation can fulfill many interfaces. If the interfaces are minimized to the least needed functionality for a given kind of client then this enables the code to explain those clients without having to understand a larger interface that's not being entirely used. It can also discourage cross-concept invasion where a client meant to work with the object in one way begins using functionality it shouldn't. A view beginning to use a model's mutable interface for example...probably shouldn't be. – Edward Strange May 24 '12 at 18:34
  • 1
    @CrazyEddie nope, the interfaces are used one-to-one like com.company.service.foo and com.company.service.foo.impl – Bob Roberts May 24 '12 at 22:48
  • 81
    @DaveE: YAGNI says you're wrong. – DeadMG May 26 '12 at 16:10
  • 41
    Whenever I see SOLID used as a reason I cannot help but think there is no justification at all for the design. For surely if there was the respondant would give a more specific reason. – Jonathan Allen Sep 04 '12 at 06:48
  • 3
    `targeting an interface rather than concrete class adds zero overhead to the program` Wrong. Unless you have a really smart compiler (you know... one that can solve the halting problem in the general case), virtual overhead will incur. Even with a JIT compiler, the virtual overhead will be incurred at least once. I'm not saying it won't be negligible, but your statement is outright wrong. -1 because I believe zero overhead means exactly what it says: zero overhead. (I'm assuming "interface" is used in the Java meaning.) – Thomas Eding Jul 01 '14 at 19:12
  • 22
    @Jonathan Same as "because it's best practice" it's broadly equivalent to "I don't know but some guy said it was a good idea" – Richard Tingle Jul 26 '15 at 18:13
  • @ThomasEding: This is a great blog post about the impacts of interfaces on call performance with Java: http://mechanical-sympathy.blogspot.hk/2012/04/invoke-interface-optimisations.html. If we are talking about C++, certainly interfaces are not free. Easiest counterpoint I can think of: STL doesn't use interfaces, but uses "interface-like" contracts. All said, in gigantic corporate software, using interfaces for everything has its advantages. For embedded programming (aerospace, etc.), the overhead may be relevant. – kevinarpe Jul 20 '16 at 08:22
  • 9
    "Every class has a corresponding interface" - I don't think this is how interfaces should be used. Interfaces should define a set of related behaviours, if your interface has many methods etc it is almost certainly in violation of the interface segregation principle. It may be trivial to make an interface but it is not trivial to make a good one. Do any of these interfaces get used elsewhere? Are all their methods always implemented or are there lots of refused bequests? – mark_h Oct 11 '16 at 15:39
  • 5
    What's wrong with just using the concrete class implementation & once you're going to have different implementations with the same API, just extract the interface & do the proper naming? The code base I work with now is full with "XYZService" & "XYZServiceImpl", it's just bloat. – Busata Oct 24 '16 at 08:45
  • 2
    what solid principle is it supporting. i am trying to understand why ? – Manoj Ramanan Feb 21 '19 at 07:55
  • Then, can I firstly do not create Service/ServiceImpl. Then, when needing refactoring, I change `class XService` to `interface XService` and create `class XServiceImpl implements XService`? Will that have any problems? Thanks! – ch271828n Mar 07 '20 at 10:37
  • 2
    How is creating interface for every class is SOLID, I just don't get it. And why in the JDK they don't change String to interface and create class StringImpl ? There isn't any logic create interface so that you follow SOLID principles. – Xoke Mar 09 '21 at 14:49
  • 1
    Interfaces are about architecture design, using them in this unreflected way will most likely fuck your architecture up big times. It's a shame to the software industry that this is upvoted that much. – Eugene May 12 '21 at 17:19
  • That answer should be deleted or more or less edited. People are making a lot of bad decisions base on this statement. Impl is anti-pattern and having it accepted in software engineering exchange is tragic – shutdown -h now Jun 29 '22 at 13:13
53

Here is how Adam Bien think about this question: Service s = new ServiceImpl() - Why You Are Doing That?

That is not only bloat (and the opposite of "Convention Over Configuration" idea), but it causes real damage:

  1. Imagine you get another implementation (thats the whole point of an interface) - how would you name it?
  2. It doubles the amount of artifacts - and significantly increases the "complexity"
  3. It is really funny to read the javadocs on the interface and the impl - another redundancy
  4. The navigation in the IDE is less fluent

and I agree with him.

Maybe your co-workers are still stuck in time with J2EE, because this was necessary when working with J2EE, maybe you can find on the internet old tutorials about hard times in J2EE.

gnat
  • 21,442
  • 29
  • 112
  • 288
Xoke
  • 631
  • 5
  • 5
  • If you distribute different services then you should also be able to name them like that. If you cannot name it differently then cosider it to be an unecessary service beside the existing one. UserService, AuthService etc. Another pretty simple example is the interface List<> in Java. – Anna Klein May 02 '19 at 20:30
  • You don't really have to duplicate comments on the interface and the class, you maybe want to use `{@inheritDoc}` tag. – mneri Feb 11 '20 at 10:10
22

Java interfaces aren't just about mockability (though of course, that is a factor). An interface exposes a public contract for your service, without implementation details such as private methods or attributes.

Note that "public" when using internal services (as in your case) refers to the actual users of said services, including -- but not limited to -- other programmers and internal services!

Andres F.
  • 5,119
  • 2
  • 29
  • 41
  • 2
    The answer is really no more complex than this. Interfaces represent a contract and enable dependency injection and mocking without the excessive and inefficient use of reflection that many frameworks provide for class injection and mocking. – maple_shaft May 25 '12 at 02:16
  • 24
    The `public` keyword does an excellent job at exposing a public contract for my classes. – Jonathan Allen Sep 04 '12 at 06:50
  • @JonathanAllen It still leaves you with non-public clutter. And what if your class implements two different interfaces? _In Java_, interfaces look like the cleanest way of communicating public contracts. – Andres F. Sep 04 '12 at 12:38
  • In Java, abstract interfaces are better than public interfaces because you have already decided to use two of them? That's not much of an argument. Nor does adding "extends foo" do anything to remove "non-public clutter". – Jonathan Allen Sep 04 '12 at 18:31
  • 3
    @JonathanAllen First, all interfaces are abstract in Java :) Second, you're looking at the wrong end: it's not from the implementation where you must remove the clutter, but from the _interface_ itself (i.e. from the "contract"). The implementation is not the contract, the interface is. You aim to keep this contract "uncluttered". It's harder to do this with classes, because you also have your "non contract" methods (private, in your example) which aren't part of the public contract. – Andres F. Sep 04 '12 at 20:29
  • 2
    @JonathanAllen (cont'd) But say your IDE can hide private methods and attributes, effectively providing you with a view of just the public contract. This works if your class implements only one contract, but what happens if the class implements two contracts at once? How can you provide a view of just one contract, but hide the other, effectively "untangling" the contracts? The cleanest way to do this would be keep each contract as a separate interface, precisely the approach you rejected ;) – Andres F. Sep 04 '12 at 20:31
  • 1
    @JonathanAllen In the end, Java interfaces describe _intent_ better than the public keyword. It's very clear that what is available in an interface is what defines the type. In contrast, who knows why a given method is public? Maybe the programmer just forgot to make it private (and you can bet this happens!) – Andres F. Sep 04 '12 at 20:35
  • A class also defines a public contract. You don't need a separate interface class to make consumers depend only on the public contract instead of the implementation. – wrschneider Jul 23 '15 at 18:45
  • @wrschneider Unfortunately Java classes are pretty bad (as in "unclear" and "cluttered") at defining public contracts, which is why `interface`s are preferred. – Andres F. Jul 23 '15 at 18:50
  • 1
    @AndresF. an interface and a class can be equally cluttered or unclear. Simply duplicating the clutter of your method signatures into an interface doesn't buy you much. – wrschneider Jul 23 '15 at 19:02
  • @wrschneider I disagree. Interfaces are less cluttered, since they only expose methods of the contract. There are no implementation details, no private or protected or (accidentally) public methods. An interface simply defines a cleaner contract. – Andres F. Jul 23 '15 at 19:12
12

One possible reason for every service class to have an interface is that it makes interactions with sophisticated frameworks (e.g., Spring, JEE) much simpler. This is because Java can simply generate interceptor objects against interfaces (see java.lang.reflect.Proxy); doing so against concrete classes is far more tricky and filled with some non-obvious caveats when working with multiple different classloaders. This holds doubly true if you work with OSGi, where those service interfaces will end up being loaded from a different classloader from the implementations of those services. That (together with the service discovery fabric) in turn enforces very strong separation between each service and its clients; the clients literally can't break the abstraction.

Be aware that even if an IDE can extract an interface from a class with a single click, it doesn't mean that it's necessarily going to extract the correct interface. Intelligence is still needed.

Donal Fellows
  • 6,347
  • 25
  • 35
  • 3
    I'm not so sure 'sophisticated' is the right word. I think clumsy is more accurate. But if you have already decided to use one of them, then there is nothing to debate. Abstract interfaces must be used. – Jonathan Allen Sep 04 '12 at 18:32
  • "Be aware that even if an IDE can extract an interface from a class with a single click, it doesn't mean that it's necessarily going to extract the correct interface. Intelligence is still needed" I am yet to find an occasion to not to do it automatically by un-marking the method that is not required. – magallanes Apr 29 '18 at 13:15
1

It seems like overhead to use Interface initially.. but later on when we need to extend some functionality these Interfaces help a lot.

If you do only concrete implementation you have to change code implementation a lot.. But by using interface you just need to add one new class which implement the contract of Interface (and you can call new class object from the reference variable of Old interface).

kundan bora
  • 145
  • 3
  • 3
    You are talking in circles. To make your case you need a concrete example. – Jonathan Allen Sep 04 '12 at 06:51
  • Then, can I firstly do not create Service/ServiceImpl. Then, when needing refactoring, I change `class XService` to `interface XService` and create `class XServiceImpl implements XService`? Will that have any problems? Thanks! – ch271828n Mar 07 '20 at 10:40