Dependency Injection in Go

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys so in this video I'm going to explain to you dependency injection and why it's useful and how to use it within a goang project so to start here we have a very simple go project and let me explain what's going on so here we have a main function which instantiate a logger passes through an API service and then just call something on the API service so if you look at our logger it's very basic so we have a new console logger ENT this prints out to our console and a function called log and then within our API imagine here we have a lot of things like you know different get request Port request or whatever you want but in this specific example the API Service uh requires a logger so we're passing in a console logger and then we simply um create a get function that logs something and returns whatever data we pass through very basic very simple so this works if that's everything you need but imagine a case where the type of logger changes so instead of cons doing console log like uh logging to our console our requirements are now we want to log to a file for example or maybe we want to log to a third party service like a through an API request like dat dog or something similar so let's let's say we want to do that so let's go to our logger and let's just create a new logger let's call it file file logger so here we create a new file logger and then we simply log things okay so we have a new logger so now in order to update things or like use this logger we want to go to our main and so we know that this logger is no longer valid because we now we have different logger so in order to change this we first need to do logger uh maybe let's call it file logger and then file log all right now here you see we already have a problem because our API is tightly coupled with this logger meaning that this logger here is not the file logger and it's very specific so to fix it we have to change this code as well and we have to say something like file logger is actually the file logger here and then we should change this one as well to file logger and this one to file logger and this one as well so you already see the problem here like if we have another one yet like let's say a third party logger then that becomes a problem because now this is a very simple and a very small project but imagine this is like a really big one and you have a lot of code that depends on this logger suddenly you have to change this every single place and that's because the code is tightly coupled and that's really the heart of the thing with this um the dependency injection the whole point is that to you decouple your code things are not dependent on each other anymore instead you inject some of that code or some of that logic in a way that makes it really easy to swap so how do we fix this imagine like we actually want to have multiple types of loggers and we want to support that so let's go back to our logger first and let me comment all of that and just rewrite some of these things so we know we don't want to have a specific logger like this and we want to make this a bit abstract right so what we can do um type logger is an interface and here we can say log a message so we don't have an implementation yet and we just uh defining an interface a contract that will enforce any other type of loggers to kind of U have a log function and now let's say we have a type called console logger which is a struct we create a Constructor for it and then we log it now this console logger is an implementation of this interface because it has a function called log right so every time you have a function any any structure that has a function called log on it is implementing this logger interface and the same will work for our other logger which is a file logger same exact thing like that and now we have another type of lugger cool so now if we go back to our API how do we change that so instead of file logger what we can do here is like let's just say logger and use logger here and this logger is actually the interface notice that we're not specifying a a specific implementation we're just making it a a contract here we're passing an interface so instead of uh passing a implementation what we can do here here is say logger which is an interface and do logger here as well and then go all the way down and say a. logger.log and whatever data for example and here yeah uh like this so yeah now this is kind of uh abstract we don't know what the logger type is and we're already like doing things with it so we're calling this function um log which is coming from this but we still don't know what the implementation is so now we can pass any type of lugger to this service so if we go back to our main function notice that this is working and we can like swap it just like that and maybe change this to logger and it will still work and the reason is because this new API service accepts any logger that implements the logger interface and and in our case we want console that works so if you want let's say a file logger let's rename this to let's say logger comment this one now this still works so that's really how dependency injection works so you want to be able to inject some sort of a dependency to the service without having to change a lot of the code so it's easy to swap and you know you can even go back to your logger here and create a even one more um logger code let's say um third body logger and that let say this connects to some sort of an API same exact thing so it's so easy now you can just go to your main and create a new logger let's just comment this one and say new third party logger and that will still work and that's the power powerful thing about dependency injection um it decouples your code in a way that uh you can swap different implementation without having to change a lot of code and this specific example is very simple obviously you see that you have three files here but imagine this project is is really big you will start seeing how powerful this thing is you can just swap implementations here's an example let's say you're using stripe for your payments and your whole code is built in a way that is tightly coupled with their API or with their um SDK maybe a requirement comes and now you have to swap uh um the stripe API to like some other payment Gateway now you have to change your code everywhere where if you actually um using dependency injection all you have to do is just change the provider create the payment for you right and you just pass it in as a dependency or injected in this way so that's kind of the idea behind dependency injection and that's just how to swap implementation but also it's very helpful and very useful when it comes to um testing so let's write a test for our API and here let's just say package main function test my API and T testing yep that should do it all right so here we create a third party logger um actually we don't want a third party logger here the idea is we want to mock this right so we want to create a mocking a mocked um logger why because maybe this third party requires an actual API call and we don't want to do that so we need to have a mocked version of this such to simulate that this thing is kind of working so what you can do is create a type called um mock logger which is a structure and instead of making API call maybe we can just add to a an array and see check if this thing is inside of the array so what we can do is um L do um we can actually pass in a message here which is an array and here yeah that's pretty much what I want essentially I'm appending um I'm appending the messages that I'm sending I'm trying to log to this message array so now instead of creating a new instance of this um third party logger what I can do is just create a The Marked version of it so I can say Mark logger here and just pass it through it's still going going to work this Mark logger is implementing our logger interface so it's still going to work right so now we know that this API is going to return something we know it's going to return hello world in this case so let's go back here and create response for example and then say that our response should be equal to this hello world we can obviously use some libraries for this for example um go get all right so now we have it now we can just use it so instead of doing that assert equal this guy there you go now the test passes and even if we run our code for example go run dot you see it works so that's the other thing about dependency injection you can essentially use it to create mocks in this case like we're creating a logger a mock for the logger and then we can use that and this is helpful because if for example the logger requires some API calls and things like that and you don't want to really do these things in in your test you can just create a mock for that so imagine other scenario for example where you're mocking an API you just don't want to call the apis but you want to kind of simulate that and that's how you do that here you create a mocked object of this and then you inject it to whatever service or code you're using and then you just use that so that's how dependency injection Works within tests as well very helpful for testing now there are libraries that you can use to kind of do more things but in the most basic form that is what dependency injection is all about it's essentially a way for you to swap dependencies for different services or within different servic without having to change a lot of code as easy as you can and then within tests it's very helpful because you can create Mark objects or Mark structures and then you can use them to simulate the certain thing you're trying to inject so that's pretty much uh what dependency injection is I hope you found this useful and I'll see you in the next one
Info
Channel: Adib Hanna
Views: 2,971
Rating: undefined out of 5
Keywords: golang, dependency injection, DI, Neovim, design patterns, advanced, logger, powerful
Id: hhr0I1pBa_g
Channel Id: undefined
Length: 11min 18sec (678 seconds)
Published: Sat Apr 20 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.