Dependency Injection | Prime Reacts

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

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

  • @zored1337
    @zored1337 ปีที่แล้ว +571

    Ohh fLiP dO yOur jOb

    • @TakenTooSeriously
      @TakenTooSeriously ปีที่แล้ว +28

      Scuffed audio

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

      mean

    • @WedgeTalon
      @WedgeTalon ปีที่แล้ว +44

      He probably could've EQd it out, but I bet he would make some lame excuse like editing 20 videos. Pfffft

    • @flipmediaprod
      @flipmediaprod ปีที่แล้ว +94

      i hate you guys

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

      ​@@flipmediaprodI for one, thank you, the videos wouldn't be as fun otherwise

  • @ivankudinov4153
    @ivankudinov4153 ปีที่แล้ว +475

    We need to praise code aesthetics more: amazing production quality, deep insights, real-world advanced examples, 0 bs. All been made single handedly by an independent small youtuber. Such a gem

    • @gagagero
      @gagagero ปีที่แล้ว +22

      "Don't write comments". It's all hipster nonsense. That is unusable in the real world.

    • @SlavaEremenko
      @SlavaEremenko ปีที่แล้ว +9

      It’s all hype no substance. Just read one chapter of POODR on dependency injection and you are good to go

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

      @@gagagero
      1. if you don't share an opinion, asking the other to stop "writing comments" is quite ignorant.
      2. Considering dependency injection unusable in for real world is even more ignorant. 🙂
      Or did I miss your point?

    • @joestevenson5568
      @joestevenson5568 11 หลายเดือนก่อน +16

      ​@@josefpharma4714He's talking about code aesthetics saying code shouldn't have comments, not telling people to stop commenting...

    • @abuDA-bt6ei
      @abuDA-bt6ei 6 หลายเดือนก่อน

      @@SlavaEremenko is it good if you don’t use ruby?

  • @EmilyGamerGirl
    @EmilyGamerGirl ปีที่แล้ว +36

    So, for the testing, they are testing the actual uploading code with the fake encryption- so if that test fails, you know the uploading has an error, rather than just knowing that the error is in either uploading or encryption or the key. Then for the encryption test, using a fixed test key makes total sense- and then integration testing by uploading an encrypted file, but, with a fixed test key still. This makes total sense as a great way to test stuff.

    • @Kenionatus
      @Kenionatus 11 หลายเดือนก่อน +8

      And he might have not shown all the upload tests that use mock encryption and mock storage. If you have a good mockup of the storage service (maybe Amazon provides one?), you can test error handling etc in isolation. Showing like 15 test cases wouldn't have fit in the video tho.

  • @asdqwe4427
    @asdqwe4427 ปีที่แล้ว +147

    I have three rules for DRY
    1: if the code has reason to change independently, just copy paste instead.
    2: if I notice that a function has become aware of where it is being used, I know that I messed up. Signs of this is when parameters keep getting added. Usually those parameters contain words like skip or include.
    3: don’t bother reusing trivial stuff
    Usually rule 2 is a result of not following rule 1.

    • @PoorlyMadeSweater
      @PoorlyMadeSweater ปีที่แล้ว +33

      #2 is a great. I call them slutty functions (they're too desperate to make everyone happy).
      I'd also add that base functions should mostly be abstract. If you find yourself writing virtual functions to avoid typing more words, you should either copy/paste or make a component. When I have trouble figuring out what a class is even doing (without digging through its parents), I know I fucked up.

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

      #2 is a symptom of mistaking syntactic repetition for semantic repetition. The former should not be refactored.

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

      @@DryBones111 likely, with a strategy

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

      @@PoorlyMadeSweater HAHAHAHAHAHAHAHAHAHAHAHHAAHHAA

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

      Yep, some ppl think I am being lazy, when I tell then to just copy the component and change it a bit. It is difficult to explain that those are different use cases and I am trading some duplication for less buggy code

  • @throwaway3227
    @throwaway3227 ปีที่แล้ว +245

    In Haskell, dependency injection is the norm (as your Monads are implicitly given to monadic functions when called, and they can easily be replaced with compatible Monads). Since it's such an integral part of the language, having DI everywhere is no longer an issue, since the typing system is so beautiful.
    I program in Haskell, by the way.

    • @HrHaakon
      @HrHaakon ปีที่แล้ว +51

      Like a vegan crossfitter... :p

    • @NNOTM
      @NNOTM ปีที่แล้ว +25

      I think it's worth pointing out that even though you say it's an integral part of the language, it's not like the designers of Haskell set out to design a language that has built-in support for dependency injection. It's more that the features you have available in Haskell lend themselves well to implementing dependency injection in a very idiomatic way.

    • @jonescity
      @jonescity ปีที่แล้ว +33

      Do you use Arch Linux too?

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

      Then you've got monad transformers which let you dependency inject your dependency injections

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

      Thank you for your service!

  • @deamorta6117
    @deamorta6117 ปีที่แล้ว +23

    Brother, you're like my go to for learning the how-tos of programming. Because of your teaching and memes i got a new job with higher salary. thanks Prime.

  • @yasscat5484
    @yasscat5484 ปีที่แล้ว +73

    the only bad thing about dependency injection is that it breaks my "Go to Definition" as IDEs can't figure out which implementation you want to jump into so they take you to the interface .. pain

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

      If you’re in Visual studio you can ctrl + F12 on the name and it will take you to the implementation.

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

      On Jetbrains IDEs this is not an issue.

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

      ​@@juxuanu it actually is, if you just use hotkeys and don't know there's a different one to get the implementation. if your current IDE can't figure out implementation from interface, it's time to upgrade to an IDE made in the last 2 decades. Or learn the hotkey.

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

      ​@@tsalVlog I'm pretty sure most LSPs can list implementations if I'm not mistaken?

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

      That's my biggest gripe with it. These graphs show you some data flow, which is nice and well, but actually seeing it is borderline impossible without a debugger. I don't mind that it can be complex (it has to be), but it's even worse to navigate than inheritance...
      And the simple thing is, that you "shouldn't" care about how the storage works, but you absolutely have to care when you deal with some obscure issue, or must extend it, etc.

  • @haph2087
    @haph2087 2 หลายเดือนก่อน +1

    11:50 I believe he's saying that:
    a) Amazon S3 is more likely to be the target than them, so if their files are stolen by somebody hitting amazon, they can say it was encrypted.
    or
    b) They have stronger firewalls around their auth server than the rest of their network, so if they get hacked, the hackers probably will have access to the database but won't have the ability to decrypt their database.

  • @bartkl
    @bartkl ปีที่แล้ว +127

    DRY is often misunderstood. The idea isn't to never repeat yourself, but to have all _information_ have a single source of truth. That is, you don't want to have to change some fact in several places since that will definitely come to haunt you.
    In the Pragmatic Programmers book they actually explicitly give an example of deliberate code repetition in case it represents different concepts/information.
    Just FYI :)

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

      So true! This is also why WET isn't really any better

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

      I think that's conceptually true, but in practice the "haunting" is often just having to change the same line in 4 places when it breaks during a refactor, which is often faaaaaar better than the deep rooted architectural cancer that comes with the dependency and inheritance spaghetti people use to avoid writing some simple procedure a few times.
      I agree that important dogmatic information is def something that should come from one source.

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

      @@PoorlyMadeSweater Yes I agree people shouldn't go nuts that way. Apply pragmatism at all times I guess.

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

      My personal very simple explanation is that I should not do the work for the computer, the work at which it's even excellent.
      Repetition should be programmed where possible, not directly written. And even in cases where I am in a situation where I actually need tons of duplicate code due to technical limitations, then it's time to look for ways to generate that code (metaprogramming, macros).

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

      @@jongeduard To emphasize the point I was trying to make: sometimes two segments of code might be identical, but they represent completely unrelated things, a consequence of which is that if one changes, the other shouldn't. Had you abstracted this repetition away, your code would've been harder to change for the wrong reasons.
      Not disagreeing btw, just wasn't sure if I made my point clearly enough.

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

    Having had quite some dozens of juniors come and go, a good chunk of them try to think of the pattern before prototyping. Some of them have this mindset of "If I use a good pattern from the start, I won't need to rewrite anything". Then they come up with the most convoluted solutions to easy problems. That was before we had code review so thankfully things are way better now.
    I understand this line of thinking, and it makes sense on a logical level, but never on a pratical level.
    And yeah, I think 99% of the good readable and testable code are strategy patterns that spawned after a functional prototype.

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

      I agree with this. Even seniors I encounter are often bent on using design patterns everywhere. I tend to favor using patterns when they become apparent in what I'm doing as opposed to try to shoe horn some desired behavior into a pattern. Only exception to that is when I'm thinking architectural patterns when standing up or integrating with a service

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

    You know you've gone too far with Dependency Injection when you're struggling to find your concrete implementations.

    • @icoder1117
      @icoder1117 3 หลายเดือนก่อน

      😂😂😂

  • @paklenizmaj
    @paklenizmaj ปีที่แล้ว +6

    I agree, don't repeat yourself a lot (3-5 times is fine) and code first so that things work, then you can clean and optimize. once you start cleaning and tuning, you can write tests to be sure and stable, before that you don't need the tests too much.
    Greate video and great comments ;)

  • @stevenhe3462
    @stevenhe3462 ปีที่แล้ว +10

    The downside is simply that you have no idea WTF is happening when you enter a new code base full of DI.

    • @vlad071096
      @vlad071096 10 หลายเดือนก่อน +1

      Yeah, just a bit of a downside.

    • @julkiewitz
      @julkiewitz 9 หลายเดือนก่อน +7

      That's not DI. That's just how reality works. When you enter a new code base by definition you don't know what it's doing. DI is not preventing you from finding out. It's like saying splitting code into multiple functions instead of having one giant block of code is preventing people from knowing what's going on. It's not.

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

      Been there. It mega sucks.
      I try to avoid it unless necessary as it can become one of those things where you “just have to know” what’s happening.

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

      Yeah not DI's fault tbh. New code based will always be somewhat confusing. Skill issue tbh. DI is one of the easiest solid principles to understand and follow in code imho

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

      @@brandon14125 It’s not necessarily that it’s not easy to understand. But you have to understand the timing happening in a program holistically to know when and what a certain function should be performing. If you’re reading a single file, it’s sometimes not obvious that the function will not be performing what is initially assigned (Though, this can be made obvious by saying “my_func = lambda: None” with a comment or something).
      Further, it’s something can get out of control fast. A couple DI’s in a project? Fine. Dozens and dozens? Now you create a web that is likely very straightforward for the person who is writing it, but will take quite a while to sort through mentally.
      I also disagree with “new code bases will always be somewhat confusing.” That’s reducing something that’s very nuanced and can be judged on a curve to something thats black and white.

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

    22:00 that's literally the entire concept behind languages like haskell- that's why you have pure functions that do your computation and then everything that interacts with the outside world happens through the io monad.

  • @EricChamberlain
    @EricChamberlain 2 หลายเดือนก่อน +1

    Thanks!

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

    The testing issue raised around 23:50 is something I run into a lot, especially with teams that are just starting out on their automated testing journeys. I have a simple rule: If that mock could conceivably be used in production (e.g. sqlite instead of postgres, a file directory instead of s3), then its a useful mock. If it would be worthless in production, its a worthless mock, and a worthless test, throw it away. For those, the only real way you can test them is to spin it up in docker compose or k3s and test it for real.

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

      Unit tests that ensure that some service burried deep within a method is called with the parameters you expect are useful and important and they should use mocks because you are are testing the service call itself, not what happens after.
      I like to divide unit tests in 2 categories: testing pure functions or testing lateral effects. In the former you test expected outputs for given inputs. In the latter you test that a class/service/whatever (eg an api or storage) gets called like you expect it to. Both are important IMO. But of course to test the real deal you need integration tests and there your statement is of course valid.
      So perhaps I misunderstood something but I don't get the lashing on mocks/stubs

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

      @@joaomacedo673 "Was this called or not" is not a terribly useful test. The common way to mock such a thing is to validate that the arguments passed match what is expected and to return a canned response. This seems useful when you first look at it, until you realize that you've encoded your assumption about how that remote service behaves into the test. Its one step above running the test, capturing the output, and then updating the test to assert the output is what you just copy pasted. It is not testing anything except that no exceptions were thrown/errors returned. The only useful test in such case is one in which a representative-enough replacement is used, such as sqlite for a real DB. If you cannot test the intermediate logic without having it try to call to an external service, that usually indicates soon-to-be catastrophic architectural issues.

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

      ​@@BloodEyePact I'm talking about testing the service/database/wathever is called with the arguments it's supposed to be called. What that call returns and what happens after doesn't matter in the case I was talking about, as one is just concerned that under specific circumstances your method performs the call with the correct parameters to produce the intended side effect.
      In fact I don't see the point of replacing the actual implementation of the database or filesystem by some other that could be viable in production. It's either the real deal (integration testing) and there, yes, you test the whole system/subsystem end to the end, or pure mock to assert the side effect call is performed as it's supposed to (unit testing).

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

      ​@@joaomacedo673Testing that a service was called or a database was queried is not a useful test, unless the software in question is specifically about making that call/query, because that is an implementation detail, and tests should never test implementation, only behavior observable to the user (whether that user is someone behind a browser, another program calling a library method, etc). You replace the implementation so as to not depend on external services which is poison to test reproduciblity, and therefore, result validity. Testing that a call was made with parameters assumes you know the correct parameters/query/etc to make, which you don't, and encoding what you /assume/ the correct parameters/query/etc into the test invalidates it, because it only tests that it matches your assumptions, not that your assumptions are correct.

    • @NoOne-ev3jn
      @NoOne-ev3jn ปีที่แล้ว

      You test a scenario, that dependency in that scenario is just behaving normally, in another scenario we can make it fail.

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

    Mocking allows you to test the happy and the bad paths... So you can tell your mocked dependencies to return a bad result or a service outage or something from your result and handle that in the tests that way you know your code is going to handle everything properly...

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

      sort of
      this works with services you run and control, it gets a bit more different when you are mocking a service you don't know (everything) or control

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

      ​​@@ThePrimeTimeagen yes, I think this works well for our services and well documented third-party services

    • @comradepeter87
      @comradepeter87 ปีที่แล้ว +27

      @@ThePrimeTimeagen But if you don't understand the service you're using completely, then you probably also don't want to handle all of its errors. You probably just want to catch ThisService::SaveFailedException, and in that case, a mock impl that just returns a generic "shit went bad", would be equivalent.

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

      It comes down to costs often. It is harder for some teams to get the budget so have to mock/short circuit/substitute the costly resources so they can validate the rest of the pipeline. We depend on SLA to provide the certainty of those resources and then being validated during integration testing.
      Ideally you would never want to mock it and your team would have it budgeted.
      @@ThePrimeTimeagen

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

      ​@@ThePrimeTimeagenthat's the thing. With unit testing you are testing a unit. You don't want a broken AWS or a broken image scaler to break your uploader test. These should be tested separately, so when something breaks it doesn't affect testing of your other components which are not broken.

  • @driesvanheeswijk1633
    @driesvanheeswijk1633 2 หลายเดือนก่อน +1

    I love your honesty and you not being afraid to show a little vulnerability. I really love it. Hope you've found some time to relax :) although it's been a year so I assume you have... right? (O_O)

  • @timseguine2
    @timseguine2 ปีที่แล้ว +72

    Strategy Pattern is one of the things that always seemed so obvious to me that I question the utility of giving it a name.

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

      Yes! I was just like: This shit has a name?? But as he said it just comes with experience

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

      try other patterns, get out of your comfort zone!

    • @timseguine2
      @timseguine2 ปีที่แล้ว +11

      @@pah967 That's a weird comment that assumes a lot I didn't say.
      "Strategy pattern is an obvious pattern" does not equal "Strategy pattern is literally the only pattern I ever use."
      Turning your comment back around: maybe don't give unsolicited advice especially when it is also not even relevant advice.

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

      @@timseguine2 well, based on your reply to my half-assed attempt at promoting exploration, I can only say... well aren't you a belligerent self-important c*nt?

    • @RainbowVision
      @RainbowVision 11 หลายเดือนก่อน +4

      ​@@pah967in addition to the above, if you're only hitting nails, then all you need is a hammer 😉 using some arbitrary design pattern for the sake of it is a quick way to ruin your code

  • @djyotta
    @djyotta 24 วันที่ผ่านมา

    27:02 I once had a colleague of mine tell me that I should write it "the right way" the first time. But invariably, the right way is only clear after almost fully implemented.

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

    7:55 Noooo! It should actually be possible if foo is defined as type {a: number}. However the "as const" with type inference sets the type of foo to its strictest interpretation:
    let foo: {a: 5} = {a: 5} as const;
    so
    foo = {a: 6} is invalid, because 6 cannot be assigned to something of type 5, which is what the error message actually says.

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

      because typescript's "as const" tells typescript that the variable's value is known at build time, and I don't know a single language that allows you to modify a truly constant variable like that.

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

      @@arjix8738 Maybe in a shallow sense. It depends, what you mean with "the variable's value", because:
      let foo = {a: Math.random()} as const;
      is valid typescript, even though the value of foo.a is not known at build time. Also I don't get how this is related to my original point.

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

    23:14 Code Aesthetics literally explains what the point of all the mocking was, right before @ThePrimeTime pauses and says "I don't get the point of all this mocking". The point is to test the uploading service in isolation. Later on you test your encryption service in isolation. Later still you test your S3 storage service in isolation. The point is to make it easy to determine where any potential bug is. If you didn't isolate the services with mocks, and your test failed, now you have to go in and hunt down exactly where a bug is occuring. By isolating all the services, you know that when a test fails, the bug is ONLY in that tested code, and not in an upstream service.

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

    "I don’t like the term `dependency injection` because it sounds lot more fancy than it actually is." 😲😲😲
    You just became my most favourite programmer of all time!

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

    Without being a big fan of using mocks for integration tests they make a lot of sense in the case that you do black integration testing and white unit testing.
    That way you can make sure that the units conform to the interface and the mock getting a lot of depth from those tests, then the integration tests can be very shallow and be very wide with minimal effort.
    This allows for great coverage at the cost of minimal brain power, you can then argue if that is worth or not.

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

    I think the unit testing at 24:49 helps guard against regression. You assert behavior this way, and if tomorrow some dev comes in and decides to refactor because he doesn't like the way it was written, you'll catch any functional braking changes introduced. I also had a hard time with this time of test initially and found them useless, but on large projects they are very useful. Granted, e2e tests can also cover this, but you have to write a lot more code to cover possible scenarios because of all the other branching that can occur.

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

    New to the channel. This guy is so way over my head, it depresses me. There is just so much to know and understand.

  • @on-hv9co
    @on-hv9co ปีที่แล้ว +5

    "...comes down to two patterns: [builder] and [strategy]" - parsing library maintainers catching strays

  • @genejas
    @genejas ปีที่แล้ว +6

    You can't EQ out clipping. The closest you're getting to removing clipping is using something like the declip module in izotope rx, which luckily is pretty painless to use

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

      very good call rx is really nice

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

    I cant imagine not using DI in C#, usage of factories like in Java is not required at all in C#, we can use a nice DI container like Autofac,Ninjact etc for Strategy pattern (multiple implementations of same Interface) and resolve them at runtime using a key. In .NET 8,keyed resolve is also supported bt default DI container.

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

    In elixir there is pattern matching on function args. It removes all of the if/else and makes it duper easy to parametrize behavior... Uh i mean, "inject dependencies" (did I use the fancy words correctly? I need to impress the Jr devs while making them feel dumb for not understanding my big thoughts right away)

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

      It also makes it much more easy to understand when you declare the struct type on the pattern. As opposed to declaring some generic interface and then trying to figure out which classes are implementing this interface.

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

      I actually prefer a straightforward switch/match statement instead of hunting for another declaration of the same function buried somewhere in the file.

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

    My last BIG project was one based upon a DI framework (in Java). It was great. However, there were times developers created some spaghetti apps where they created DI apps that data could get lost in. I think they didn’t design or think out their app well. While “not my code”, I would often get called at midnight to fix it. The code from our group based upon this framework had very few problems (most were traced to 3rd party data providers). We would work as a group to talk through data paths in our app. Worked well.

  • @RainbowVision
    @RainbowVision 11 หลายเดือนก่อน +1

    I think the difference between strategy and adapter pattern is that strategy uses different interchangable components for different outputs / side effects and adapter uses different interchangable components, but we expect the result to be the same whatever implementation you use.
    I do think he showed us more adapter patterns than strategy by that definition, but it is a very fine line nonetheless.

  • @GingerGames
    @GingerGames ปีที่แล้ว +78

    This is one of the reasons why I hate OOP (not necessarily objects): all of the stupid names for simple things. "Dependency Injection" is just passing objects to procedures as a value. WHY DOES IT NEED A SILLY NAME LIKE THAT?!

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

      Its just a fancy name for composition where object is determine at runtime either by configuration or automatically. hell I used spring since 1.x, never heard the term until 3.x

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

      DI is not unique to OOP and has nothing to do with it. It's a general term that generally describes the concept.

    • @GingerGames
      @GingerGames ปีที่แล้ว +27

      ​@@deallocThe only people who use the term are OOP people. Everyone else doesn't even bother naming it because it's such a trivial concept, and only seems "great" if you have been doing insane OOP things.

    • @thewhitefalcon8539
      @thewhitefalcon8539 ปีที่แล้ว +6

      It's a pattern. It's not every time you pass something to something, it's a specific type of passing something to something. You're asking why we don't just call singletons static variables and the answer is that not all static variables are singletons.

    • @GingerGames
      @GingerGames ปีที่แล้ว +10

      ​@@thewhitefalcon8539I am not asking about calling singletons. I am literally saying that "dependency injection" is a silly name, not that is a bad idea.

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

    some luv to the editor, 20vids a day is insane!!

  • @andrew_ray
    @andrew_ray 6 หลายเดือนก่อน

    7:58 You can have a pointer to a constant, but you need to give the type implicitly because "as const" forces TS to infer a narrow type. let foo = { a: 5 } as const; gives foo the type {a : 5}, to which { a: 4 } is not assignable.

  • @dan_le_brown
    @dan_le_brown 11 หลายเดือนก่อน

    24:52 I'd argue that it's a way to test your critical paths or what i like to call "best case scenarios"-at the end of which you'd have provided value to your users

  • @stroiman.development
    @stroiman.development 8 หลายเดือนก่อน

    This example uses dependency injection as a way to implement the strategy pattern, which does make sense to some degree (Was there a test verifying that the correct dependencies are injected in the production version? A pretty crucial part of the solution)
    But for the vast majority of code that I've seen, there is NO strategy - no alternate implementations of behaviour (in production code). It's just, the DbContext is injected into the UserRepository. The UserRepository is injected into the UserManager. The UserManager is injected into the UserController. And then each of these are tested independently with a ludicrous amount of mocking (I've seen implementations where the very thing to test had been mocked out).
    The hip bone's connected to the ...

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

    In python, I usually have a default implementation of e.g. a Repo, that does exactly what it should do, and inject it. So the usual work of DI based usecases for clean arch become self-sustainable, and only while testing, I replace the dependency. I am not sure, why everyone shys away from happy path defaults. It makes it a lot easier to deal with, than having endless debates whether we should dependency inject this or that here or there, which is usually won by the guy who wants everything explicit, with ten interfaces, and quits the job right after everything has been refactored to this overexplicit mess.

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

    TypeScript "as const" is *type narrowing*. I.e. narrow it to the most specific type possible. So `{a : 5}` is typed as `{a: number}`. but `{a: 5} as const` is typed as `{a: 5}`.

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

    Us FPers staring at the OO crowd for giving some fancy name to passing data as a function argument.

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

      It's not passing data, it's passing an implementation hidden behind a facade.
      Us FP guys asking, why a lambda aka strategy pattern isn't sufficient.

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

      @@McZsh It's still passing data because, in OOP, implementations are data structures.

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

    "The secret to good writing is re-writing" - this is golden. I often tell juniors that one of the most important skill is the ability to discern when code needs to be refactored, and the stamina and rigor to do the refactoring.

  • @KennethBoneth
    @KennethBoneth ปีที่แล้ว +45

    OOPERS when they discover function parameters, "THIS IS THE BEST PATTERN EVER!"

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

    There is no silver bullet when it comes to programming. Things that appear common in the beginning end up having slight differences later on down the line. The realm of software development now vs 20 yeas ago (that I have noticed) is that code is expendable, don't try make it immortal.

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

    DRY...man I'm using Dapper on one of our projects...I don't even remember what the using statement looks like because I wrote it just once, and copy-pasted it a million times whenever database requests were needed.

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

    I see some value in DI/mock/tests in that you can ask the simple question "if y is working, why is caller x (or forward call z) blowing up? If it's not working, how does x (or z) handle it?". That simple yes/no will suffice for most things. It can even help with transient conditions if (at the boundaries) your parameters are reduced to a "generic" message passing object that both carries back the reply, if any, AND the state of the "operation". Your caller must now decide if when presented with "failed because of K" it wants to just fail, or handle the fail and retry, or....,etc.
    For me though, the true value is that it burns into you the idea of "interfaces at boundaries". Going forward, even when you're not using any of it, you start to instinctively "feel" when you crossed the line between (what should be) a and b components. Eventually you start NOT doing "monolithic" and also stay away from "abstraction i don't need". Hopefully...
    p.s. loved the SQLite mention. Had to "hard sell it" to my colleagues the other day and boy, was it a tough battle... What brought it home was the logical conclusion that if you wrap all of it in a "container", you can actually commit the state to a file at any point AND restore from that checkpoint at any time. The value of that when testing for "elusive bugs" can not be understated.
    p.p.s I only use SQLite when things are stable enough. First port of call is a simple "memory mapped" container that can be checkpoint'ed to/from a json file. It mimics "ideal conditions" and let's you test the code "if all was working properly". If so, and when the overall architecture is "stabilized" you move to the SQLite implementation so it's easier to do postmortem analysis if needed. Best part is that, using any of these (and client allowing), we can pull the live data from the SQLServer/MySQL/etc at any time with a tool, save it to a file, transfer it and our support team can play around with it to see what is happening when under clients state in an environment with full debug capabilities. Can save you a LOT of time over having someone checking it at the client's front end while someone else is sifting through backend logs, dead and live.

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

    love the smug ass incorrect pointer assumption that you then fail to prove. really nice dude *chefs kiss*. confidence inspiring

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

    27:50 that’s my problem. I learned SOLID and other design patterns and now I end up using dependency injection and abstraction and all that…. Before I even have more than 1 implementation for my interfaces. I try to design the app around abstraction instead of just coding and if something goes gross refactoring.

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

    @23:54; And importantly, you're not testing them together, integrated - you're not testing that the Encryption *also* works with the S3 uploading stage. They might work separately just fine in individual unit tests, but then fall apart when used together.
    Like, as I'm reminded as I've recently saw your video about the CrowdStrike report, they tested their file template generation, and they tested their file template parsing...but not their file template parsing *with* the file template generated. Because of the Dependency Injection of the generated file template, they didn't actually test that the file generated from one test didn't just generate validly, but also can be validly parsed by the code that will be parsing it.

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

    The moment you defined `as const` as the "pointer to a constant", I immediately thought about trying the exact same experiment you did with `let`. Glad you covered that 10 seconds later.

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

    is S3 the "ExtraSpace" of data? can we buy storage containers of data that people stopped paying on? get a bucket full of old christmas ornaments and boxes full of newspapers hoping to find a Amazing Fantasy 15?

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

    i mean. here's the thing. experts in anything know the exceptions to the rule. we teach DRY because it's a very valuable concept. it's more about don't cut and paste the same code all over the place, abstract it out, make it easy. i've been out of things for a while, but i never heard the Extreme folks saying DRY in relation to patterns, DRY means abstract out common code so you don't have to maintain and debug 10 separate instances of something that could be done once.

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

    "There's only one implementation of..." I know where this is going.
    @24:30 the sample test code can have multiple implementations - always happy path, always sad path, slow network, dropped network, etc

  • @AlienAndrew51
    @AlienAndrew51 6 หลายเดือนก่อน

    Whats your opinion on e2e testing mircroservices or approach? I'd like to use test containers for integration test but it's an uphill battle to get a sign off on it for the enterprise version. I do agree that mocking usually causes issues and you end up always finding bugs due to something external not working as expected. For e2e we had to build out a microservice to test all the other services which I'm not a fan of.

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

    I saw the original video and since then i refreshed your channel every few hours waiting for a reaction.❤

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

    ThePrimeTime.... at 07:51 ... you can basically just call that a const, and then change the values... you can update everything in the const object, you just cant re assign it

  • @vojtasks
    @vojtasks 6 หลายเดือนก่อน

    The problem with DI and OOP (which DI isn't the only thing used) is that, it relies heavily on abstractions. You always cook something over some gigantic amount of some object that all are abstractions over abstractions.

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

    This is one of my favorite patterns for plug-in type systems. Turning DI into abstraction hell is a code smell.

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

      there cannot be to much if your language supports it well. that's why some languages even have special DI syntax sugar.

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

    While doing Advent of Code (which I'll finish later...), I often deduplicated code that would only occur twice, but that's a bit contrived since you know that most of the code will overlap upfront.

  • @HobbitJack1
    @HobbitJack1 6 หลายเดือนก่อน

    One thing I remember from somewhere is that *locality* is a key principle for code readability (as with all things in software, it's a principle, not something to overdo) and it seems DI really helps keep locality and so that's part of what helps keep it readable when it's used right.

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

      DI adds more indirection. How does that help with locality?

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

      @@youtubeenjoyer1743
      It helps improve logicality at a given level of indirection. If you're reading code, it can be helpful to read through it and treat it as a black box until you have time to go down that road. This is especially useful when you're doing someone on someone else's codebase. You don't need to know how a FoobarGrabber works, only that you're given a FoobarGrabber and you can use it to grab a foobar. So long as you don't need to understand the implementation details of a FoobarGrabber, by treating it as a black box you can just keep reading the code.

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

    In this video the business logic was trivial so unit testing isn’t particularly useful. But it might be excessive to create an example project that has business logic worth testing, for a video like this.

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

    Dry is bad when you refactored out code that actually wasnt the same and have to start adding multiple conditionals in it to gandle different use cases.
    This is especially annoying/hard if you pulled it out to a shared repo as you cant stop allowing the old pattern or else yoh may break other code.

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

      DRY only tells half (or a third of) the story - "repetition exists, and you CAN abstract it to reduce it".
      abstractions cost design time, a brain context switch every time you encounter them, and maintenance costs when the abstraction needs to be modified. those costs pile up. and the maintenance of a premature abstraction can cost a lot.
      you have to balance those costs against the value produced, and the likelihood of change. otherwise you may be increasing your total workload, and your complexity tax, without getting much value out of it.

  • @djyotta
    @djyotta 24 วันที่ผ่านมา

    When I first began .Net development I was shocked to discover dependency injection is a thing. And professional developers were encouraging it. In my view, dependency injection is an anti-pattern that no developer should be using. I'm referring to .Net crazy DI container not "dependency injection" referred to in this video... which is really just normal use of interfaces.

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

    The separation of logic and I/O is the ports and adapters or hexagonal architecture pattern and yes, it's very useful. But also it can be taken to an extreme and become a nightmare. Don't ask me how I know this 😅

  • @iNuchalHead
    @iNuchalHead 11 หลายเดือนก่อน

    17:10 DRY is aspirational. Don't does necessarily mean never. Nice to hear this!

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

    The monad is considered a functional design pattern I believe. 🤔 Another one you come across often is the Facade pattern and the Singleton.

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

    16:58 The proper phrase is actually "Avarice is the root of all evil". 🤓

  • @outwithrealitytoo
    @outwithrealitytoo 11 หลายเดือนก่อน

    In the land of C: a struct type containing - an enum to switch on and a "union of struct types" for the parameters... Add in a test/mock type and its all good for unit tests. "What if someone passes the wrong parameter structure?" well, then you have personal and integration problems that compiler checks won't save you from.
    Abstract the APIs behind open,read/write close file interface a la Unix...
    What about the weird and wonderful things that can go wrong with each storage method? Generally "something went wrong" is important for control flow. "What went wrong?" that's a debug issue (and that is why Golang error handling works like it does). In my experience... code that properly handles something going wrong at any time, is rare enough... and using "what went wrong" in control flow is abused or only partially handled.

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

    You don't test a car by just going on the road, but you test the engine on a dyno, the tyres by checking the wear and slip in wet conditions, etc. You want to test thing individually to see where it goes wrong. Mocking and simulated environments can be convenient for this.
    But in general, testing to me is just taking the code that I already wrote to see if everything worked and saving it.

  • @bugfacedog44
    @bugfacedog44 10 หลายเดือนก่อน

    It looks like Manim animation to me (which is indeed a Python library). It was developed by 3Blue1Brown for all of his math videos.

  • @Quantris
    @Quantris 3 หลายเดือนก่อน

    builder pattern: what is my data
    strategy pattern: what do I want to do with it
    yup, checks out, this pretty much covers everything

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

    21:57 Yes, this! I try to split components by those who work with data and those who work with timing and DI is nice for that.

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

    I don't use TS but one way I solved having multiple sets of parameters is to have a lookup object table. The class must be constructed with, for example the storage service to be used. Then the object map provides autocompletion for the rest of the parameters using JSDoc. I don't have types for the class but it is well documented and autocompletion is a chef kiss.

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

    I'm genuinely struggling to tell apart "bad" inheritance from "good" DI
    For me inheritance was always different implementations of the same interface
    And DI was a bunch of spaghetti where function declared within a function is passed as an argument to another function and two weeks later no one knows what it does and how it works.

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

      if you're abstracting things, it better produce value now.
      abstracting just because you can and just because you "might" need it results in what you described.
      as far as DI: the more you can push your configuration to the top level of your program, and the more coarse you can make your configuration, the better. the more decentralized component selection is, the more confusing the program will be. if you have a ton of different factories spread out throughout your code, then you're probably making more of a headache for yourself.

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

      Controversial: Because it's virtually all bad. DI is a function pointer, used to solve the adaptability problems coming from mapping data to fantasy mental models that happens in OOP land. I think data structures (aka "objects") just need to represent the necessary data for the relevant usage. But OOP is full of solutions where objects represent functionality rather than data - which is an unnecessarily complex (and rarely a good) solution that turns into more trouble the further you go. I think applications should be built by being specialized instead of generalized, and having layers where the bottom is what's least likely to change and the most likely to change is at the top. Not having all your data at the bottom.

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

    22:10, that's what Haskell claims to do through types (String vs IO(String))

  • @lexer_
    @lexer_ 10 หลายเดือนก่อน

    Mocking is wonderful to simulate failures upstream or downstream of the thing you want to test. It's also useful if the actual task is way too expensive or slow to run. Otherwise you are probably better off not mocking.

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

    Typescript type mapping: If I look at this, it screams classes or interfaces to me. There is a functionality - upload() - that's polymorph. So instead of these if's and the various parameters, we have an object passed in and all the function does is to call object.upload(). Of course we don't need the function anymore, it literally has nothing left to do. I'm not saying everything is or should be an object, but if there ever was an example where using an object is natural, this is it: A common intuitively understandable functionality that is implemented differently by various instances: "interface AttachmentService { upload(an: Attachment); }". Then you can have a factory or you can inject the service, whatever makes stuff easier to understand and handle. Who in their right mind would write a function with if's discriminating over implementations of one functionality? That was questionable style in 198x in C64 assembler. It's 2023 now.
    You can of course create a type map for all possible parameter combinations of all implementations and probably get that to become type-safe with TypeScript. But who would do such a thing? Who would update the interface every time a new backend is added. Who would document that? Who would want to read this documentation? You have to be mad to even consider such a thing.
    Not even mentioning that most of these parameters contain sensitive info, such as passwords. Exposing them like this makes you life hell if ever you had to distribute that code and then have to reorganise it to get the secrets out of the parameter lists. You cannot possibly get it more wrong.

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

    The point is you need to balance between Reuse and Ease of use. Same as when someone says composition over inheritance. NOOOO. You need to understand when to use what. But 1 thing never fails, make it as simple as possible that doesn't jeopardize functionality and testability.

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

    Isn't this the one that showed how he made his videos with PowerPoint? Or was that no boilerplate?
    I just never got how he called his channel code aesthetic but then never followed the standard coding style for C# (e.g. he uses camel case method names), and now apparently spent 5 months learning TS doesn't follow it for TS either (e.g. he uses snake case). Next he will switch to rust and use kabab case.

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

    No the problem is people take SOLID principles so seriously that they end up with mammoth 100m+ lines unfathomable behemoths that no one understands or wants to work with.

  • @NoOne-fe3gc
    @NoOne-fe3gc 10 หลายเดือนก่อน

    A lot of this can be dumbed down and distilled to this simple thought: Whenever you are implementing a functinality, always keep in mind "who's concern is this", e.g. Where the data will be stored, how the data will be scanned, and even WHAT the data is, is NOT a concern of the UploadRequest, so it SHOULDN'T KNOW anything about

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

    I don't use dependency injection as extensively. I use a mix of dependency injection and dependency requesting or dependency obtaining.
    DI is already explained here.
    DR or DO are similar but differ only on where the login for having the dependency is.
    In DR, the class/object knows who can provide the information and it requests that said object instance or just piece of data from that external entity.
    In DO, the class/object knows where the source of information is for something it requires to work.
    Although in enterprise they like to DI almost everything, I'm more the kind to just do a mix of the 3 depending on the context. I'm not that much of a fan of the only way being having code (mine or from a lib/framework) to fetch and provide the dependency to the class. Many times, that said class already knows where to get it and just gets it instead.

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

    I learned a lot watching the video you're discussing, mostly things I didn't know how to do.
    But "how" it's done is to me, nice and clean.
    I believe I got to the video from a video talking about using composition rather than inheritance.
    So, both the "favor composition" and "use DI" were to me 👍👍.
    I appreciate your comments as well Prime.
    Thanks to all.
    Will investigate the strategy, builder, and factory patterns much more now.

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

    Polymorphism is an OO contruct oft utilized in patterns. It is simply the ability for the caller to execute code without knowing the subclass implementation. That's it.

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

    What you tried to do with Typescript might be `interface Foo { readonly a: number}; let foo: Foo = {a: 5}; foo = {a: 42};` Reassigning foo is fine, but the value itself is constant. `foo.a = 69`; is not valid.
    With a lint rule in eslint-functional , you can force all interfaces to be readonly like that and make ts an almost functional language.

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

    For any c++ person, to whom all these buzz words sound like childish giberish, this is basically using interfaces and inheritence where you pass the object pointer under the interface type. (And you allow others to also implement that interface any way they see fit)

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

    Unit test is just only the first line to make sure the logic is running fine, as we trust the other dependencies (we dont develop them, and they have their own test with other dev team and got pass QA and delivery to us) so we mock them and pretend they are good at functioning as they should be. Integration test or e2e test should have more meaning than this, but this is the first, quickest and most convinient way to build up your peace of mind in development. Also, due to unit testing later in mind, you will be tending to write more modular code, better code, better isolation logic.

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

    All programming is about reducing indentation, AKA SINGLE RESPONSIBILITY + DEPENDENCY INVERSION, AKA reducing cyclomatic complexity, AKA making code easy to test.
    The first step (following TDD dogma) is to write a test that asserts that your code does something, the second step is to make your code do something, the third step is to make all the things your code does simple, the fourth step is to compose those things in such a way that they do the original thing and the fifth step is to ensure that you're not doing too much work to make that composition happen.
    I don't follow TDD dogma, so I do the first step at the end, and test manually in-between.

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

      He missed the part where you simplify the composition, and you conflated that he was talking about unit tests as opposed to integration tests. If you write tests first, start at a high-level.

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

      Replacing if/switch statements with dynamic dispatch (AKA SINGLE RESPONSIBILITY + DEPENDENCY INVERSION) does not reduce complexity. The branch is still there.

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

    Fully agree with the take on testing at 24:14. What you want there is maybe an integration test but a noop pipe through test is pretty pointless unless you want to check your input validation. To many goofballs go mental about 100%, or close to, test coverage

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

    I loved that comment. Most of programming is using builder pattern and strategy pattern. I agree whole-heartedly

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

    At 23:55. You are correct. You are not testing anything. You should be stubbing these APIs at test time and verify that the value you stubbed with is the value returned at test. It localizes the data being worked with and avoids the issue where your mock just returns a dummy value. or passes the value through.
    The traditional way of doing these mocks causes a problem where you end up requiring mock classes. you end up writing test classes, etc just for testing. What I do now is use protocol witness where the default implementation raises a fatal error. During production, these values will always be set. At test time they won’t. This
    1. requires the tester to understand a dependency used during test, forcing them to mock the resource
    2. the witness can be assigned a function pointer (or closure) that is localized to the test, which makes it unbelievably easy to see what is being tested and what is expected to return by the dependency.
    This is a long shot, but I’d love to show you the pattern. HMU if you’re interested.

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

    My advice is to always use DI even if you aren't using an IoC container; passing deps in through a constructor manually is still DI. Always pass your deps in through the constructors.

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

      I agree - but technically passing dependencies through constructor is not DI - it is just composition if you think about it. The term "injection" implies you are not manually doing it, but some framework is doing it for you - lets say with reflection, or if compile time, then through some kind of pre-compilation, language support etc....
      So no... what is presented here is technically totally not DI - but the way to pretty much emulate it manually. The point of DI is to not do this and thus remove boilerplate codes and make it product-level configurable what is being used.
      Of course I still think it is a good idea to add your dependencies via constructor - but I like the naming to be proper, because lets say I can easily imagine a native language where you would have either compile - or even deploy time - real dependency injection of components and even not just single ones, but like array of components to iterate over - etc.... But it can be made both compile and deploy time that way that no virtual functions would be needed for this to work!!! Which is awsome to think about. Actually the best way to emulate that currently in native code is via the linker not the compiler.... but I really mean it could have made that way that even inlining is possible etc...

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

      I started with an IoC framework when I first started doing DI assuming it was saving me time and frustration. Fortunately I have learned that 99% of the time, it saves no dime and leads to frustration. Manual DI is just better, clearer, easier to maintain long term and often easier to test.

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

      @@HalfMonty11 It is just not called DI then: but composition. And composition is KING it is AWSOME - I agree in that. Just its not "injection" anymore to be honest...
      And again - there are upsides of DI other than less boilerplate with sending around parameters. Like as I said it is easily imaginable to make a programming language level support for DI in a native language where calls to a component would be totally inlined! Think of a game engine where you can choose what physics engine (or AI) you want! The calls to that will be as free as if you call an inlined funcion - not even function calls are needed because code can be inlined. This must happen either compile OR deploy (install) OR at least "before running the app"-time! Then calls can be more optimized than vtable like calls.
      Currently you can do this compile-time with templates / generic and composition, but easy to do later and more dynamically with a DI language feature.
      So my point is that its better to call things by their real names. I usually prefer composition over DI just like you do, but I do not call composition as DI...

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

      @@HalfMonty11adding a dependency and pushing your change, having 500 test fail only because the construction code failed to build it.
      Then having to go through every one of those test and fix the manual insert of mocks/dependencies is super annoying.
      A container should let you reordered, remove or add dependencies without any tests failing.
      But that’s only going to work in strongly types, OOP languages. Not going to work so well in languages like js

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

      If the process is depending on an externally provided and allocated dependency, it is DI. Remember, composition means the containing object owns it thus responsible for lifetime management. If your class allocates or owns the memory, it isn't DI. So a factory function or constructor injection of an interface satisfies that, and that is what his code is doing.
      @@u9vata

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

    For the person asking for a concrete example of DRY being bad. When you’re doing microservices, DRY leads to heaps of shared libraries and, holy cow, that was a hot steaming mess.

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

    You make it fun to learn the science behind code thanks man!

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

    "What's WebDAV" made my cry so hard because I didn't know it either until I had to re-do a whole "FileTransfer" Lib in our Common Lib where I had to reimplement all the connectivity of the possible endpoints for filetransfer, including FTB, SFTP and "ofc" WebDAV. WebDAV nearly made me cry, maybe it was our infra or WebDAV is just coming literally out of hell, idk haha.

  • @AceHack00
    @AceHack00 10 หลายเดือนก่อน

    DRY goes wrong in C# when you try to create complicated generics that don't infer the generic types during use and you require the user of your API/Library to pass 3 or more generic type parameters to call a 5-10 line long function. In general DRY can lead to functions that are too complicated and overengineered, making it difficult to read the code. As a rule of thumb, I follow the rule in the video, only consider DRY after you repeat yourself 3 times.

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

    At 23:20
    "... you're not really testing anything. You know what I mean? You're testing your not real encryption"
    Yep. I totally agree.
    But i do think that it is still useful. The problem is solved if one see where it is useful and use it for that goal and not for other illusory ideas.
    So what are we really testing?
    In this case, we are just testing our own assumptions about a part of the S3 protocols.
    How can this be useful? Probably the best use case i can see here is when refactoring or when one create the tests before the code implementation. Assuming that our hypothetic protocol is not too far from the real one.
    But there should be other useful cases. They will really depend on the dev. For example, as was mentioned in the chat, one case would be to increase coverage and gain a bright and luminous badge to try to blind the business minded people?

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

    Dependency injection using the basic features of a programming language is great.
    But Java EE style dependency injection, which uses a zoo of annotations, plugins, and config files, is a nightmare that can easily make code unreadable. It forces you to rely on documentation for things that should be obvious. It creates major problems for a minor boost in comfort.
    Programmer: "So what is actually getting injected here? Where does this call actually go to?"
    IDE: "IDK, it's just here. Check the annotation I guess"
    Annotation: "I'm just a piece of text. Maybe copy-paste it and search THE ENTIRE CODEBASE"
    Codebase: "Na sorry nothing found lol. The config files to resolve the name used in the annotation are not in the project folder and maybe not even on your machine, I'm pulling half my sht off some web service."

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

    its fine flip, we can lower the audio ourselves. Do not worry!

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

    I got a DoorDash ad right after the Wifeagen brought him food. “You know… you can have your food delivered too…”

  • @lynnwilliam
    @lynnwilliam 3 หลายเดือนก่อน +1

    My project at work, everything is DI. Everything! And adding anything is a pain

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

      Debugging a software that dynamically changes at runtime is a pain too and reminds me even to self-modifying code, that's why DI just sucks and I personally never use it. Actually he said it in the video too "... we used it everywhere until it got out of control" - if that is not a sign for a design pattern not working at scale and with increasing complexity, then I don't know...