Dependency Injection question
I was learning about coupling/decoupling and one thing that was confusing to me was this:
Basically, people tell you to leave the instances for the calling of the constructor method, and instead just use an Interface that implements that class when using it on your code.
The reason people will say this is useful includes (while not limited to) "Making so that if the signature of that class changes, the code using that class won't be affected, since it's using an abstraction of it, an Interface. Making it easier to change the class without breaking the code"
While I understand that, doesn't this just changes the necessity of getting the signature correct from inside the code to "outside" the code? (And what I mean by that is calling the code, since you will need to pass the instance of this class anyways and if the signature has changed I don't see how it won't give errors the same exact way)
38 Replies
the interface helps you understand what the class should really have public, what the class does
to do this you need to study the problem and it helps also anticipate some of the problems you may encounter down the road
But how does this process helps you avoid errors when changing the signature of a class?
it helps you with that if you have more that one class that implements said interface
the main point tho would be abstracting first to have less changes
Not sure I quite understand yet 🤔
i wouldn't say you have to have an interface for every class in your program
if that's the doubt
I just don't understand the practical benefit of doing this at all, since it just looks like to me that you are shifting the issue from the contents of the class to the calling of it instead.
there are various reasons to have interfaces, one of those is dependencies
you can for example have a project with the interfaces to your classes that you can use elsewhere without having to include all the concrete classes
or for example you can share it with someone without giving them code that could be protected in some way
I understand that interfaces are useful
My question is more directed to this specific usage that does dependency injection with the use of Interfaces
well this
Making so that if the signature of that class changes, the code using that class won't be affectedis not right, methods between interface and derived class must have (almost) exact corresponding signature almost in the sense that minor things like nullable differences for references are only a notice and not an error so if you change interface you have to update all the classes that implement it
to give another perspective, i'm going to agree that i don't think this idea of 'if the signature of the class changes, the code using it won't be affected' is correct
or even a reason i've ever heard for using interfaces, i think
the point of interfaces is to be just the signature
i would be interested in seeing any places you've seen which are expressing this viewpoint
Maybe I misunderstood the class I was taking 🤔 what is the real reason for doing this DI with interfaces then?
generally you use interfaces with DI for the purpose of testing.
or more generally, swapping out implementations without the consuming code knowing you've done so
i.e. if i have a class that takes in an IEmailService
in my unit tests i can pass it a dummy IEmailService-implementer which doesn't actually send out emails
and the class i'm testing doesn't know the difference
Sorry, I'm still a noobie, having a hard time following.
What do you mean the code knowing or not knowing, and what difference would that make?
let me draft up a quick example for you
Thank you so much 🙏
i want you to think about how you'd test the SomeService class
without going bankrupt
you can't do it -- it has to use a MoneySpender, and the MoneySpender will always cost you 50k
not only testing but potentially switching multiple versions of the code
or even different implementations
for example swap a client that uses serial port or ssh with just an interface for sending data
or whatever other reason
so you can't test SomeService
now consider this example
you can give a FakeService to SomeService and it will work. SomeService doesn't know if you just gave it a FakeService or a MoneySpender. it just knows it's an IService
this means you can now test SomeService without spending lots of money
I understand that in the example whenever you run DoImportantWork you end up also running the DoSomethingExpensive. So in another example, when testing DoImportantWork, it would be hard to know if the issue isnt coming from DoSomethingExpesnive, since it is not run independentely
if thats what you mean with the example
But how would using an interface and passing the class via the constructor help?
moreso what i mean is that there are (quite often) bits of code you want to run in normal usage, but not run in other cases. for example you don't want to actually send out emails to users when testing your app
(i was typing and i didnt see the second message)
interfaces let you section off awkward and annoying dependencies and step around them as needed
(let me go back and read)
ah, ok
is fakeservice supposed to be an interface too? not a class?
woops
no, it's not, sorry
Ah ok
I think I'm starting to understand
Let me think a bit more about it 😂 im kinda slow
lol, no worries
i think everyone had that experience with interfaces at first
Ok so, the issue with coupling is that you cant use ClassA (in this case, SomeService) without running the exact implementation of ClassB
While with DI (in this example via an Interface) you could try out other ClassB implementation for testing purposes
Is that the takeaway?
yes, that's a pretty good way to think of it
though as MutableString noted, this is useful in cases besides testing
you might, say, have an app that makes use of encryption, and you want to switch from one encryption algorithm to another... if you have an IEncryptionService interface which hides the details of what specific algorithm is used, you could swap it out for a different implementation and the rest of your codebase wouldn't know - wouldn't have to change
Not knowing in this context means that it works without knowing the specific implementation
correct?
correct
So you can change it at the calling
and its not a issue
ok i think i got it
Thank you so much 🙏
class A, speaking generally, shouldn't care about how class B does stuff. it should just care about what class B can do for it
one model of 'good code' is having lots of little, closed-off, independent modules
glad to hear it 🙂
The only thing that is kinda weird to me still
is that it sounds a little bit more niche than what I expected from how much people say this is necessary
but maybe im just very wrong
i would like to add that an interface represent a way to use a class/concept (also said contract)
so a class can obviously implement many interfaces (look for example at primitives like int)
which can matter in different contexts
it's not niche, it's just useful when you have to organize hundreds of classes or more
it's one of the many patterns that only becomes truly useful on 'serious' projects, i.e. ones with lots of classes and enough complexity that testing is a requirement
i will also say that you don't have to use interfaces everywhere. in fact i actually prefer not using interfaces if i can
because i want my tests to exercise as much 'real code' as they can
but there's some stuff, like database calls, http calls, etc., that you really just have to mock out sometimes
Got it. Ill try to use it in some classes that I feel like could have different implementations at the very least