Dependency Injection Explained in 7 Minutes

Поделиться
HTML-код
  • Опубликовано: 6 июн 2024
  • In this video, I'll explain why dependency injection is a game-changer for your coding projects. Creating loosely coupled code is key to making the code more flexible and more maintainable. This is all possible through the implicit use of dependencies.
    👷 Join the FREE Code Diagnosis Workshop to help you review code more effectively using my 3-Factor Diagnosis Framework: www.arjancodes.com/diagnosis
    🔥 GitHub repository: git.arjan.codes/2024/tuesday_...
    💻 ArjanCodes Blog: www.arjancodes.com/blog
    ✍🏻 Take a quiz on this topic: www.learntail.com/quiz/ryabck
    Try Learntail for FREE ➡️ www.learntail.com/
    🎓 Courses:
    The Software Designer Mindset: www.arjancodes.com/mindset
    The Software Architect Mindset: Pre-register now! www.arjancodes.com/architect
    Next Level Python: Become a Python Expert: www.arjancodes.com/next-level...
    The 30-Day Design Challenge: www.arjancodes.com/30ddc
    🛒 GEAR & RECOMMENDED BOOKS: kit.co/arjancodes.
    👍 If you enjoyed this content, give this video a like. If you want to watch more of my upcoming videos, consider subscribing to my channel!
    Social channels:
    💬 Discord: discord.arjan.codes
    🐦Twitter: / arjancodes
    🌍LinkedIn: / arjancodes
    🕵Facebook: / arjancodes
    📱Instagram: / arjancodes
    ♪ Tiktok: / arjancodes
    👀 Code reviewers:
    - Yoriz
    - Ryan Laursen
    - Dale Hagglund
    - Kit Hygh
    - Alexander Milden
    - Bean
    🎥 Video edited by Mark Bacskai: / bacskaimark
    🔖 Chapters:
    0:00 Intro
    0:49 Before
    3:47 After
    6:42 Final thoughts
    #arjancodes #softwaredesign #python
    DISCLAIMER - The links in this description might be affiliate links. If you purchase a product or service through one of those links, I may receive a small commission. There is no additional charge to you. Thanks for supporting my channel so I can continue to provide you with free content each week!

Комментарии • 97

  • @ArjanCodes
    @ArjanCodes  3 месяца назад

    👷 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 3 месяца назад +60

    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 3 месяца назад

      What do you mean "when you want na empty list"?

    • @TheEvertw
      @TheEvertw 3 месяца назад

      ​@@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 3 месяца назад +2

      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 3 месяца назад

      Can someone explain why he added this warning?

    • @erikstv7802
      @erikstv7802 3 месяца назад

      @@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 3 месяца назад +5

    Beautifuly explained, clear as water! keep it up!! I think dependendy injection is one of the most important concepts in programming!

    • @ArjanCodes
      @ArjanCodes  3 месяца назад

      I'm happy you enjoyed the video!

  • @roger_rogerthat
    @roger_rogerthat 3 месяца назад +2

    This time I felt like I've already seen this video. You should talk about an auto wiring DI library like kink

  • @TheEvertw
    @TheEvertw 3 месяца назад +5

    "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 3 месяца назад

      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 3 месяца назад +1

      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 3 месяца назад

      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 3 месяца назад +1

      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)

  • @VanosTurbo
    @VanosTurbo 3 месяца назад

    Agree your codebase gets such an improvement when you start using dependency injection.

  • @diegovargas3853
    @diegovargas3853 3 месяца назад

    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!

  • @capability-snob
    @capability-snob 3 месяца назад +2

    Don't get confused when talking to Java programmers about DI. Over there, it generally means "magically inferring which service to use".

  • @MagnusAnand
    @MagnusAnand 3 месяца назад

    These are the best videos!!

    • @ArjanCodes
      @ArjanCodes  3 месяца назад

      Thank you! Glad you like this content!

  • @Ruskialt
    @Ruskialt 3 месяца назад

    Yes it's a great pattern. To actually manage and reduce dependencies you need also consider where to place your abstract classes and interfaces.

  • @willemvdk4886
    @willemvdk4886 3 месяца назад +1

    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 3 месяца назад

      Could you share some options here please?

  • @ifeanyinneji7704
    @ifeanyinneji7704 3 месяца назад

    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.

  • @ytuserln4990
    @ytuserln4990 3 месяца назад

    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.

  • @mackymccormack8446
    @mackymccormack8446 3 месяца назад

    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.

  • @kvicar7419
    @kvicar7419 3 месяца назад +3

    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 3 месяца назад +1

      I was just about to ask the same questions. I thought these would be answered in the video but they are not.

  • @maleldil1
    @maleldil1 3 месяца назад +3

    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 2 месяца назад

      Not really. Protocol are better abstract classes

  • @buchi8449
    @buchi8449 3 месяца назад

    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.

  • @Phoenix_ZA
    @Phoenix_ZA 3 месяца назад

    I have been happy with Mailtrap

  • @danielwhiting4017
    @danielwhiting4017 3 месяца назад

    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?

  • @TheEvertw
    @TheEvertw 3 месяца назад

    I prefer SMTP as my email sender. Works every time, regardless of how a customer has configured his email server.

  • @hello_world_zz
    @hello_world_zz 11 дней назад

    Thanks Arjan

  • @heinereniscaicedo7510
    @heinereniscaicedo7510 3 месяца назад

    There's an awesome third party library called Dependency Injection, it's so good to apply this principle to any python project

  • @calebrubalema
    @calebrubalema 3 месяца назад +1

    informative, thank you!
    Have to ask though, is there a Python package that can do DI the way Spring Boot does it?

    • @talwald1680
      @talwald1680 3 месяца назад

      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 3 месяца назад

      We have better, something like Lagom for example.

    • @Lexaire
      @Lexaire 3 месяца назад

      FastAPI or FastDepends have enough DI for most people. But do you mean the Beans? I've not encountered something like that in Python.

  • @alexandarjelenic2880
    @alexandarjelenic2880 3 месяца назад

    I’m confused between the factory pattern and dependency injection. I watched both your videos. Is it the same?

  • @marthinus.x
    @marthinus.x 3 месяца назад

    Sheesh! Fresh off the presses!

  • @manonthedollar
    @manonthedollar 3 месяца назад

    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?

  • @ShadiPL94
    @ShadiPL94 3 месяца назад +1

    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 3 месяца назад

      They must inherit so that his EmailSender class can call any of them. See code at 4:00

    • @andreas3682
      @andreas3682 3 месяца назад

      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.

  • @Nalewkarz
    @Nalewkarz 3 месяца назад +6

    Deja vu, You have recorded almost the same video again. Arjan it's time to go deeper into more advanced examples.

    • @ArjanCodes
      @ArjanCodes  3 месяца назад +9

      This video was a lead up to another one that’s coming very soon, covering DI frameworks 😊

    • @mirkoulrich6312
      @mirkoulrich6312 3 месяца назад

      @@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.

  • @vyacheslavkapitonov9677
    @vyacheslavkapitonov9677 3 месяца назад

    How will it work if I need to pass an attachment? I still need to change send_email for all of my classes

  • @DanielRodriguez-lu3uu
    @DanielRodriguez-lu3uu 3 месяца назад

    is decency injection only applicable on Classes?

    • @Lexaire
      @Lexaire 3 месяца назад

      No, you can inject abstract functions into other functions.

  • @jumper0122
    @jumper0122 3 месяца назад

    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  3 месяца назад

      I have a couple of older videos talking about it already! :)

  • @danielschmider5069
    @danielschmider5069 3 месяца назад

    Can we see the files email_service and services? You put code there and never showed them

  • @andyk2181
    @andyk2181 3 месяца назад +56

    So, er... it's *not* about vaccinating your children?

  • @thefattysplace
    @thefattysplace 3 месяца назад

    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.

  • @deViant14
    @deViant14 3 месяца назад

    I've been doing this but had no idea it was a design pattern.

    • @WalterVos
      @WalterVos 3 месяца назад

      If you've been doing something (in multiple projects, I assume) then it is by definition a design pattern ;)

  • @user-lp6qm3cg6h
    @user-lp6qm3cg6h 3 месяца назад +1

    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 3 месяца назад +1

      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!

  • @JobertoDiniz
    @JobertoDiniz 3 месяца назад

    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  3 месяца назад

      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.

  • @PanduPoluan
    @PanduPoluan 3 месяца назад

    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 3 месяца назад

      Base class is esoteric for You ? 🤣

    • @andyk2181
      @andyk2181 3 месяца назад

      Can Python be used with Keychron or GMMK, or does it have to be a Ducky typing? 😂

    • @Naej7
      @Naej7 3 месяца назад

      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 3 месяца назад

      Where do the ducks come into play?

    • @Lexaire
      @Lexaire 3 месяца назад

      You lose the benefits of typing and autocomplete if you don't at least use a Protocol.

  • @MineStrongth
    @MineStrongth 3 месяца назад

    Reupload? I swear I've watched this before.

  • @kubas89
    @kubas89 3 месяца назад

    Postmark

  • @crazy_pythonist
    @crazy_pythonist 29 дней назад

    hmmmm, is this actually just Strategy Pattern??