Understanding swappable implementations -- Factories and Dependency Injection - examples in Laravel

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys welcome to a new video I'm really happy to have you here before we begin slicing I would like to talk about two things first one is that I have a new newsletter that's hard to say and where share Cooling's that I've found throughout week sharing my blog posts many videos ask for some ideas of videos and I'm also going to release a free test driven development course in the next few weeks if you like to have some early previews I will also like to ask you for feedback and all this stuff you can subscribe to the list in the description it would be really cool if you could do that you know I appreciate it second thing is if you want to support me to continue doing this kind of videos all I ask is for a subscribe and like and if you like you can share this with a friend or with the community that you think would be helped by this content but anyway today we are going to talk about swappable implementations and although the name is a little bit fancy it's actually a very simple concept it just means that you have an implementation and that you can swap it for another implementation while keeping the same public API so let's see let's work with two examples I'm target with one example you have two payment gateways let's say stripe and Braintree and you have your website serving users and the US and Russia or let's say Rahzel and the u.s. ng one client some of the u.s. to pay using stripe and client some Brazil to pay using Braintree so you have two implementations and what I see lots of beginner to intermediate developers do is put a lot of F plus a lot of conditionals in their code instinct a different kind of services it's really a little bit messy and it's just not easy to maintain it's not easy to look at you can just really figure what's going on and with the swappable implementation you can have a single API so a single public API so if you call a method call P you can always call that and you can have your system your application resolve the corrective pendency for you automatically at the correct implementation so if your client needs Braintree it will get you the bring - provider if it wants you stripe it will get you to stripe providing all automatic and you only have one single Klingon API you don't really care what gateway you are using the system will determine that for you and you just use the correct implementation I'm also going to talk about the repository pattern but in another video it kind of depends on this one I just want to lay some foundation but anyway let's jump into the code and I can explain it a little bit better for you guys see you later I mean - in a sec okay so here we have kind of a test controller just want to show you guys how it works and we are just calling this stripe class it's all fake I created a stripe in braintree class to just serve up upset purposes and we are calling this class in pain so what you would usually do in your controllers is say hey if the you we don't have a user authenticated but let's just write some pseudocode is in Brazil something like that then we won't see or say I don't know generate raintree payment and if the user is on the US which is the only other possible place you can say hey generate a stripe payment and then you have a bunch of duplicate code oh it's def and then you're just your actions what we want to do is to have a clean api and use that for all the implementations so what we want to do is something like that say Gateway I'm going to show you guys two things the first one being the factory pattern and then we're going to show you guys something called dependency injection and also letting the container resolve things for us if you do not know what the container is I'm using laravel in this example but Symphony has the container as well lots of frameworks has it have it and you can check the documentation but it's big Scalia a place where the Hodes where the application holds all of the available classes and it resolves the classes for you sir when you say hey container resolve me the payments controller it's going to search for that class if it's not inside the container it's going to pull it and then give it to you but it allows you to do a lot of things for instance you can say hey container when a class asks you for the payments controller class object don't give them the payments controller object actually give them the receipts controller class so you have that we have that option you can kind of give it some you can keep I don't know how to say this you can basically bind things to the container and you can say I don't know container when someone asks you for a contract for an interface and you know that you cannot instantiate an interface when someone asks you for the payments interface actually gives them the stripe gateway something like I'm going to show you guys so the first thing is the factory pattern and what you could do here is you could say pay gateway factory and then you could even better for it user and and then you could say I don't know you can sir country something like that let's write this class just to give you guys an example and let's just be let's just pass a hard-coded value here let's say R is Oh and let's just return that weight week so we can see a little bit whoops let me go back to it so I'm going to create a class called reject create this one so I'm going to create a class called Gateway let's do a static function let's just say for country okay change it let's change this okay let's import this class so we have this method and what we can do here is just say if country equals Brazil we return a braintree instance and why is this whoops running okay if it's not Brazil we just have the US so you can just return a stripe instance and what we can what we are seeing here is that the controller does not really care for which type of instance it is it will just instinct it doesn't care it's asking for this gateway class whatever the gateway class you gives them gives it it's just going to use it so we can do faiman Gateway Bay let's spin them on a hundred and let's return in a race so I can show you guys the difference what it returns okay it returns in a tree so if we go to crown and we ran this I don't know what this is empty oh I mean I let's jump and die this actually and you can see that we have a Braintree instance here and the array that it returns but if we were to give a user living and that you ask it actually gives us a stripe instance so that's pretty basic that's the factory pattern that's really really useful you're going to use that a lot probably but we have a small issue here so we're calling this way method but we cannot be certain that the class has that payment that we are not sure about that and what we can do to kind of go around this is to add a contract an interface so let's create an interface let's do it contracts folders so let's say payment gateway so let me copy this contracts and we can do interface payment gateway you need to have a pain method and it should return an array something like that there we go so you're saying that it needs a payment method and you should return an array okay cool so we can say influence payment gateway and the same for stripe let me just copy this and put it here and pull this class so what we are saying we are seeing here is that we don't we're not following the interface we're not following the contract we have changes so this enforces that we have the same API for all of the objects we don't have to worry about this let's change it um I forgot to add that it has a need to amount and we'll still get these error so let's say we are supposed to return an array so let's see array and the same on Braintree let's return an array and now it works and now we can be sure that we are getting a proper object and that it follows the API actually we cannot do that yet we would need to add a return type here you can say that we want to return a payment gateway so we we are enforcing this and it still works if I were to we are getting stripe right so if I were to go here and remove this oops it's going to fail because we are not returning an instance of payment gateway it is not implemented so that's the first thing I wanted to talk to you guys about that's that's a really useful pattern and you can do a lot of things with that you can check for a property inside a model you can check for an environment configuration so you may have the app deployed in two different instances and you can have an environment variable saying it's you should use stripe or that you should Braintree or anything like that and we are actually going to do something similar to to use the repository pattern but that's subject for another video and another thing that we can do is there's something called dependency injection and that's basically not in sync shading the objects like we are right here not using new we ask someone to give us a dependency something like that we can do a construct let me actually do a shortcut and we can say Gateway let me just change this protected and you can say let's even type hint this and say that we want a payment gateway and I'm doing this in the wrong class sorry about that guys this video is a mess we're supposed to do this here and you may think okay let's go but uh on laravel or symphony or i believe any framework you do not actually instantiate the controller so how can we pass an argument to the constructor and here's where their container shines you did not even sting she ate it but Larry Valdez or Symphony or Zen or any framework and you can instruct the framework to give you a certain instance let's try running this let's change this for this let's use that argument and changes here as well and if we run this we're getting an error after all payment gateway is a contract it's say an interface it's not instinctual and what we can do is instruct the faint framework to give us the proper class so we can go and say go to let's say app service provider go to boot and we can do something like that this app bind so we are binding and we can bind the payment gateway interface to give us let's say stripe let's try it and now we're getting stripe and if we say Braintree and give us Braintree and you can go even further and you can say I don't know if we are in Brazil if this let's say let's say you have an environment you have a configuration so you can say F that country BR then you can bind this payment gateway to bring stream if it's not Brazil you can buying it something else and this is really really flexible you can do lots of things with it I'm giving you guys you really some example using two payment gateways because that's something that I'll have to do in an app that I'm working on so it's the most which the example that I got right now I've used this I use this all the time but it's just the first example that came to my and I think that most of us can relate to but this is a really it's a really important thing to know this it gives you a lot of rooms these are lots of things so when we do this we are saying that a container should always inject raintree class when we ask for a payment wait gateway and this is not limited to your classes because what this is actually doing it's passing a string and take a look at this if I go and remove this and I call for this class manually and I can do it like this let me just change this to gateway there's a method called result so we can say resolve payment gateway it's the same thing that we were doing earlier but just manually the controller is not injecting it and if we run this with you get a brain stream but you can also use this for other things it doesn't have to be an implementation you can I know you could say gateway you can pass a string and we if we say Gateway and we run this we still get Braintree so the container is not actually looking for a class but for a string inside of its resolved classes so when we say family gateway class we're actually just doing gateways payment gateway that's what we are saying so this approach works for a lot of things it's not just that what it's not what just what I'm showing you guys it's not just dependency injection dependency injection is not actually this but the concept that I showed earlier where your John actually instantiate objects in the class instead you receive them and I also want to talk about why that's useful let's say you are doing let's let's say we are back to the old approach we're having the constructor here this is really easy to test and the reason being is if we're doing a feature test a functional test whatever you want to call it when you're testing a controller when you are actually testing the request all the requests life cycle if you don't want to actually have the great way if we don't want to actually call stripe or call Braintree you can swap this implementation because this is resolved through the container and it would be the same thing if you were using the resolve method here but if you were hard instantiating it using the new keyword saying Gateway equals new blah blah blah or using the factory as we had it it wouldn't be able to do this it would always give you a hard dependency and that's really terrible some become you wouldn't be able to test this properly you don't actually want to hit stripe what you could do instead is swap this for a fake implementation alario uses it in another place so if you go to bus fake this a class and you can see that it implements queuing dispatcher and you can see that it has the same API so let me show you guys it has the dispatcher cue method it has a dispatch now method it has a dispatch method and when you swap the burst implementation for this bus fake implementation he just thinks differently it is a different implementation so you can see that we have this shoot fake job and it went into the fake implementation instead of dispatching it actually just adds it to an array and then you can check things like which job was patched if it was specially after response you have lots of you have lots of ways to do this but I'm starting to get confusing here but what I want to say is when you inject a dependency instead of hard hard instantiating it you can swap it for anything that follows a contract if it does fall out contract and in this case we are injecting an interface a contract so we are saying hey whenever you ask for this contract give this class and the level framework does this in lots of places you'll find it all over the framework I don't think it instantiates a hard dependency anywhere it always uses a container and the container is very powerful so if you would like to test this class it's really easy in the way it is and you can just stop to swap this implementation for a fake or for a mock you can mock this and wherever will automatically give this swapped class instead of this one I think that's it for dependency injection I do have another video about dependency injection it's a little bit old but I think it does get my point and yeah so whenever you think about making a mask with a lot of conditionals think about either using a factory or using dependency injection and the container there contain most people don't use this and this is a really powerful class you can do lots of things here so yeah if you go to the documentation there are other methods you range you can do a lot of things you can even be more extreme and say container when the payments controller asks for a payment gateway give it class a but when the invoices controller asks for the same implementation for the same interface give it class B I not a fan of this approach but you can do it you can run anonymous functions inside here so you can actually run some some code inside the function to determine which class to give there are lots of things and all I want to do with this video is lay some foundation and help you guys a little bit for the next video which is about the repulsor pattern which is widely used you see really common pattern and I want to talk about it and I actually want to talk about why I don't like in what I have against him and to do this I need to give you some foundation on what is dependency injection how it works how the continuum works and there's a little other problem here we are assuming that Braintree and stripe both returning the same thing so we're calling this and we want to do something with this payment but trifa's most services will return different things most implementations will return different things and if you don't want to end up with conditional how the best way that you have to avoid it is to have a standard object so let's say range free returns an array or returns a range repayment object something like that instead of returning this you would have the contract return something like payment a payment object which is a standard object that you can construct based on the Braintree response or a stripe response and you would always end up regardless of the Gateway that you're using you would always end up with the same object for the same class with the same methods and with the same property so let's save range way returns the invoice on an invoice ID few it but stripe returns it on an invoice field there are different fields the solution would be put in an if block here so I don't know invoice ID you could do gateway each stripe is a stripe something like that and if it is you'd say invoice I'm sorry it would say payment invoice if it wasn't you'd say in my city and that's just messy and confusing if you were to return a standard object you could just say invoice ID Feynman University and the this would be an standard object both implementations return and construct based on the data it has even if we were to just change this to toad amount and have it amounted here it already breaks the whole thing so I'm going to make a video on standard objects I think it's really useful as well and I think pseudo didn't wasn't really I mean I think I passed my point but I think got confusing in some parts so if you guys don't understand something please leave it in the comments I would gladly help you guys I also have a few blog post about this it might be easier to understand but anyway thank you for watching I really appreciate it and if you've liked this video you can support me by subscribing to the channel or liking the video and sharing it with friends if you if you could share that's really helpful that's the most helpful thing so thank you guys and I'll see you later in the next video which is about dependency injection and after that it's changing objects and that's it guys talk to you later bye bye
Info
Channel: Mateus Guimarães
Views: 1,153
Rating: undefined out of 5
Keywords: php, laravel, tdd, test driven development, clean code, repository pattern, factory pattern, swappable implementations
Id: IFOmEpCTAH8
Channel Id: undefined
Length: 23min 36sec (1416 seconds)
Published: Fri Jul 10 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.