C
C#2y ago
Thinker

✅ What's the point of abstracting services as interfaces?

Legitimate question. What's the point of making services into interfaces which you then inject into your endpoints/controllers/services? What are the significant advantages of this over just injecting a concrete class?
92 Replies
Head0nF1re
Head0nF1re2y ago
1) Interfaces force developers to develop according to the specification, less prone to errors. 2) Easier to replace, with an interface you just have to swap the concrete implementation in the DI container. Without it, you would have to replace the types in whatever places you declare it as a type
Thinker
Thinker2y ago
Sure, I get that, but in what circumstances would you actually want to swap concrete implementations?
Head0nF1re
Head0nF1re2y ago
For example, imagine a payment gateway, like Stripe and Mollie. Normally you only use one. You write an interface and you can replace the implementation of Stripe for the implementation of Mollie, or vice-versa
HimmDawg
HimmDawg2y ago
Also, services that implement an interface provide better testability. If some other service depends on an abstraction rather than on a concrete class, you can easily mock that abstraction of the service
Head0nF1re
Head0nF1re2y ago
Or, the typical use of Repository pattern where you write specification that suits whatever database you choose. Tho, in that case EF Core already does that for you but it's still nice to have an interface I guess (you may as well not want to use EF Core 🤷)
Doombox
Doombox2y ago
also you never know when you need another implementation of something, or even to write a concrete class that implements two services generally it's just a good idea to approach it the same way every time, at least you know exactly where you stand even if the interface ultimately ends up adding nothing, actually declaring the interface takes up very little time anyway
Thinker
Thinker2y ago
Fair enough
sibber
sibber2y ago
id argue for not-big personal projects with only a couple of services, its unnecessary youre the only person developing it anyway
Thinker
Thinker2y ago
That's the primary thing I was thinking
Doombox
Doombox2y ago
for smaller personal projects it's very much a case of do whatever you want tbh you're the only one who has to maintain it and the only person to blame for any tech debt in the future
Angius
Angius2y ago
I had a mailer that was using a certain service. Suddenly, they started requiring my address, phone number, shoe size, and favourite hot sauce to continue service. I was able to whip up another mailer using another service, and all I needed to do was swap <IMailer, FooMailer> for <IMailer, BarMailer> Boom, done
Thinker
Thinker2y ago
sure
boiled goose
boiled goose2y ago
also by this you can have an abstractions package with only interfces and models which you can distribute or whatever without having the hassle of all the concrete stuff
D.Mentia
D.Mentia2y ago
I use them mostly to prevent dependencies on specific libraries. Like I'm writing a thing that works with midis, and I can either a. Use Melanchall.DryWetMidi.MidiFile, MidiNote, etc everywhere, and run into a nightmare if it ever stops working right or I want to change to a different library because it's slow or doesn't do async file reads, or b. Make a bunch of my own models, an interface that exposes ways to make and handle them, and an implementation of that interface that uses DryWetMidi without DryWetMidi ever leaving the context of that implementation If I ever wanted to swap to another midi reader, I'd make another implementation that also just translates between that library and my interfaces, none of my logic changes
Yawnder
Yawnder2y ago
An actual use case of mine: I made a tool we're using at work to help migrate clients. It allows, for example, to move things From/To a FileSystem or SharePoint. If we needed it, I could easily implement Blobs for example. It means that the "crawling" logic, and how to read or write in a redundant manner is specific to the media, but the notion of "crawl" and the operation isn't. Just with configuration, I can set the source/destination and it will handle the transfer, filtering, etc., as needed.
Shinyshark
Shinyshark2y ago
Answers to questions regarding abstraction seem illogical until you run into an issue where the solution for it would have been a good abstraction. The issue is that developers tend to over-abstract everything they find the moment they learn about it. Abstractions fit really well into the SOLID principles. If you use a service by itself, you do not specifically need the interface. But if you extract the interface ahead of time you have the ability to swap out later. Whether you do that or not is not as relevant as having the option to do so.
khamas
khamas2y ago
I'm guessing for testing you can more easily mock a service it also offers additional compatibility, meaning you can change the implementation while keeping the same interface
D.Mentia
D.Mentia2y ago
Just remembered another good reason, you can easily extend or override functionality on any given implementation and register your new thing, without having to touch any of the endpoints (which I find mostly useful if some shared package is doing something wrong, I can implement a workaround in our code to show that it works, before trying to go bother another team to put it in the real code)
khamas
khamas2y ago
I tend to use abstract over interfaces a lot of times but my use case is different
Pobiega
Pobiega2y ago
I use multiple implementations of a service that can handle messages of a certain type. Adding a new message type is literally just implementing the interface and the startup/DI system takes care of the rest.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
boiled goose
boiled goose2y ago
that's not true at all for itty bitty small projects you don't probably need abstractions for all the rest it's not as simple as "duh you have only one implementation" you may need the types elsewhere, without the implementations
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Thinker
Thinker2y ago
Most of this question in general was just if it's necessary for a project like mine - a comparatively miniscule project. but thanks for the answer
LPeter1997
LPeter19972y ago
The only actually legit reason I've seen in the wild: testing, passing in mock services instead of real ones People saying they might need another implementation of a service have just fallen into the trap of YAGNI, if it's not really some other provider integration that happens to work with the same interface your existing service does.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
LPeter1997
LPeter19972y ago
Sure, didn't say silver bullet Said legit reason for... well, a reason
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
khamas
khamas2y ago
interfaces are good for things that need different implementations if you do automated mock testing, IDatabase if you have multiple implementations of an ICustomCollection but even then an abstract class can do the job
LPeter1997
LPeter19972y ago
interfaces are good for things that need different implementations
That's sadly a lie in the wild Like we work with 20+ providers And I don't think even any 3 of them can share an interface for reaching out to the service
Thinker
Thinker2y ago
Unless the interfaces are as generic as IEnumerable<T> or something
LPeter1997
LPeter19972y ago
Yes, you can be way too generic and win nothing with the abstraction What ended up working for us is 2 services for each provider integrated and then an aggregator service that is actually uniform. But then you don't need the abstraction again, it's a single "implementation" of the aggregator, no reason to do abstractions after that point on
khamas
khamas2y ago
yeah well good enterprise code: INumberAdderServiceFactoryBuilder bad enterprise code: var result = num1 + num2;
LPeter1997
LPeter19972y ago
I'll take a useless interface over any abstract class tho Class based inheritance is freaking disgusting
khamas
khamas2y ago
I use abstract a lot for certain things it all depends on the use case I got an interface that's implemented by an abstract class
LPeter1997
LPeter19972y ago
You mean the other way around?
khamas
khamas2y ago
yes edit incoming discord slow today
D.Mentia
D.Mentia2y ago
I mean even if you have one implementation, never expect another and don't test, its still good practice to use an interface because if you don't, someone is going to end up using a dependency of the thing, its models or something specific to it Then it's super expensive to change when you inevitably do change it, because you will, whether you expect to or not
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
You would use an interface if you have the feeling that you would get another implementation. You don't have to use an interface, ever. You don't even have to program OOP either. There is no 'right' answer in this scenario. The correct thing to do is only obvious in hindsight. The vision I have is that hindsight is easier to obtain when you have your interface between your class and your code attempting to interact with that class. You may disagree with that and not use it, and that is okay. But it is important that you think about why you would or wouldn't use it There are a bunch of correct ways to program something. Out of all those ways, 60% of them are correct but not very good for either maintainability or readability. 30% of them are pretty good and the final 10% usually comprises of two or three options that you can endlessly debate on.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
That's because they did it blindly without thinking about it.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
Like I said earlier, abstractions start to look meaningful when you have had a good use case for them or when they were implemented right.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
But, just like async and await, a lot of people "use" these concepts because others do. That depends Do you want a piece of code to depend on a concrete implementation of a class or on an interface?
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
I don't think it is.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
Sorry?
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
When did adding an interface take 1 hour?
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
Sure, you can do that.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
It's fine. Like I said, there is no correct way. But I prefer to have my code depend on an interface, not the concrete implementation. That way, the dependencies are very low.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
Well that depends on the structure of your code. Because if you made it in such a way that everything depends on the concrete implementation and you wish to add an interface afterwards it will be harder.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
But if you have a single interface for a single class and you find that you now have another one, you can just have it implement your interface.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
If that moment never comes, at worst you have an interface in between your class.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
I don't think we'll agree. You have valid points and I understand them. It is a matter of preference. I do not mind adding the interface beforehand. I do not think it is a bad idea. You do.
Thinker
Thinker2y ago
this thread blew up for some reason I think I'll just use some interfaces because it's probably gonna save me some headache somewhere down the line, and rn I just can't be bothered to argue with the what everyone else does.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
Do what you understand best, try some things here and there if you want to learn.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
Interface or not, your code will likely work the same way.
Thinker
Thinker2y ago
yep Also btw I love your pfp
Shinyshark
Shinyshark2y ago
Thanks
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
ShinyCute
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
ero
ero2y ago
sh-shrk....... <:pr_pretty:957996947015356466>
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
That's fine, do remember to give others a fair chance to explore these topics though. You come off as very hostile on this topic
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
I didn't agree with it at first, I started to see use cases for it so I started doing it more.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiX2y ago
Shinyshark#2846
You would use an interface if you have the feeling that you would get another implementation. You don't have to use an interface, ever. You don't even have to program OOP either. There is no 'right' answer in this scenario. The correct thing to do is only obvious in hindsight. The vision I have is that hindsight is easier to obtain when you have your interface between your class and your code attempting to interact with that class.
React with ❌ to remove this embed.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
I didn't intend to specify it as an animation. As I said earlier, the choices you make in these situations are all correct if you can explain why you use them.
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Shinyshark
Shinyshark2y ago
As long as you think about the choices you make and have valid points for them, you can't really go wrong.
Thinker
Thinker2y ago
so $itdepends
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Thinker
Thinker2y ago
The thing I'm mostly just not a fan of is overengineering everything without any apparent benefit, although ironically that might be the easiest solution - just going with the flow
Shinyshark
Shinyshark2y ago
A lot of abstractions are overengineered by people who love to make it work. I have seen a lot of abstractions at work that did nothing but hinder me. Undoubtedly, at some point they were good abstractions but it is really hard to make a correct one. Especially if you work on custom software projects where the requirements keep changing. When you work on an enterprise application where every UML needs to be approved before you can even write, it becomes a lot more interesting to use these kinds of concepts.
D.Mentia
D.Mentia2y ago
The benefit is that it prevents certain kinds of mistakes. If some dev bakes in a model from your dependency you're gonna have problems later, if you only expose an interface they can't do that An interface is basically like a method signature. Both are contracts, and even though you have to edit both the signature and code anytime you change either one, it's worth it to keep things safe
boiled goose
boiled goose2y ago
if you will need an interface or an abstractions package after everything is compiled, versioned, and distributed, you will have to update every service that is already deployed, edit the code to use the interface instead of the concrete class... ergo it would be a mess and it would be too late we are always paying attention to trying not to do the astronaut, but if the class is not a really really specialized one and it's used in a modular service, then interface it is