✅ 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
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
Sure, I get that, but in what circumstances would you actually want to swap concrete implementations?
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
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
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 🤷)
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
Fair enough
id argue for not-big personal projects with only a couple of services, its unnecessary
youre the only person developing it anyway
That's the primary thing I was thinking
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
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, donesure
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
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
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.
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.
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
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)
I tend to use abstract over interfaces a lot of times
but my use case is different
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•2y ago
Message Not Public
Sign In & Join Server To View
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•2y ago
Message Not Public
Sign In & Join Server To View
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
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•2y ago
Message Not Public
Sign In & Join Server To View
Sure, didn't say silver bullet
Said legit reason for... well, a reason
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
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 jobinterfaces are good for things that need different implementationsThat'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
IEnumerable<T>
or somethingYes, 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
yeah
well
good enterprise code:
INumberAdderServiceFactoryBuilder
bad enterprise code: var result = num1 + num2;
I'll take a useless interface over any abstract class tho
Class based inheritance is freaking disgusting
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
You mean the other way around?
yes
edit incoming
discord slow today
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•2y ago
Message Not Public
Sign In & Join Server To View
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•2y ago
Message Not Public
Sign In & Join Server To View
That's because they did it blindly without thinking about it.
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
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•2y ago
Message Not Public
Sign In & Join Server To View
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•2y ago
Message Not Public
Sign In & Join Server To View
I don't think it is.
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
Sorry?
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
When did adding an interface take 1 hour?
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
Sure, you can do that.
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
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•2y ago
Message Not Public
Sign In & Join Server To View
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•2y ago
Message Not Public
Sign In & Join Server To View
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•2y ago
Message Not Public
Sign In & Join Server To View
If that moment never comes, at worst you have an interface in between your class.
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
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.
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
Do what you understand best, try some things here and there if you want to learn.
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
Interface or not, your code will likely work the same way.
yep
Also btw I love your pfp
Thanks
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
sh-shrk....... <:pr_pretty:957996947015356466>
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
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•2y ago
Message Not Public
Sign In & Join Server To View
I didn't agree with it at first, I started to see use cases for it so I started doing it more.
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
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.
Quoted by
<@!689473681302224947> from #What's the point of abstracting services as interfaces? (click here)
React with ❌ to remove this embed.
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
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•2y ago
Message Not Public
Sign In & Join Server To View
As long as you think about the choices you make and have valid points for them, you can't really go wrong.
so $itdepends
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
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
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.
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
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