Dependency INVERSION vs Dependency INJECTION in Python

แชร์
ฝัง
  • เผยแพร่เมื่อ 24 ธ.ค. 2024

ความคิดเห็น • 225

  • @ArjanCodes
    @ArjanCodes  3 ปีที่แล้ว +79

    Finally upgraded to better microphones for this video!

    • @jamie9926
      @jamie9926 3 ปีที่แล้ว +1

      You could record an audiobook about python now haha!

    • @metal571
      @metal571 2 ปีที่แล้ว

      The RE20 is an excellent choice. Love this channel

    • @alira7296
      @alira7296 2 ปีที่แล้ว

      I'm only a couple of minutes in so far, but I'm actually finding it hard to listen because of the music...

    • @raidensama1511
      @raidensama1511 2 ปีที่แล้ว

      It’s about time 😉

    • @josephfifstones
      @josephfifstones 2 ปีที่แล้ว

      Which microphone do you use? I am using HyperX QuadCast but I am not happy with it :)

  • @HenockTesfaye
    @HenockTesfaye 3 ปีที่แล้ว +16

    I like the background sayings
    "It depends"
    "Solid advice"

  • @susmitvengurlekar
    @susmitvengurlekar 3 ปีที่แล้ว +81

    After learning about testing, there is more happiness and more smiles when all tests are pass than the actual code working properly 😂

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +15

      Who cares about working code! 😄

    • @vekyll
      @vekyll 3 ปีที่แล้ว +4

      If you write your tests properly, these two should be the same!

    • @yuriysukhorukov391
      @yuriysukhorukov391 3 ปีที่แล้ว +8

      @@vekyll The testing can not prove that the code works properly, it can only prove that smth goes wrong )))

    • @vekyll
      @vekyll 3 ปีที่แล้ว +5

      @@yuriysukhorukov391 Of course. This does not contradict what I said.

    • @digitig
      @digitig 2 ปีที่แล้ว

      @@vekyll You can't fully test any non-trivial code. That's why for critical software there has to be analysis as well.

  • @steventimberman9313
    @steventimberman9313 3 ปีที่แล้ว +31

    This is the first example I've ever seen that clearly shows the motivation behind an abstract class, great video!

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +2

      Glad you liked it, Steven!

    • @kayakMike1000
      @kayakMike1000 9 หลายเดือนก่อน

      I usually refer to databases when thinking about dependecies. Your project will likely be just fine if it uses mariadb or postgres or oracle or mssql.... Just provide an object that can run basic SQL queries, doesn't matter which.

  • @raki1190-y7i
    @raki1190-y7i ปีที่แล้ว

    Fantastic Tutorial, you explain why something needs to be done instead of just explaining how it's done(which are most of the tutorials in TH-cam). And it's very easy to retain the knowledge because now you know why's behind the logic. Great job !!

    • @ArjanCodes
      @ArjanCodes  ปีที่แล้ว

      Much appreciated! Thank you very much!

  • @ojosedirceu
    @ojosedirceu 2 หลายเดือนก่อน

    Finally clarified the differences between them, Thank You Arjan!

  • @NilenduDasnilendudas
    @NilenduDasnilendudas 2 ปีที่แล้ว +1

    Dependency inversion is the process of introducing a new layer between objects in the form of abstract class to reduce dependancy between objects directly and also means that these can be replaced with their subtypes. - This is hands down the most simple definition I have ever heard. Thank you so much.

    • @DerekHohls
      @DerekHohls 2 ปีที่แล้ว

      Are ABC classes really the only way to achieve this?

    • @janekschleicher9661
      @janekschleicher9661 2 ปีที่แล้ว

      @@DerekHohls In python certainly no. You can just duck type and just call the methods on the passed objects. As the method call is resolved dynamically at runtime, it works if you pass the right kind of object and most certainly fail if not. The only disadvantage of that approach is that it makes IDE/linting support harder, so less likely to have autocompletion or detection of completely wrongly passed objects before starting the program. (You can work that out by helping the linters with specific mypy or pylint or w/e header files for the objects or improving the IDEs. For several highly dynamic projects that uses dependency inversion/injection a lot like Django, that's indeed what's done there). And of course, what also can happen that for accident the passed object is the wrong one, but supports the called method, so your business logic is doing something completely wrong just because two different methods are called the same for different classes (this of cause concerns the purist, but is rarely a real problem).
      The main motivation for the abstract classes is coming from the static compiled languages that just need to know an interface to check it at compile time and prepare the calling in the compiled code already (internally they also reserve some at compile timed known locations like offsets where the address of the method is stored, so they can just say at assembly JUMP to that address). But even in those, big dependency inverse/injection systems are often implemented by (what is there called) reflection what is just dynamical lookup with a bit more type safetyness. The classical example for it would be Java Spring, but most other bigger Java systems use this kind of reflection a lot, too. The most negative example would be log4j where this resulted in a hazard security problem :-) - But indeed, the pattern can also be completely language agnostic. E.g. Kubernetes uses it also to a high degree and with just configuration in yaml files (again bypassing a very static language like Go with a very dynamic injection system).
      So, the abstract classes are the old school examples coming from old Java in the design patterns written in the 90s. They are still valid, as unless you want to write a big framework, in static languages, they are often enough choosen as path of least resistance and "most" control. But certainly, the dependency inversion/injection is not necessarily achieved by abstract classes and I guess (I don't have hard numbers on that), that most big system don't rely on it per se. (Usually they still have it, even though it's technical not necessary, but as a way to communicate the necessary interface and it's easier to write an abstract interface/class and have an auto documentation, auto linting, auto completion, etc.) - than to "just" write a good documentation and a good error handling if things are not done right :-)

  • @SurajAdhikari
    @SurajAdhikari 2 ปีที่แล้ว +14

    Nice video. One important detail you could add for tests is that instead of instantiating an actual object we normally create a mock object which inherits the abstract class. The mock implementation obviously will have dummy return values. But that will highlight the true power of dependency injection in lieu of unit testing.

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      Great suggestions, Thank you.

  • @ruszkait
    @ruszkait 3 ปีที่แล้ว +80

    Very nice video again! :-) Dependency injection is covered very well, but the dependency inversion was for me a bit incomplete. As I have seen you have just implemented a "strategy pattern". In my opinion dependency inversion is a bit more than that - though the machinery is the same. The essence of dep. inversion: We want to make that the peripheral details depend on our precious business logic and not the way around. In you example I see the Order and Payment Processor as the business logic, which we want to protect from peripheral details. Therefore we split the Order and Payment Processor into a separate module and there - beside the Payment process implementation - we define the Authorizer interface (ABC in python terms). So the business logic component is "virtualized", it runs on an abstract peripheral - as we have only an interface for the peripheral. Then in a Authorizer module we implement the Authorizer interface from the business logic module. If we do so, then we have flipped (inverted) the dependency. The business logic (Order, Payment Processor, abstract Authorizer interface) does not depend on the concrete peripheral implementation any more, it depends only on its internal interface (Autohrizer interface). On the other hand the Authorizer (peripheral) depends on the business logic as it implements the Authorizer interface. So just by shifting the interface from the peripheral component to he business logic component we have flipped (inverted) the direction of the dependency between the components. I think it is hard to demonstrate it well if all the logic is in one file - you do not see the component (module) boundaries. It would easier if you split up the code: the business logic component (python module) would contain the Order,Payment Processor, Authorizer interface and the peripheral component would contain the Authorizer implementation classes. So the "import" statements would reveal the real power of dep. inversion. You would have an "from business_logic import Authorizer" in the peripheral code, but in the business logic you would have no "from Authorizers import SMS_Authorizer" statement. Another improvement could be that the composition root is also in another component (this is what you have now in the main funcion). The composition root would wire everything together so, it would be dependent on everything (business logic and authorizer peripherals).

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +38

      Thanks for your feedback! It's true that to get "real" dependency inversion, you'd split out the different classes into different files. I have not done that for these examples to keep things simple, but in this case it might have been helpful to do that. I'm trying to ride a careful balance between having practical examples that actually show how it works in "the real world" but still keeping things simple enough that my videos about them make sense :).

    • @Victorinoeng
      @Victorinoeng 3 ปีที่แล้ว +13

      Thanks, Tamas. Your comment was polite and constructive! I am actually gaining twice the value: from the videos and the amazing constructive comments, such as this one!
      The idea of the importing statements made a lot of sense to me regarding the “inversion” part!
      Cheers!

    • @xtunasil0
      @xtunasil0 3 ปีที่แล้ว +7

      I was just asking myself "ok but why is it an 'inversion'?" And your example is crystal clear!
      Thank you very much!

    • @magenertech9412
      @magenertech9412 2 ปีที่แล้ว +1

      Great video and great comment, just to get things straight (correct me if I'm wrong):
      Dependency Inversion is injecting generic abstract dependencies rather than the actual dependencies.
      This makes the actual implementation of a said dependency irrelevant to the dependent class therefor making looser coupled code.

    • @ruszkait
      @ruszkait 2 ปีที่แล้ว +18

      @@magenertech9412 What you describe is rather the dependency injection: where you want to consume a class, you consume an interface instead and the instance is given/injected to your class. For example if you want logging in your library, then you expect in your constructor arguments a logger interface. Then when the system starts-up it can decide what logging system will be injected. For your this detail is irrelevant, you just use the interface. The dependency inversion is a bit different topic: It helps you to place the interfaces (like the logging interface) into libraries. In the classical approach you have a logging library, which has a logger interface. If you want to use logging via that interface, then you become dependent on that specific logging library. So basically your flexibility is reduced to a certain level, that you do not have to know which exact logger from the logging library is injected into your code (say: network logger, file logger, console logger), but you are limited only to those loggers, which are coming from that specific logging library. If you do a step forward and you want to get rid of this restriction, too, then you apply the dependency inversion principle. In this case you do not use an interface from the logging library but you declare and interface in your library yourselves. Then in the system code (say the main function) the user of your library creates a small adapter class, which maps between your logging interface and the interface of the logging library. This way you became absolutely independent of any logging framework, your library is much more versatile. And where is the inversion? Now your library is not dependent on the logging library, so you do not have outgoing dependency, but the adapter becomes dependent on your library. So you have flipped the direction of the dependency just by pulling the interface into your library.

  • @cetilly
    @cetilly 3 ปีที่แล้ว +17

    Your videos are brilliant. Just love this content. I need to watch this video a couple times to catch everything going on.

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Glad you enjoy it, Chuck!

  • @kukuruzayevhenii8764
    @kukuruzayevhenii8764 ปีที่แล้ว

    Thank you! I watched a dozen videos on the topic, but this one not only explained it in the best way, but also felt like a way more complete explanation!

  • @davidzitzmann542
    @davidzitzmann542 3 ปีที่แล้ว

    6:24 I'm glad that I'm not the only one having problems with this mock system. I had such huge problems with this, that I was forced to use dependency injection. Thank you python standard library to make me a better person!

  • @WilliamBrumble
    @WilliamBrumble 3 ปีที่แล้ว +4

    Well structured thorough video that includes design pattern and unit testing. Thank for sharing!

  • @AlexGb007
    @AlexGb007 3 ปีที่แล้ว +4

    Keep up the good work Arjan. These Python OOP topics are helping me understand a lot of new concepts! I also like how you demonstrated unittests and code coverage!

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +1

      Thank you Ali, and will do!

  • @AlejandroLamKhoa
    @AlejandroLamKhoa 3 ปีที่แล้ว +1

    Thank you for having the videos in this series build on concepts of earlier videos. I have been binging your videos, and now while following your example of dependency inversion, I could already tell how you were going to apply that concept and the code you'd write. Thank you Arjan!

  • @rolandovillcaarias5112
    @rolandovillcaarias5112 ปีที่แล้ว

    Finally I can see an example to understand DI clearly. Thank you Arjan for your explanation :)

  • @vinnyt4398
    @vinnyt4398 2 ปีที่แล้ว +2

    I've also encountered similar pain when running tests where my function creates an object within, and I need that object to be in a certain state in order for my test to pass. The thing I had to do (not really recommended, but it works), is you use mock on the "__init__" method of the class for the object you create. In your example here, you would have to mock the "__init__" method of the class Authorizer_SMS

  • @felipealvarez1982
    @felipealvarez1982 3 ปีที่แล้ว +2

    I was delighted to see mock and testing! Every programmer should be doing this!

    • @DerekHohls
      @DerekHohls 2 ปีที่แล้ว

      I missed seeing mock objects here - where were they used?

    • @felipealvarez1982
      @felipealvarez1982 2 ปีที่แล้ว

      @@DerekHohls I think at 4:06 and 9:49

    • @DerekHohls
      @DerekHohls 2 ปีที่แล้ว

      @@felipealvarez1982 Those snippets refer to "patch" not mock?

    • @felipealvarez1982
      @felipealvarez1982 2 ปีที่แล้ว

      @@DerekHohls patch is a convenience method for mock. Same library.

    • @DerekHohls
      @DerekHohls 2 ปีที่แล้ว +1

      @@felipealvarez1982 Thanks! I find mocking quite an obscure topic to understand; but Arjan's use of it here made perfect sense. Hope he tackles the topic in depth at some point.

  • @fazzah777
    @fazzah777 3 ปีที่แล้ว

    your test cases with repeat initialization of sms authorizer are a great starting point for a pytest fixtures tutorial, which are a powerful tool as well. Great video, as always!

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +1

      Thanks! And that's certainly something I'm going to cover soon on the channel!

  • @nithyanandhasubramanya
    @nithyanandhasubramanya 3 ปีที่แล้ว +1

    Wow !! Just one video and I subscribed . The content and quality is outstanding !!!! thank you so much for sharing the knowledge in such a easy way. I look forward to more such videos.

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Welcome aboard! ;)

  • @DeKeL_BaYaZi
    @DeKeL_BaYaZi 7 หลายเดือนก่อน

    You are the coolest developer ever

    • @ArjanCodes
      @ArjanCodes  7 หลายเดือนก่อน +1

      Thank you so much for the kind words!

  • @Korcari1
    @Korcari1 2 ปีที่แล้ว

    Thanks!

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      Thank you so much!

  • @taylormonacelli
    @taylormonacelli 2 ปีที่แล้ว

    So clear, so concise, so awesome! Thank you Arjan

  • @muralir8504
    @muralir8504 2 ปีที่แล้ว

    best tutorial for advance topics

  • @andyanderson222
    @andyanderson222 ปีที่แล้ว

    I absolutely love this channel! Its pure joy to watch these tutorials! Thanks a lot!

    • @ArjanCodes
      @ArjanCodes  ปีที่แล้ว

      Thanks so much, Andy!

  • @ATXAdventure
    @ATXAdventure 3 ปีที่แล้ว +2

    Best programming education videos out there.

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Thank you so much - glad you like them!

  • @VladimirSuravtsov
    @VladimirSuravtsov 3 ปีที่แล้ว +1

    Thank you for really clear and helpful explanation. Code examples are very illustrative too. Nice work!

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +1

      Thank you - glad you like it!

  • @dmytroparfeniuk2670
    @dmytroparfeniuk2670 3 ปีที่แล้ว

    Best video I have seen regarding DIs. Thanks!

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Glad it was helpful, Dmytro!

  • @RichardVodden1
    @RichardVodden1 2 ปีที่แล้ว

    This is a wonderfully clear explanation of a potentially very complex topic. Thank you very much. I tend to prefi my instance variables with _ (e.g. self.autborizer) so that mypi will warn if I call it from outside the class. This avoids accidentally introducing coupling through injected components.

  • @paulkuhne3855
    @paulkuhne3855 3 ปีที่แล้ว +1

    Extremely clear explanation. Great! Thank you!

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +1

      Glad you enjoyed it, Paul!

  • @AR-scorp
    @AR-scorp 3 ปีที่แล้ว +1

    Excellent video. Thanks for making and sharing this.

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +1

      Glad you enjoyed it!

  • @gcl2783
    @gcl2783 2 ปีที่แล้ว

    I like the tests over the driver scripts of previous videos.

  • @Roman-kn7kt
    @Roman-kn7kt ปีที่แล้ว

    Awesome!!!

  • @theunknown2090
    @theunknown2090 3 ปีที่แล้ว

    Great video, more people should start teaching like you.

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Thank you, happy you liked the video!

  • @brianakong7644
    @brianakong7644 2 ปีที่แล้ว

    Awesome video, explanations, and examples! Thank you!

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +1

      Thanks so much Brian, glad the content is helpful!

  • @Jacob011
    @Jacob011 3 ปีที่แล้ว +3

    Turns out, I considered this common sense and used it in my code without even knowing what it is called.

  • @geekyboytop
    @geekyboytop ปีที่แล้ว

    Awesome explanation thank you took plenty of notes!

    • @ArjanCodes
      @ArjanCodes  ปีที่แล้ว

      Glad you enjoyed it!

  • @Lodinn
    @Lodinn 3 ปีที่แล้ว +1

    Great CAPTCHA 10/10 would implement

  • @Hubert4515
    @Hubert4515 3 ปีที่แล้ว

    super useful information about inversion and injection, thanks

  • @danspeed93
    @danspeed93 2 ปีที่แล้ว

    Thank you that is a nice video that goes directly in my favorites

  • @TheBIKEDEALZ
    @TheBIKEDEALZ 8 หลายเดือนก่อน

    superb.
    what should be the guideline to splitting it properly?

  • @pinakadhara7650
    @pinakadhara7650 2 ปีที่แล้ว

    Excellent content. Thanks a lot for making this!

  • @robertbrummayer4908
    @robertbrummayer4908 3 ปีที่แล้ว

    Great explanation

  • @LucasNaruto8107
    @LucasNaruto8107 3 ปีที่แล้ว +1

    Your content is amazing m8!

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +1

      Thanks a ton, Lucas!

  • @edgeeffect
    @edgeeffect ปีที่แล้ว

    As ever, an excellent video but could I just recommend that watchers follow this up with Code Aesthetic's equally excellent Dependency Injection video.

  • @miquelvazquez4544
    @miquelvazquez4544 3 ปีที่แล้ว

    This is really good! But a subtle point: DI/IOC is possible not only with classes but in functions. The theory is the same, the issues and benefeits are the same as well :)

    • @koraytugay
      @koraytugay 3 ปีที่แล้ว

      Are you talking about callbacks? How do you do DI in functions?

    • @miquelvazquez4544
      @miquelvazquez4544 3 ปีที่แล้ว

      @@koraytugay By passing the dependencies as parameters. `def notify_user_signed_up(user: User, email_service: EmailService, jwt_service: JwtService)`

  • @douglaspearson5741
    @douglaspearson5741 3 ปีที่แล้ว

    Great Channel - Learning a lot

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Thank you Douglas, glad you are enjoying the videos.

  • @sebastianrodriguezcolina634
    @sebastianrodriguezcolina634 3 ปีที่แล้ว +2

    Hey thanks for your videos, they are great. I have a question for this one. Is there any reason you use things like is_authorized and set_status instead of using the property decorator?

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +3

      When I published this video I was not yet fully committed to Python-only on my channel, so I wanted to keep the more Python-specific things such as decorators out of the examples for simplicity. I've now moved to fully focus on Python in my channel, so you can expect to see these kinds of things appear more frequently in my upcoming videos.

    • @sebastianrodriguezcolina634
      @sebastianrodriguezcolina634 3 ปีที่แล้ว

      @@ArjanCodes thank you! Great work 👌🏼

  • @rusbelbermudez238
    @rusbelbermudez238 2 ปีที่แล้ว

    Really nice videos I have learned a lot.

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      Thanks so much, Rusbel, glad it was helpful!

  • @brennorris7061
    @brennorris7061 2 ปีที่แล้ว

    Coding Away, one of your video came up on in the background... 3 hours later, i think you're one of the best presenters on TH-cam :) Very knowledgeable and not afraid of diving down deep. Thank you for all your time and effort! PS i totally hate the python module system of 3.7 (we have some legacy code and we cant get off the damn version) - are there notable improvements between 3.7 and say 3.9 or even 3.10?

    • @brennorris7061
      @brennorris7061 2 ปีที่แล้ว

      OH! and if you even see the above comment I have to ask: are you able to target bytecode (WHL/Eggs?) written in 3.9/3.10 so we can write modules in newer versions and know they'll work on the older 3.7 codebase? i'm pretty new to Py - sorry if its a stupid question.

  • @WMRamadan
    @WMRamadan 2 ปีที่แล้ว

    Is there a blog post explaining dependency inversion in relevance to file structure?

  • @johnrperry5897
    @johnrperry5897 3 ปีที่แล้ว

    I love your lighting!!

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Thank you, John!

  • @iliqnew
    @iliqnew 2 ปีที่แล้ว

    AMAZING VIDEOS! THANKS!

  • @JabmarMusic
    @JabmarMusic 2 ปีที่แล้ว

    Thanks for the video. Can you tell me what Color Theme do you use?

  • @nestorguemez4846
    @nestorguemez4846 2 ปีที่แล้ว

    Excellent video

  • @tadastadux
    @tadastadux 2 ปีที่แล้ว

    1:10 - Dependency Injection
    1:38 - Dependency Inversion

  • @JamesWolfisz
    @JamesWolfisz 3 ปีที่แล้ว

    Not sure if your patch question was answered but you can patch __call__ of the class and return whatever you like.

  • @maikwiesmueller
    @maikwiesmueller 2 ปีที่แล้ว

    When I saw the title i got instantly triggered by the "VS" just to find out that I love this video. So was it clickbait? Maybe, but i love it!

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +1

      Glad you liked it!

  • @_hello_5346
    @_hello_5346 2 ปีที่แล้ว

    This is great, thank you.

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      Thank you, glad you liked the video!

  • @mpete0273
    @mpete0273 3 ปีที่แล้ว

    Amazing videos - keep it up!

  • @vikingthedude
    @vikingthedude 2 ปีที่แล้ว

    Hey Arjan, would you recomment injecting and mocking the builtin "input" function as well? How do you decide when to inject and when to just directly use an object/function?

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +1

      Hi @VikingTheDude, I'm going to release a video soon where I talk about unit testing and in particular patching and mocking. So stay tuned :).

  • @romulorff
    @romulorff 3 ปีที่แล้ว +2

    Awesome video and very illustrative examples, love it! I noticed you were running Python 3.9 so I would have also consider to use Protocols instead of ABC, which was introduced in Python 3.8

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +3

      Thank you! I’m working on new examples at the moment that rely on Protocol instead of ABCs.

  • @simonkufeld7903
    @simonkufeld7903 3 ปีที่แล้ว

    good explanation

  • @hakimbhd9736
    @hakimbhd9736 2 ปีที่แล้ว

    You are the best 🤩

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +1

      Thanks so much Hakim, glad it was helpful!

  • @grif.n
    @grif.n 6 หลายเดือนก่อน

    Is there a reason the PaymentProcessor needs to take an authorizer argument at all instead of there being another process_order method on the Order class which authorizes the user and then takes payment? Is it because payment shouldn't be possible without authorization every time, so the strict usage of authorize inside pay method is necessary?
    Would refactoring authorize and pay to happen separately but inside a process_order method also be dependency inversion?

  • @wing-keiwong9418
    @wing-keiwong9418 2 ปีที่แล้ว

    It looks like generate_sms() is not called as part of the new code. How will you retractor the codes so it is included when the class authorise_sms is used and excluded while authorise_robot is used?

  • @esatylmaz1476
    @esatylmaz1476 2 ปีที่แล้ว

    hello, authorizer is abc and has common functions, but when I give the sms method to Payment Processor, and intellisense like authorizer.get_sms_code() does not appear, how can I provide this?

  • @davidlayton5054
    @davidlayton5054 3 ปีที่แล้ว

    In your unit test you use a real authorizer instance rather than a spec'd mock. I've always used mocks to reduce coupling in tests, but that often convolutes the test and sometimes the mock behavior diverges over time. So I can see the merits of using the real instance. What are your thoughts?

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      I didn’t use a mock for the authorizer since it is a really basic class (not much more than a mock actually). If a class is relatively simple and is more or less standalone, I don’t have any issues using instances of it directly in the test. But then I wrok at a startup where we have to move fast sometimes, so that means making sacrifices once in a while.

  • @ChrisHalden007
    @ChrisHalden007 2 ปีที่แล้ว +1

    Great video. Would be nice to use bigger font. Very hard to watch full screen on mobile phone.

  • @Sidorvm
    @Sidorvm ปีที่แล้ว

    Nice!

  • @rjgonzalez8108
    @rjgonzalez8108 3 ปีที่แล้ว

    Thanks for sharing this high quality content. Very clear explanations. I'm learning Python coming from an embedded systems background. I need to pickup the language asap. I'm currently debating on whether to pay for.a course or teach myself with books, videos and doing projects. Would be great to know how you or others reading this have learned Python.

  • @MarkWernsdorfer
    @MarkWernsdorfer 3 ปีที่แล้ว

    thanks for the video! instead of a docstring or a rc file, can't you also just raise notimoplementederror for coverage to ignore abstract classes? or decorate them as abstract?

  • @davidlayton5054
    @davidlayton5054 3 ปีที่แล้ว +1

    Enjoyed the video. The patches are a smell for injection. It felt like you were going to inject input. Was that cut in the interest of time? It opens up so much extensibility.

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Ha, well spotted. I did cut a few things out to keep it from becoming too long.

  • @fjolublar
    @fjolublar 3 ปีที่แล้ว

    Great video but I am a bit confused. You removed the authorizer.generate_sms_code() from the actual code but you used it in the test case. You said you would go back to it but I seem to miss it. Isn’t that very important in the actual code? Where is it going to be run?

    • @fjolublar
      @fjolublar 3 ปีที่แล้ว

      in my understanding generate_sms_code() should be called inside the authorize method

  • @ice7mayu
    @ice7mayu 3 ปีที่แล้ว

    Thank you , ur vid is very helpful

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Thank you, glad it was helpful!

  • @TheDefirion
    @TheDefirion 4 หลายเดือนก่อน

    If I understood this correctly an extra layer of abstraction is created between the Authorizer subclasses and the PaymentProcessor, where do we define which Authorizer is used? Am I missing something

    • @TheDefirion
      @TheDefirion 4 หลายเดือนก่อน

      I think I got it, you pass this on the test by setting each auth on the various authorizers, something that would be the case should the code is implemented

  • @zdzichuWentyl
    @zdzichuWentyl 3 ปีที่แล้ว

    as always good work

  • @ComputerScienceSimplified
    @ComputerScienceSimplified 3 ปีที่แล้ว

    Incredible video, keep up the awesome work! :)

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Thank you! Will do!

  • @dariuszspiewak5624
    @dariuszspiewak5624 2 ปีที่แล้ว

    Arjan, is it not more convenient to use pytest instead of unittest? Seems to be simpler and (maybe?) more flexible?

  • @agamemnonc
    @agamemnonc ปีที่แล้ว

    Is this abstract class or "intermediate layer" as you call it an interface? If not, what's the difference between such an abstract class and an interface?

  • @paulorugal
    @paulorugal 3 ปีที่แล้ว

    Hey Arjan! Recently I've been diving into your videos, they're so amazing!
    Your knowledge is very SOLID and the references and arguments you use are very clarifying!
    Thank you for posting such amazing content!
    I started using python in 2011 and at that time people would frown when the subject was threads.
    Most of my peers would use Java saying the support for using threads was a lot better, do you think/plan on touching this subject?
    And/or even making some comments explaining if threads are helpful in the web development context or a microservices approach would be a better approach

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +5

      Hi Paulo, thank you - I'm glad you're enjoying the videos! I must admit I haven't used threads in many years. When I need asynchronous behavior, I'll generally use asyncio/Futures. But I can imagine there are still quite a few types of applications where threads are important (I just don't happen to work on those :) ). Async is a topic that's on my video list, so I'll surely cover that on the channel at some point.

  • @enricoroselino7557
    @enricoroselino7557 ปีที่แล้ว

    so dependency injection is the way to pass a class and inversion is the interface / abstract so the passed class not tied to one specific class. noted, thank you mr arjan

  • @alexbelov6287
    @alexbelov6287 2 ปีที่แล้ว

    Thank you!

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      You’re welcome!

  • @dawid_dahl
    @dawid_dahl 3 ปีที่แล้ว

    Thank you! 💙

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      You're welcome 😊

  • @k98killer
    @k98killer ปีที่แล้ว

    Dependency inversion is then something like the maxim "couple to interfaces, not implementations".

  • @sashacooper9326
    @sashacooper9326 3 ปีที่แล้ว

    As primarily a Rubyist, this feels like a halfway house to me between type checking and duck typing. I'm a big fan of duck typing wherever possible, and it seems like it would work perfectly well here - instead of creating the abstract class, I think you could just remove the assertion on PaymentProcessor that its authoriser has any particular class type?
    I realise that type checking is often valuable, but in cases such as this where you want something more flexible, why is dependency inversion better than just leaving the type fully open?

  • @nocodenoblunder6672
    @nocodenoblunder6672 3 ปีที่แล้ว

    I have a question. Composition is for example if a class Car has an attribute of another class ie Engine and if the outer and inner object have the same lifetime. Otherwise its an aggregate. So if each Car has the same engine by default(engine gets created in car) its not dependency injection only aggregation. If the engine is created outside of Car an is passed through init to assign to Car.engine it is both injection and aggregation. If Car has no attribute engine but uses the engine in one of its method that expects Engine it is only dependency injection. Is what I said correct?

  • @demidrek-heyward
    @demidrek-heyward 3 ปีที่แล้ว

    great content thank you

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Very welcome, Mathias!

  • @MrTulptuiz
    @MrTulptuiz 3 ปีที่แล้ว

    Man you are awesome!

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Happy you like the videos!

  • @MrCucolea
    @MrCucolea 3 ปีที่แล้ว +1

    Amazing content! Creating a video about testing and mocking with pytest would be very interesting in my opinion.

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +1

      Glad you like it Robert - and thank you for the suggestion!

  • @davidlayton5054
    @davidlayton5054 3 ปีที่แล้ว

    Great to see you solve the problem that you created by using the type system. It shows the cost of adding the type, but what is the marginal value (on top of unit tests)? The abstract class reduces the dependency to the interface the ABC defines, but if you'd not used types (and the interface was wrong) your test would just throw an attribute error that makes the issue just as clear. I honestly don't get it. Can you explain?

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +1

      Hi David, the Python interpreter completely ignores type hints - they don't have any effect whatsoever on what the code does when you run it. The main reason types are there is to provide help to the developer. Thus, types don't create problems, they make them explicit, and allow using tools like Pylance and Mypy to help you avoid mistakes while you're writing the software.
      I think it's a bad idea to use failing unit tests for establishing what the interface is between pieces of code. Do you really want to sift through a bunch of unit tests to figure out what kind of objects with attributes should be passed to a function as opposed to having that information clearly defined by types (which can then be automatically checked)?
      Finally, if you write code in a team of developers (which is probably true for many developers working on commercial software), types help establish what the interface is, and that + automatic type checking makes adding new code or refactoring existing code faster for the developers in your team.

    • @davidlayton5054
      @davidlayton5054 3 ปีที่แล้ว

      @@ArjanCodes thanks for the response. By problem I meant the coupling. After the pendacy is injected, there's no longer any dependacy on the class beyond the annotation.
      I see how something like mypy is useful if you're not writing tests, but I fall to see what it adds if you are. Is there an example of a type of issue MyPy would catch that a good unit test wouldn't?

    • @9e7exkbzvwpf7c
      @9e7exkbzvwpf7c 3 ปีที่แล้ว

      @@davidlayton5054 "Is there an example of a type of issue MyPy would catch that a good unit test wouldn't?" Yes, it is true that if you commit to having 100% test coverage static typing won't catch any errors your tests wouldn't. However, why sign up for 100% coverage and the time that entails when you can use static typing while being sure that the case of "are the types correct" is getting caught at build time?

    • @davidlayton5054
      @davidlayton5054 3 ปีที่แล้ว

      @@9e7exkbzvwpf7c Thank you so much for your reply. I definitely see the value in what you are saying. I do TDD b/c I program a lot faster that way-- not b/c I think it is the one-true way. So I'm personally already signed up to 100% coverage. I certainly see the value in tool like MyPy.

  • @Tekay37
    @Tekay37 3 ปีที่แล้ว

    This might just be a minor detail, but why did you choose "1234567" as the wrong auth code. Having to know that a valid auth code has to have exactly 6 digits seems like a hurdle for understanding. Why not use an auth code like "wrong1" or "invalid"?

  • @selimrbd
    @selimrbd 3 ปีที่แล้ว

    Is there a video where you explain the difference between a design "pattern" and "principle" ? It wouldn't shock me that dependency injection be called a "principle", same if dependency inversion was a "pattern". Is there a clear-cut difference between both or is it fuzzy ?

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว +2

      The way I view it is that a principle is more of a guideline, whereas a pattern is a specific solution to a design problem. In that sense, "dependency inversion" is a principle because you can apply it in many different ways, whereas the "strategy" is a design pattern, because it prescribes a specific organization of classes and methods. To draw a carpentry analogy: a design principle is "make your wooden construction such that it can support at least twice the weight of what's needed"; a design pattern is a dovetail joint.

  • @tokero5199
    @tokero5199 ปีที่แล้ว

    I'm new to python, I'm wondering why use an Abstract class for the Authorizer, why not use an interface?

  • @fmictsang8874
    @fmictsang8874 ปีที่แล้ว

    Thanks.

  • @pascalpfeiffer9088
    @pascalpfeiffer9088 3 ปีที่แล้ว

    Another great video!
    Where can I get the picture from the background?

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Thanks Pascal, that's just an image I created myself using a photo from Unsplash + added the two colors. If you send me an email at business@arjancodes.com, I'd be happy to share it with you.

  • @PawelOlas
    @PawelOlas 3 ปีที่แล้ว +1

    test_init couples your test to the implementation. if you decide to refactor and rename the variable to _authoriser, the test will break. IMHO you should test the public interface of the class to allow free refactoring of your implementation later. Technically "authoriser" variable is public in this example but maybe it shouldn't?

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Indeed, in a production application I would definitely hide attributes behind properties or methods.

    • @PawelOlas
      @PawelOlas 3 ปีที่แล้ว

      @@ArjanCodes I understand that you want to simplify the examples to demonstrate something but at the same time there are people learning from your code and they may think that this is what they need to do. They don't know that you do not do it in production code. I really like your lessons but as a learning resource I think the code should be perfect and production ready.

  • @programminginterviewsprepa7710
    @programminginterviewsprepa7710 ปีที่แล้ว

    But how do you inject objects deeper in call hierarchy??

  • @sloan00
    @sloan00 ปีที่แล้ว

    Can you check subtitle in video? It seems to not support English.

    • @ArjanCodes
      @ArjanCodes  ปีที่แล้ว

      Hey! Thanks for this, indeed, there was a problem, but I just fixed it! :)

  • @phaphiq
    @phaphiq 3 ปีที่แล้ว

    Very good video, I will check the other you have now :-)

    • @ArjanCodes
      @ArjanCodes  3 ปีที่แล้ว

      Thank you Jakub!