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.
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.
- 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.
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, ...
- 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.
- 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).
- 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.
- 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.