148

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?

14
  • 2
    Maybe they were produced from some code generating tool? Commented May 24, 2012 at 15:59
  • 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. Commented May 24, 2012 at 17:17
  • 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
    Commented May 24, 2012 at 18:24
  • 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. Commented May 24, 2012 at 18:37
  • 9
    What is a "service class"?
    – user1249
    Commented May 24, 2012 at 21:28

6 Answers 6

119

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.

16
  • 9
    Just because there's no seeming utility today doesn't mean it has no utility.
    – DaveE
    Commented May 24, 2012 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. Commented May 24, 2012 at 18:34
  • 82
    @DaveE: YAGNI says you're wrong.
    – DeadMG
    Commented May 26, 2012 at 16:10
  • 44
    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. Commented Sep 4, 2012 at 6:48
  • 25
    @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" Commented Jul 26, 2015 at 18:13
124

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.sstatic.net/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.

5
  • 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
    Commented May 24, 2012 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
    Commented May 25, 2012 at 8:28
  • 19
    YAGNI is not universally accepted as a valid principle, even in combination with the supporting practices
    – Oscar
    Commented Mar 12, 2013 at 16:52
  • I guess one might be more productive than gadding about the code finding interfaces and eliminating them. Commented Jan 23, 2015 at 9: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
    Commented Jul 7, 2016 at 7:02
55

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.

2
  • 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
    Commented May 2, 2019 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
    Commented Feb 11, 2020 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!

11
  • 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
    Commented May 25, 2012 at 2:16
  • 27
    The public keyword does an excellent job at exposing a public contract for my classes. Commented Sep 4, 2012 at 6:50
  • 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.
    Commented Sep 4, 2012 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.
    Commented Sep 4, 2012 at 20:31
  • 2
    @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. Commented Jul 23, 2015 at 19:02
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.

2
  • 4
    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. Commented Sep 4, 2012 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
    Commented Apr 29, 2018 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).

2
  • 4
    You are talking in circles. To make your case you need a concrete example. Commented Sep 4, 2012 at 6: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
    Commented Mar 7, 2020 at 10:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.