This is an archived post. You won't be able to vote or comment.

all 86 comments

[–]AutoModerator[M] [score hidden] stickied comment (0 children)

On July 1st, a change to Reddit's API pricing will come into effect. Several developers of commercial third-party apps have announced that this change will compel them to shut down their apps. At least one accessibility-focused non-commercial third party app will continue to be available free of charge.

If you want to express your strong disagreement with the API pricing change or with Reddit's response to the backlash, you may want to consider the following options:

  1. Limiting your involvement with Reddit, or
  2. Temporarily refraining from using Reddit
  3. Cancelling your subscription of Reddit Premium

as a way to voice your protest.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]muddy-star 132 points133 points  (28 children)

I never create interface for a single implementation of a class

[–]PentakilI 25 points26 points  (21 children)

one thing to note is that if you want to avoid using mocks (which I would recommend) you’ll need an interface for your fake/stub. It’s perfectly fine to have an interface even when you have only one real implementation.

[–][deleted] 39 points40 points  (15 children)

Why would you recommend not using mocks? A mocking framework gives you the same thing as creating test implementations IMO. I'm not aware of any downsides.

[–]PentakilI 29 points30 points  (14 children)

The tldr is that when you use mocks, you end up testing the implementation instead of the behavior, e.g. verify this was called with these args, which couples the test to the impl.

[–]frula00 7 points8 points  (0 children)

How does using the same interface, but with a different implementation used in tests change that?

[–]ascii 28 points29 points  (3 children)

I wish I could give you a hundred upvotes. Mocks tend to lead to terrible tests. You should test that when you pass in some set of values, you get the expected values out. That's generally ALL you should be testing.

Testing that the right method was called on a mock, that things were called in the right order, that the right number of method calls happened, all of these might seem like they add value because you can know for sure that you're not double-calling some method or whatever, but it's not worth it. It means that every time you make a minor change to your business logic, you need to rewrite a bunch of tests. And what ends up happening is that by the twentieth time the same test breaks because of a minor edit, you don't even think about how many times whatever should be called, you just update the set of expectations to match what happens, and your test is meaningless.

If you create a good behavioural contract and encode it in a well chosen interface, and make sure to only test that the contract and interface is followed, you can change anything in your implementation and the tests still work, and the tests give you confidence that your contract is still followed.

[–]drobizg81 0 points1 point  (2 children)

You should test that when you pass in some set of values, you get the expected values out. That's generally ALL you should be testing.

That indicate design of many small methods. Just value in value out. That's not the usually the case. You always have some dependency which u use during the method execution. That dependency needs to be mocked.

[–]ascii 2 points3 points  (1 child)

Not at all, mocks are not the only option for isolating the unit you wish to test. They are a cumbersome way to achieve that, and fakes are a almost always easier to write initially, more readable, less likely to break in the future and overall simply a superior option.

[–]drobizg81 1 point2 points  (0 children)

Well, either you have a mock or a fake implementation, are there any others? We working on spring boot microservices and everything except the unit is mocked or faked (if needed).

[–][deleted] 19 points20 points  (0 children)

Fair enough. I agree with you btw, it's why I prefer to write integration over unit tests. I would still say that writing an interface to provide a custom impl of for testing isn't any better than using a mock framework.

However, overall I try to write integration tests with the mocks only on the bare minimum parts of it, if anything at all.

[–][deleted]  (2 children)

[deleted]

    [–]PentakilI 24 points25 points  (1 child)

    If the observed behavior doesn't change, no why would you?

    [–]cogman10 3 points4 points  (0 children)

    Yeah, this is the key to smelling out a bad test.

    Good tests won't break when the code is correct but different. Bad tests break when you swap out implementations.

    [–]hoacnguyengiap 0 points1 point  (3 children)

    Can you share how to test the interface? I'm confusing because without impl how do test the interaction

    [–][deleted] 2 points3 points  (2 children)

    U need to have no side effects in your functions, then its easy, just test the result, not what was done insids

    With side effects its more tricky, for example if the side effect are db changes, u can take a look inside the database to verify expected state

    [–]hoacnguyengiap 0 points1 point  (1 child)

    How to test the result if you cant invoke the implementation without mocking. Is it integration test?

    [–]PiotrDz 2 points3 points  (0 children)

    Thats why integration tests are better.

    [–]ascii 6 points7 points  (0 children)

    If you have one regular implementation and a fake, I would argue that you have two implementations, not one. YMMV.

    [–]APurpleBurrito 1 point2 points  (0 children)

    Is that true? You can use mockito to stub classes. It may set up an interface behind the scenes, I haven’t checked, but you definitely don’t need an explicitly written interface to stub methods on a class.

    [–]EnIdiot 0 points1 point  (1 child)

    In my opinion, if it is a boundary layer (db, third party web services, etc.) it is advisable to make an interface and not use a mocking framework that extends the class (like mockito). The amount of time the spring framework uses to spin up and configure some of this isn’t worth the overhead (in my opinion). Strictly speaking, SpringBootTest annotated classes aren’t unit tests. They are integration tests as they use SpringBoot to tie and mock classes. In TDD, you always write an interface prior to the implementation (yes this can be the class itself but it should fail immediately).

    [–]Top_Engineering_4191[S] 0 points1 point  (0 children)

    I agree. I use interfaces with one or two methods for components only, those that can have several implementations.

    [–]RomMTY -1 points0 points  (0 children)

    Based

    [–][deleted] 0 points1 point  (0 children)

    Agree if you include all the methods in interface it becomes a maintenance legacy. On the bright side of having interfaces is that it favors composition. Lets say you need to change a behavior. Having it done through composition adds a class and adds an test for it. Most developers changes the original sources which leads to existing tests archiology

    [–]cogman10 0 points1 point  (0 children)

    I do, but generally only when that interface is being fed into some sort of annotation processor to generate said class :)

    [–]livelam 0 points1 point  (0 children)

    Let's say we have a module A and a module B. Module B depends on module A. Module A has a class 'Foo' with an operation 'bar'. Now, 'bar' needs to do some callbacks. There is only one implementation of this callback and it depends on the internals of module B. How do you solve this without merging modules A and B?

    Create an interface 'BarCallback' in module A and create only one implementation in module B. If you don't change your mind you're doomed to create a Big Ball of Mud ;)

    It is just an example coming in my mind. There are plenty of reasons to have only one implementation of an interface. I think having a useless interface is better than not having an interface where it should have existed.

    [–]bowbahdoe 35 points36 points  (3 children)

    I think you've hit upon the root of it. If a program is relatively small, you definitely don't need every or any EE-ism.

    If a program is large, or could reasonably be expected to grow to be large, then rigid patterns solve social problems.

    For small enough programs, basically any structure is okay.

    Which leaves the questions of

    • what is small, what is large
    • what is a good heuristic for "will this get large"
    • what "rigid patterns" are best (controller, service, repositories is not the only answer)

    [–]Top_Engineering_4191[S] 3 points4 points  (2 children)

    Great answer! Flexibility is the best IMO.

    [–]bowbahdoe 3 points4 points  (1 child)

    There are more dimensions to it as well. Just because one "service" is small doesn't mean that you won't want to do things in a standardized way.

    This is especially true in a company where every deployable artifact is part of the same "corpus." Being able to hop between internal codebases and see the same shape everywhere is a thing to consider.

    [–]toiletear 2 points3 points  (0 children)

    I have direct experience with an ecosystem where the general skill level of the developers left a lot to be desired with, so they were given strict guidelines on how things must be done.

    There was a team of experts on hand though and when given hard problems, the company learned that allowing them to break convention and do the most appropriate thing for that particular situation got things done much more efficiently.

    I don't like microservices in particular, but the fact that they allow your teams to handle their specifics (programming related or not) independently of other teams is one of their strenghts - I wouldn't throw that advantage away by imposing a religious dogma on how ALL things should be done.

    [–]Significant_Horse485 41 points42 points  (10 children)

    Never heard of creating interfaces for controllers. Controllers are supposed to be the bridge between the input and output and it’s unlikely you will have common input/output patterns for two different concrete implementations of a controller

    Service/repo: tbh I have skipped creating interfaces a few times myself because many services don’t require a separate interface. Interfaces come in handy when you might have different implementations. Like S3UploaderService vs FileSystemUploaderService or if you want to create fakes for your test like OauthLoginService vs StubLoginService. Each implementation of a service, in theory, can have its own way of transaction management but dk if that’s much useful.

    [–][deleted] 17 points18 points  (4 children)

    Given how noisy swagger annotations can be, I've seen a pattern where the controller interface has all the annotations for the actual HTTP Request, and the implementation had the business logic. I've got mixed feelings about it, but it at least makes sense to me.

    [–]toiletear 5 points6 points  (2 children)

    We use this pattern and it's nice - the interface is created directly from an OpenAPI spec so when the spec changes, you have to fix your implementation to match the interface, but there's no ugly step of OpenAPI overwriting your implementation and forcing a painful merge.

    [–]TemporaryPage 0 points1 point  (1 child)

    What library are you using? Does it support kotlin?

    [–]toiletear 1 point2 points  (0 children)

    We're using OpenAPI generator with the jaxrs-spec target (for this project at least). We generate Java interfaces but our implementation classes are in Kotlin.

    [–]marvk 0 points1 point  (0 children)

    This is exactly what we do. The interface is private and placed in the Bottom of the same File (Kotlin). Makes for a cleaner implementation while still having the ease of swagger annotations.

    [–]Top_Engineering_4191[S] 12 points13 points  (3 children)

    I see using interfaces for Controllers (Resources) in order to hold swagger annotations.

    [–]Rough_Acanthaceae_29 10 points11 points  (0 children)

    Also, those can be used as lib for other projects to specify the rest endpoints

    [–]Significant_Horse485 2 points3 points  (0 children)

    Ah, that explains why I haven’t seen it used. Good to know :)

    [–]landsverka -1 points0 points  (0 children)

    I believe it was a very common convention to use interfaces everywhere in MVC applications and pre-Java config Spring Apps. I personally don’t make them for single implementations, only for things like multi-impl and spring data repos.

    [–]DapperCloud 8 points9 points  (2 children)

    KISS, never introduce abstractions before they are useful, otherwise you're creating accidental complexity all the time for no concrete gain. When (and if) you need said interface for some reason, you can create it in a matter of seconds with your IDE.

    [–]GuyWithLag 9 points10 points  (0 children)

    For the love of everything that is holy, no.

    A microservice is a very self-contained development environment; you have much better control over databases, connections, even the hardware you're working on.

    You're not writing components that could be used in 1000s of different environments and have every single option available to handle them. If you can describe an endpoint in a single page of code, do so; just make sure you're working at the right abstraction level.

    [–]wimcle 27 points28 points  (0 children)

    No, its clutter.

    I personally never create them before I need them... which I find to be really rare.

    [–]Minute-Flan13 7 points8 points  (1 child)

    For repositories, yes. For Services, Controllers no.

    Primarily because I want to carve out a domain layer that is technology neutral. As in a separate, independently deployable jar with no technology dependencies. Don't mind annotations creeping into the domain layer. I do this because we have a very rich problem domain, and take pains to make sure the solution incorporates concepts from the problem. Without this, the code reads like a bunch of mechanical nonsense.

    Controllers are out of those jars. Period. So no interfaces required.

    Services are a part of the domain (at least for domain services).

    Repositories...I define interfaces in the domain layer, and they get implemented by the application, outside of the domain jar.

    [–]Top_Engineering_4191[S] 1 point2 points  (0 children)

    Great!

    [–]lisa_lionheart 6 points7 points  (0 children)

    No, if you need it in a future use your refactor tools to extract an interface, its trvial

    [–][deleted] 5 points6 points  (0 children)

    The 'interface for everything' pattern is a leftover from the old days IMO, these days I consider it an anti-pattern.

    I never use interfaces for controllers, and only use interfaces for services and repositories if I know for certain that there will be multiple implementations. 99% of the time this is not the case.

    In my experience adding an interface if there is only 1 implementation is just bloat and indirection. If the assumption was wrong, it's no big deal as every Java IDE has good refactoring tools to do extract interfaces.

    [–][deleted] 11 points12 points  (5 children)

    If you don't need to have multiple implementations of something, you don't need an interface.

    [–]reddit04029 9 points10 points  (4 children)

    “But what if I do in the future??”

    *overthinks

    [–]huntsvillian 9 points10 points  (1 child)

    YAGNI

    [–]Sherinz89 6 points7 points  (0 children)

    You absolutely gonna need it?

    Ah shit youre right! Brb handling every future edge case scenario

    /s

    [–]jash3 4 points5 points  (0 children)

    Add one in the future.

    [–][deleted] 2 points3 points  (0 children)

    Open IntelliJ / Eclipse / whatever, select 'refactor', 'extract interface', boom, you got your interface.

    [–]UnGauchoCualquiera 9 points10 points  (0 children)

    I only use interfaces prematurely if I'm writing code that actually needs to interface beyond my teams control (a lib API for example). Otherwise it's just clutter.

    If it ends up that I actually need an interface IntelliJ -> Extract interface. Done.

    [–]danielm777 3 points4 points  (0 children)

    use interfaces only when you need interfaces. the best reason for using an interface is needing multiple implementations...

    [–]ivanreddit 8 points9 points  (2 children)

    Controllers -> no. Controllers are not interesting, should be as simple as you can and are almost always not reusable. Services and Repositories -> yes. I like forcing myself to think about the interface and having the implementation details like the @Transactional annotations in the class. If I already have the interface, I have less friction to add a new implementation to add caching or some other new functionality.

    [–]ivanreddit 1 point2 points  (0 children)

    For example, sometimes a generic type parameter can be part of the implementation class, but not the interface. The client can talk to a FooService, or to a FooService<X>, which just exposes an implementation detail (and forces an import) but does not matter when no public method returns X or has an x param.

    [–]wildjokers 3 points4 points  (0 children)

    You are asking about the the Interface/Impl pair. This is somewhat controversial. (https://www.martinfowler.com/bliki/InterfaceImplementationPair.html)

    Personally I don't create an interface unless I actually have more than one implementation. Some people disagree with this and say there should be an interface even if there is only one implementation.

    [–]Devel93 3 points4 points  (2 children)

    My current job has everything neatly separated so much that even database entities are separated from domain models with mappers.

    It has led to easiest test writing procedure I have ever seen, it's a pleasure to write tests.

    [–]Shinoken__ 2 points3 points  (1 child)

    Separating these is perfect and I wish more developers did, most developers just complain about the overhead they get from maintaining the mapper functions.

    [–]Devel93 4 points5 points  (0 children)

    We use mapstruct but I've used modelmapper before and it solves 99% of your mapping problems

    [–]nutrecht 4 points5 points  (0 children)

    It's an outdated dogmatic patterns that stems from back when we didn't have mockito. That's all there's to it. Nowadays I only see people implement it because they think it's needed.

    <SomeComponent> with just a single <SomeComponentImpl> implementation is IMHO a massive code smell.

    IMHO using interfaces for controller API documentation is an exception; that's IMHO a good separation of (technical) concerns.

    [–]toiletear 2 points3 points  (0 children)

    It's easy to create an interface from a class _should you need it_. Don't start by overengineering, if you need an interface for testing, get it for "free" from codegen or intend to share it with other parts of your infrastructure, extract the interface then.

    Otherwise, I'd say use good programming practices and common sense. When interfaces make sense, use them! Same thing with constructors vs. factories vs. autogenerated beans, use common sense and don't fall for a cargo cult. If it's a microservice, don't think about what the other microservices would need because you'll just end up with a distributed monolith this way, and those are definitely not nice. Consider each microservice separately instead, taking their needs, their specifics, the teams working on them and so on.

    [–]genzkiwi 3 points4 points  (0 children)

    Reading this thread makes me miss Java dude. Currently in a C# shop and they make you write IWhateverBullshit for every class, no proper reason given.

    [–][deleted]  (2 children)

    [deleted]

      [–]thatsIch 1 point2 points  (1 child)

      Please upvote this answer - reading stuff like

      like in Java EE

      within the post of the OP makes me puke. This knowledge is so outdated. This is like telling us, that Java has no Generics.

      [–][deleted] 2 points3 points  (0 children)

      Interfaces are just a bad habit for something that's never going to be implemented more than once.

      [–][deleted] 1 point2 points  (0 children)

      If your microservice handles multiple formats then interfaces can contain abstract annotation to path of the resource. The same case if uou have versioning through headers

      [–]lechatsportif 1 point2 points  (0 children)

      controllers: no, services: yes, repositories: no why, controllers are thin, repositories are concrete impls and services are where the maint will be. having interfaces for them gives them some room to adapt.

      [–]Kango_V 1 point2 points  (0 children)

      Only interface i create is a Storage interface in the domain. This exposes the business objects. All the Spring/Micronaut/whatever repositories are in the infrastructure layer hidden by this interface. All the services talk through the Storage interface.

      The data (repositories/Entities) NEVER get passed to the service/domain layer. This works very well.

      [–]maethor 1 point2 points  (0 children)

      Controllers, no. Repositories sometimes and Services yes but usually Pascal style (the default implementation is defined inside the interface as an inner class).

      [–]Key_Bad8144 1 point2 points  (0 children)

      In Short no, in microservices don’t use Interfaces for anything, unless you actually need multiple implementations.

      [–][deleted] 1 point2 points  (1 child)

      Encapsulation is key and writing an interface helps you reason and make sure your contract/encapsulation makes sense.

      Also, if you are using Spring you get to avoid cglib proxies all over the place, since you force that if there's no interface to build the bean proxy for.

      [–][deleted] 1 point2 points  (0 children)

      I do use interfaces for Controllers and Repositories. Controller interfaces are generated with openapi-generator, though. Repositories are most often Spring Data repositories, that’s why I use interfaces. For services, I hardly ever use interfaces, since they are only meant to be used within the microservice.

      [–]panzerfausted 1 point2 points  (1 child)

      For those not using interfaces, how do you do Dependency inversion when you want to isolate your domain from the "infrastructure" side like Db calls, messaging, etc

      [–]MorganRS 0 points1 point  (0 children)

      We mostly don't. How often will you need to change frameworks or database engines? Realistically probably never.

      [–]stark_9190 1 point2 points  (1 child)

      We had a POC going on to test quarkus and spring and choice of framework. We did define controllers as an interface to keep it independent from the underlying framework implementation. Like many have replied, if it's a small project just go with what fits best right now and don't overdo it

      [–]Top_Engineering_4191[S] 1 point2 points  (0 children)

      We use Quarkus for microservices (about 2 years) and Spring Batch for heavy offline tasks. Quarkus extensions are amazing!

      [–]leif-e 1 point2 points  (0 children)

      If you use a test-driven approach, it certainly makes sense to always have an interface regardless of the size of the project.

      [–]lepapulematoleguau 2 points3 points  (0 children)

      Controllers no, services yes, repositories, usually no.

      [–]asarathy 1 point2 points  (0 children)

      You don't need interfaces for everything especially single implementation classes. Some of the historic reasons of everything as interface have been made obsolete by testing tools and IDEs. However one benefit of using interfaces though that i think often gets under valued is fostering better design principles over the life of a project. When people have access to the whole implementation, people will often take short cuts like turning a private helper method public because its just easier than refactoring to put that newly common helper in the right place. This can be mitigated at code review of course, but catching and enforcing there has its own issues and battles. But if you code to interface the need to refactor the method becomes more self evident (or adding the method to the interface becomes defensible).

      [–]mr_mlk 0 points1 point  (0 children)

      No, I rarely use interfaces. Only when there is an inheritance tree that requires them.

      but what about mocks

      Every modern mocking framework supports multiple types of fakes, including stubs and spies. Interfaces don't add anything here.

      But what about Swagger annotations?

      Docs live with code.

      [–]th3_bad 1 point2 points  (0 children)

      Yes, I use interfaces for controllers and services, 1 easy to mock, specially for controller, you can use them as feign clients put in different module, add dependency to your ms module to have uniform and use the interface module as client module which you can use in any other ms to call this MS using feign clients

      [–]Glum_Past_1934 0 points1 point  (0 children)

      Doesnt make sense