Dependency Injection Explained in 7 Minutes

  Рет қаралды 57,251

ArjanCodes

ArjanCodes

Күн бұрын

Пікірлер: 105
@ArjanCodes
@ArjanCodes 5 ай бұрын
👷 Join the FREE Code Diagnosis Workshop to help you review code more effectively using my 3-Factor Diagnosis Framework: www.arjancodes.com/diagnosis
@loic1665
@loic1665 6 ай бұрын
Warning, at 4:26: never use a mutable variable as an argument! This is because the same object will be reused if you call the function/method several times! This is also a common mistake when you want an empty list. A solution is to not provide a default value, but a default factory. Apart from this, thanks Arjan for the video :) Very good, as always! The new example is refreshing and is well appropriate
@dynamicgrad3820
@dynamicgrad3820 6 ай бұрын
What do you mean "when you want na empty list"?
@TheEvertw
@TheEvertw 6 ай бұрын
​@@dynamicgrad3820 If you pass an empty list as default argument in a function, that default empty list is created once, and then reused every time that function is called. Which means that most likely, after that first function call, that list no longer is empty. And if the list passed to the function is stored somewhere in your code, there are multiple references to that list spread around your data structure waiting to cause nasty and hard-to-debug side-effects. Your Python IDE will warn about this. A better solution is to use an `typing.Optional[List[xxx]]` argument, with a `None` as default argument. `None` is immutable, so it can be safely reused and shared between multiple calls to the function.
@TheEvertw
@TheEvertw 6 ай бұрын
Seconded. I spotted that as well, you beat me to it. Besides using the factory argument, Python has the Optional typing hint, which expects a None default value.
@dynamicgrad3820
@dynamicgrad3820 6 ай бұрын
Can someone explain why he added this warning?
@erikstv7802
@erikstv7802 6 ай бұрын
@@dynamicgrad3820 if you specify a default value to a function argument, Python constructs that object only once (together with the function), not again for every call that needs the default value. A common situation would be that you make an argument default to an empty list []. Let's say that the function's code appends something to this list. You may be surprised to notice that if the function is called a second time, the default value is no longer the empty list but the result of manipulations to the list in the previous function call! I.e. it's reusing the very same instance of the default value, not constructing a new value. A way to solve this is to use None as default value then in the beginning of the function replace None with a new empty list if that's what you wanted.
@estevaoyt
@estevaoyt 6 ай бұрын
Beautifuly explained, clear as water! keep it up!! I think dependendy injection is one of the most important concepts in programming!
@ArjanCodes
@ArjanCodes 6 ай бұрын
I'm happy you enjoyed the video!
@edgarcarrillo3814
@edgarcarrillo3814 2 ай бұрын
Thank you Arjan! Clear, concise, and to the point. I now know Dependency Injection!
@ArjanCodes
@ArjanCodes 2 ай бұрын
Glad it was helpful!
@roger_rogerthat
@roger_rogerthat 6 ай бұрын
This time I felt like I've already seen this video. You should talk about an auto wiring DI library like kink
@buchi8449
@buchi8449 6 ай бұрын
One of the surprising things I encountered when I moved from Java to Python was the heavy usage of the service locator pattern. A typical example is Flask's "request" and "d". It is still widespread in Python to put a dependency or an accessor to a dependency in the global context and reference it inside a component. Of course, Python has enough flexibility to manage tests of such less decoupled codes. However, I have always believed that clear decoupling using DI is cleaner and more straightforward. FastAPI's DI is handly but covers only part of the DI commonly practised in Java. FastAPI supports only DI in the "request" scope. But DI frameworks in Java, like Spring, support other scopes, including the "application" scope. The lack of DI containers supporting the application scope is why people must repeat "app.include_router(...)" etc., to construct big applications. DI realises IoC (inversion of control) at the component level. However, you still need to control the construction of an application (injection of dependencies), as demonstrated in this video. The automated construction of applications using DI and CoC (convention over configuration), which is widely used in Java, is something we should consider in Python as well.
@mackymccormack8446
@mackymccormack8446 5 ай бұрын
Thanks really helpful. In this example though I couldn't see how variations in the email service protocols were catered for. The send_email method didn't show an indication of the different logic needed for different services.
@shashishekhar----
@shashishekhar---- Ай бұрын
Great example.
@Nalewkarz
@Nalewkarz 6 ай бұрын
Deja vu, You have recorded almost the same video again. Arjan it's time to go deeper into more advanced examples.
@ArjanCodes
@ArjanCodes 6 ай бұрын
This video was a lead up to another one that’s coming very soon, covering DI frameworks 😊
@mirkoulrich6312
@mirkoulrich6312 6 ай бұрын
@@ArjanCodesi was looking in the comments, if this framework discussion has been requested yet^^. I recently used Dependency Injector, but never got really fond of it. I am looking forward to this upcoming topic.
@kvicar7419
@kvicar7419 6 ай бұрын
So in this case, how the email service specific arguments are going to be handled? For example the attachment argument? First we are going to create an instance of email service, pass the arguments to it and then use it to create an instance of EmailSender to actually send the email?
@NicolasChanCSY
@NicolasChanCSY 6 ай бұрын
I was just about to ask the same questions. I thought these would be answered in the video but they are not.
@audox4885
@audox4885 2 ай бұрын
yea that made no sense to me
@maleldil1
@maleldil1 6 ай бұрын
Why do you use Protocols if you're going to subclass that anyway? Doesn't it defeat the purpose of Protocols (structural subtyping) in the first place?
@kaosce
@kaosce 5 ай бұрын
Not really. Protocol are better abstract classes
@TheEvertw
@TheEvertw 6 ай бұрын
"Dependency injection", as explained here, is probably the most simple OO design pattern. In OO, it is called the Strategy Pattern. You hide the details of an algorithm behind an (abstract) interface. The user of the strategy only knows the abstract interface, each implementation of the Strategy interface knows only the details it needs. I don't understand why people wanted to change the name. The name "Strategy Pattern" has been in wide-spread use for 30 years. I guess people like re-inventing the wheel. That is no critique on Arjan, he didn't coin "dependency injection". I thank him for this video, I never understood what people meant with DI. I thought it was some complex trick like the "Curiously Recurring Template" pattern. Which is similar to DI but achieves lightning fast execution & minimal memory footprint, at the cost of long compile times.
@m__42
@m__42 6 ай бұрын
I would say, dependency injection is (usually) built upon the Strategy pattern, but goes beyond that. Your dependencies to inject will usually use the Strategy pattern, but in addition you have some concept of instantiating the dependencies, a repository to keep them, and a way to inject them as needed. This was of course the most basic example with just one dependency which is created in the main() and injected via the constructor. Really a textbook Strategy pattern. This works fine for this simple case with only one level of dependencies. However in an even moderately complex application, this simple approach soon falls apart in that it either explodes the number of dependencies you have to pass along, or forces you to create all strategies in a central place which prevents modularization. There Dependency Injection frameworks come to help...
@Naej7
@Naej7 6 ай бұрын
TL;DR : The Strategy Pattern uses the Dependency Injection principle but the Strategy Pattern is not the Dependency Injection principle, and the Dependency Injection principle is not the Strategy Pattern neither
@Lexaire
@Lexaire 6 ай бұрын
Strategy Pattern is specifically at runtime choosing different options. Dependency Injection is focused on a caller creating an object that the callee acts upon. Strategy Pattern doesn't require generic interfaces. The Before code that Arjan showed was an example of using the Strategy Pattern.
@WalterVos
@WalterVos 6 ай бұрын
All applications of the strategy pattern need dependency injection, not all cases of dependency injection are applications of the strategy pattern. (All swallows are birds, not all birds are swallows)
@Ruskialt
@Ruskialt 6 ай бұрын
Yes it's a great pattern. To actually manage and reduce dependencies you need also consider where to place your abstract classes and interfaces.
@diegovargas3853
@diegovargas3853 6 ай бұрын
Hey Arjan, thank you for your work from Spain. Would be great if you create a video with your top python books "to improve your python skills to another level", thank you!
@willemvdk4886
@willemvdk4886 6 ай бұрын
Python has, just like many other languages, very nice libraries for dealing with DI. Very valuable in big projects with loads of modules, units, tests, deployment environments, etc. etc.
@amanlodha6260
@amanlodha6260 6 ай бұрын
Could you share some options here please?
@capability-snob
@capability-snob 6 ай бұрын
Don't get confused when talking to Java programmers about DI. Over there, it generally means "magically inferring which service to use".
@andyk2181
@andyk2181 6 ай бұрын
So, er... it's *not* about vaccinating your children?
@markcampanelli
@markcampanelli 5 ай бұрын
lol!!!
@VanosTurbo
@VanosTurbo 6 ай бұрын
Agree your codebase gets such an improvement when you start using dependency injection.
@manonthedollar
@manonthedollar 5 ай бұрын
Dumb question: In this example, the EmailService ends up hard coded (at 5:17 see Line 6-8, for example). In a more real-world example where you don't know which email service a user will need, won't there still be some big long if/elif/else block that needs to be updated when you add a new service?
@ifeanyinneji7704
@ifeanyinneji7704 6 ай бұрын
Recently did something like this for work. But used a general email sending function that takes in smtp type, port etc for different email providers.
@TheEvertw
@TheEvertw 6 ай бұрын
I prefer SMTP as my email sender. Works every time, regardless of how a customer has configured his email server.
@heinereniscaicedo7510
@heinereniscaicedo7510 6 ай бұрын
There's an awesome third party library called Dependency Injection, it's so good to apply this principle to any python project
@danielwhiting4017
@danielwhiting4017 5 ай бұрын
Thanks for the great video. I understand that this is a bit of a contrived example but can you explain why you use an EmailSender class at all when it only wraps a method of the service object that is passed to the initialiser? In other words, why not just call the send_email method directly?
@ytuserln4990
@ytuserln4990 6 ай бұрын
Hello Arjan, great video as usual! I have a question why do you inherit from the protocol in a class which implements one? It's the second video in which I can see this, whereas in ABC vs Protocol you pointed out that it is not needed (duck typing) and also decouples the one who implements from the one who requires. Is there any reason for that? Thank you in advance for the response.
@alexandarjelenic2880
@alexandarjelenic2880 6 ай бұрын
I’m confused between the factory pattern and dependency injection. I watched both your videos. Is it the same?
@janetgauntt903
@janetgauntt903 9 күн бұрын
To answer your question about which email service, I'm using mailjet
@ShadiPL94
@ShadiPL94 6 ай бұрын
I am bit confused, since when we have to inherit explicitly from Protocols? Your Smtp, SendGrid and MailChimp classes all inherit from EmailService. Or is this just to show that those classes implements the protocol?
@Lexaire
@Lexaire 6 ай бұрын
They must inherit so that his EmailSender class can call any of them. See code at 4:00
@andreas3682
@andreas3682 6 ай бұрын
Inheriting from 'Protocol' is necessary to create EmailService Protocol. Whats not necessary and where i believe the confusion stems from is inheriting from 'EmailService'. A protocol in python is a typing related construct and should be used as such by using it to declare the type as done in the 'EmailSender' init method. In this example an ABC would be better suited as we have full control over the different implementations. If a third party implementation of an EmailService was imported that you could not control in addition to some of your own code alongside it or as alternative implementations you could use a protocol.
@hello_world_zz
@hello_world_zz 3 ай бұрын
Thanks Arjan
@ArjanCodes
@ArjanCodes 3 ай бұрын
Glad you enjoyed it!
@MagnusAnand
@MagnusAnand 6 ай бұрын
These are the best videos!!
@ArjanCodes
@ArjanCodes 6 ай бұрын
Thank you! Glad you like this content!
@danielschmider5069
@danielschmider5069 6 ай бұрын
Can we see the files email_service and services? You put code there and never showed them
@Phoenix_ZA
@Phoenix_ZA 6 ай бұрын
I have been happy with Mailtrap
@calebrubalema
@calebrubalema 6 ай бұрын
informative, thank you! Have to ask though, is there a Python package that can do DI the way Spring Boot does it?
@talwald1680
@talwald1680 6 ай бұрын
We heavily use DI in one of our projects, and it is getting really difficult to manage. We looked and didn't find anything standalone (FastAPI has DI but not standalone, and the project isn't an http server.. ). So if someone knows a good package - lets us know!!
@Nalewkarz
@Nalewkarz 6 ай бұрын
We have better, something like Lagom for example.
@Lexaire
@Lexaire 6 ай бұрын
FastAPI or FastDepends have enough DI for most people. But do you mean the Beans? I've not encountered something like that in Python.
@jumper0122
@jumper0122 5 ай бұрын
I'd really like a few more videos on this topic -- it seems really clever and useful but I don't totally understand it
@ArjanCodes
@ArjanCodes 5 ай бұрын
I have a couple of older videos talking about it already! :)
@vyacheslavkapitonov9677
@vyacheslavkapitonov9677 5 ай бұрын
How will it work if I need to pass an attachment? I still need to change send_email for all of my classes
@marthinus.x
@marthinus.x 6 ай бұрын
Sheesh! Fresh off the presses!
@thefattysplace
@thefattysplace 6 ай бұрын
The emailSender class here is not needed imo. A better approach (imo) would be to use a common interface on the sender classes, and use DI to pass the relevant sending class to the interface object. Then just call send on the interface.
@user-lp6qm3cg6h
@user-lp6qm3cg6h 6 ай бұрын
I don't get the real advantage of it .The lines of code you reduce in the first class you have to put them in an other file, so you end with the same (probably more) lines, more files and dependencies. I would really like to understand the advantages of it to apply it more naturally. Thanks in advance
@Lexaire
@Lexaire 6 ай бұрын
Advantage is for testing, separating construction of a service from where it's used, organizing your services better, and keeping code clean. If you can swap out one service for another without a fuss, then your code is properly decoupled!
@DanielRodriguez-lu3uu
@DanielRodriguez-lu3uu 6 ай бұрын
is decency injection only applicable on Classes?
@Lexaire
@Lexaire 6 ай бұрын
No, you can inject abstract functions into other functions.
@JobertoDiniz
@JobertoDiniz 5 ай бұрын
5:20 Hi. This is not dependency injection. You demonstrated a pattern called dependency INVERSION. Injection is on top of that. Injection means you outsource the instantiation of a class to a Container that will automatically inject dependencies to the class based on configuration.
@ArjanCodes
@ArjanCodes 5 ай бұрын
Yes, it is. Dependency injection doesn’t require a container. DI means you provide an object or function to another object or function, thus separating creation and use, which leads to better decoupling. Dependency inversion means you rely on abstractions instead of concrete classes, which I didn’t cover in this video.
@deViant14
@deViant14 6 ай бұрын
I've been doing this but had no idea it was a design pattern.
@WalterVos
@WalterVos 6 ай бұрын
If you've been doing something (in multiple projects, I assume) then it is by definition a design pattern ;)
@user-hk2gk7pj8h
@user-hk2gk7pj8h 21 күн бұрын
Isn't using a mutable argument in Python a ROOKIE MISTAKE?
@ArjanCodes
@ArjanCodes 20 күн бұрын
Unfortunately in Python there’s no way to indicate that an argument is a const. When you pass a mutable data structure like a list as an argument, you probably should avoid modifying the list in the function or method that you pass it to. In case it’s an object with methods that is passed as a dependency, it’s a good practice that reduces coupling.
@MineStrongth
@MineStrongth 6 ай бұрын
Reupload? I swear I've watched this before.
@PanduPoluan
@PanduPoluan 6 ай бұрын
The power of Python's duck-typing leads really well into dependency injection. Just pass an object that has the required properties/methods, and done. No need to subclass from an esoteric BaseSomethingClass first.
@Nalewkarz
@Nalewkarz 6 ай бұрын
Base class is esoteric for You ? 🤣
@andyk2181
@andyk2181 6 ай бұрын
Can Python be used with Keychron or GMMK, or does it have to be a Ducky typing? 😂
@Naej7
@Naej7 6 ай бұрын
Convenient but a bad idea Write a Protocol to be explicit, and it’s easier to create a new implementation as you directly know what methods to write with what arguments
@darcash1738
@darcash1738 6 ай бұрын
Where do the ducks come into play?
@Lexaire
@Lexaire 6 ай бұрын
You lose the benefits of typing and autocomplete if you don't at least use a Protocol.
@kubas89
@kubas89 6 ай бұрын
Postmark
@crazy_pythonist
@crazy_pythonist 3 ай бұрын
hmmmm, is this actually just Strategy Pattern??
Should You Use Dependency Injection Frameworks?
14:43
ArjanCodes
Рет қаралды 42 М.
Please Help Barry Choose His Real Son
00:23
Garri Creative
Рет қаралды 23 МЛН
КТО ЛЮБИТ ГРИБЫ?? #shorts
00:24
Паша Осадчий
Рет қаралды 3,7 МЛН
Python MAGIC METHODS are easy! 🌟
13:36
Bro Code
Рет қаралды 5 М.
Dependency Injection, The Best Pattern
13:16
CodeAesthetic
Рет қаралды 802 М.
5 Signs of an Inexperienced Self-Taught Developer (and how to fix)
8:40
What is Dependency Injection?
6:48
Scott Bailey
Рет қаралды 115 М.
15 Python Libraries You Should Know About
14:54
ArjanCodes
Рет қаралды 384 М.
Dependency Injection | Prime Reacts
28:34
ThePrimeTime
Рет қаралды 320 М.
Abstraction Can Make Your Code Worse
5:13
CodeAesthetic
Рет қаралды 640 М.
7 Tips To Structure Your Python Data Science Projects
14:49
ArjanCodes
Рет қаралды 114 М.
Dependency INVERSION vs Dependency INJECTION in Python
17:51
ArjanCodes
Рет қаралды 158 М.
Please Help Barry Choose His Real Son
00:23
Garri Creative
Рет қаралды 23 МЛН