[HN Gopher] Inversion of Control Containers and the Dependency I...
       ___________________________________________________________________
        
       Inversion of Control Containers and the Dependency Injection
       pattern (2004)
        
       Author : Tomte
       Score  : 37 points
       Date   : 2024-02-20 12:10 UTC (1 days ago)
        
 (HTM) web link (martinfowler.com)
 (TXT) w3m dump (martinfowler.com)
        
       | TheAlchemist wrote:
       | It's a very good article. I wish I knew how to find this at the
       | time when it was written.
       | 
       | I remember when I first discovered the pattern, at a job I took
       | 10 years after this article. The codebase seemed so clean, easy
       | to evolve and test, even for a newbie and 'half programmer' as me
       | - my mind was blown. I was thinking - what kind of black magic is
       | this ?!
       | 
       | Say you're new to programming. What's the best place today to
       | learn about design patterns (with python examples, since it's the
       | most used language for beginners) in an easy and accessible way ?
        
         | mcnichol wrote:
         | Head First Design Patterns. It's a recent and very friendly
         | introduction to the popular Gang of 4 - Object Oriented
         | Programming book.
         | 
         | I love this part of the journey for folks because it opens the
         | door to a world of possibilities that has dramatically more
         | structure and form. Thoughts and ideas become less "what if.."
         | and more puzzling together the best interactions between
         | certain design implementations.
         | 
         | At risk of rattling on endlessly in my excitement for you, TDD
         | became a very interesting and enjoyable way (for me at least)
         | to implement these patterns and gain a better understanding. I
         | think you'll find Martin Fowler, TDD, and IoC/DI are peas in a
         | pod.
         | 
         | (I realize you said Python and this was Java. I'll see if I can
         | find something Python friendly. If you'd like to try your hand
         | with Java....I highly highly recommend Spring Framework and
         | more specifically Spring Boot. Spring is an IoC Container
         | Framework where the Dependency Injection is done for you on the
         | fly. So much to throw at someone but if you'd like to connect
         | on it, I'd be more than happy to give you a running start.)
        
           | uptownhr wrote:
           | I would love to pair with someone that works through TDD. I
           | personally tried it a few times in the past and constantly
           | got stuck for one reason or another. My conclusion is that
           | testing is hard and guides and articles online don't do it
           | justice. Anyone love and practice TDD and want to help
           | another engineer out, please reach out :)
        
         | bb86754 wrote:
         | Dependency Injection Principles, Practices, and Patterns by
         | Mark Seemann.
         | 
         | Examples are in C# but it's a great book about OOP in general.
        
         | ayhanfuat wrote:
         | If you are a beginner and you are coding in Python, I'd say
         | hold off on the design patterns (as defined by the gang of
         | four) but instead focus on idiomatic Python. The reason is many
         | of the design patterns are baked into the language. It may
         | create more confusion. For idiomatic Python, I can recommend
         | two books that I've found really helpful: 1. Python Cookbook by
         | David Beazley (it doesn't have the latest features like pattern
         | matching but the 3rd edition uses Python 3 and it is still very
         | relevant) 2. Fluent Python by Luciano Ramalho (the book itself
         | is very good but it is also very valuable for the list of
         | suggested readings at the end of each chapter).
        
         | tester756 wrote:
         | >hat's the best place today to learn about design patterns
         | (with python examples, since it's the most used language for
         | beginners) in an easy and accessible way ?
         | 
         | https://en.wikipedia.org/wiki/Result_type
         | 
         | https://github.com/rustedpy/result
        
         | nicklecompte wrote:
         | I would second ayhanfuat's comment[1] - if the programming
         | beginner is at the level that we'd prefer to show them Python
         | over Java or C#, then they probably aren't ready for
         | understanding these design patterns.
         | 
         | The other thing is that Python doesn't actually seem like a
         | good language to discuss these abstractions compared to Java or
         | C#: it's dynamically/gradually typed and in general
         | dependencies are handled in a more "UNIX"-y way. In particular
         | Python doesn't have first-class interfaces (at least last I
         | checked, maybe mypy has something?). But statically-checked
         | first-class interfaces are critical for why e.g. the service
         | locator pattern works "seamlessly"[2] in real-life Java/C#
         | codebases with lots of people doing lots of different things.
         | 
         | My gut is that a lot of inversion-of-control design patterns
         | don't actually work so well in _practical_ Python compared to
         | just throwing things in a dictionary /etc and using strings +
         | careful unit testing. I do see there are some service locator
         | Python packages so maybe I am being too closed-minded. But for
         | _teaching_ C# /Java is probably a better choice.
         | 
         | [1] https://news.ycombinator.com/item?id=39459732
         | 
         | [2] I have been mystified by too many null pointers to say this
         | with a straight face. But when the bugs are squashed it really
         | does manage a "magical" level of complexity.
        
           | polotics wrote:
           | Wow, are you really sure you've updated your priors? This
           | notion that Python is for programming beginners as opposed to
           | Java/C# has aged quite a bit has it not?
           | 
           | In other news, ten years on the game's been up a while now,
           | Fowler's profusion of wordage plastered onto simple
           | functional concept, eg. in the present case: partial function
           | application, doesn't really fly so well, even in the
           | enterprise.
        
         | bobfromhuddle wrote:
         | If you're new to programming, steer clear of design patterns.
         | If you're a working python programmer who's curious about how
         | other ecosystems use design patterns, try
         | https://www.cosmicpython.com/
        
       | Veserv wrote:
       | Dependency injection has always been such a bad name for the
       | concept. It is just passing dependencys as arguments.
       | 
       | Though the funniest part about it is that the things we use every
       | day, programming languages and build systems, still do not
       | generally use this concept. Your imports are dependencies, you
       | should just pass them in. Wham bam, no more environment
       | variables, ambiguity, lookups, multiple version ambiguity,
       | rewiring challenges, naming conflicts, etc.
       | 
       | Well, you still need somebody to know so they can instantiate the
       | correct dependency versions in the first place (which you could
       | implement as a snazzy automatic dependency resolver), but all of
       | the internal ambiguitys disappear. Replacing a library (with a
       | drop-in compatible one) would be just instantiating a different
       | codebase into the same symbol name which will get passed in
       | exactly the same way as the old one.
        
       | peheje wrote:
       | This has become so seeped into how we develop dotnet c# past
       | couple of years. Just using Microsoft built in ServiceCollection.
       | 
       | Honestly I think this is the most important pattern in my line of
       | work. It has become so common for me. That when I see c# code not
       | using it. It almost looks like another language.
       | 
       | Testing becomes so easy because everything is easy to mock out.
       | Be it in a unit test using some mock framework. Or a real
       | 'integration-test' where you write a small in memory queue mock
       | by hand to easy your tests.
       | 
       | Object lifetime is easy to change and manage. Just how you
       | register the dependency. As scoped (to http request for example)
       | as transient (every time you ask) or singleton?
       | 
       | Want to do something before/after with some hook? Just Decorate
       | the dependency and register it to the container.
       | 
       | Nothing feels tangled. Just inject the service. Call the method.
       | Do the thing. No need to worry about cleanup or how to create the
       | dependency. It's already setup.
        
         | tester756 wrote:
         | >That when I see c# code not using it. It almost looks like
         | another language.
         | 
         | On the other hand
         | 
         | While I see the value of DI containers in web apps (ASP.NET)
         | 
         | Then I don't really see the value of it in console apps (tools)
         | (yea, asp app is console too, ik.)
         | 
         | You may ask what's the difference and in my opinion the
         | difference is: input/output flow model
         | 
         | In web app you run your app with some args/envs, and then
         | you're receiving request and return them results.
         | 
         | In console app your run your app with some args/envs and then
         | you're doing stuff until you complete (ofc unless you're
         | listening/waiting for things... like in web app)
         | 
         | In this 2nd model DI containers seem to not give me anything
         | useful. You even were writing about this here:
         | 
         | >"Just how you register the dependency. As scoped (to http
         | request for example) as transient (every time you ask) or
         | singleton?"
         | 
         | It fits asp request/response model very well, but for other
         | things? I dont feel it
        
           | nh23423fefe wrote:
           | The value was always the implicit object graph. I don't see
           | what IO has to do with it. DI lets you label nodes and the
           | container toposorts and makes edges for you.
        
             | tester756 wrote:
             | >I don't see what IO has to do with it.
             | 
             | ASP web framework creates instances of Controllers
             | (handlers) on request basis, that's when they need to
             | resolve dependencies in order to create them, so it fits it
             | very well.
             | 
             | But when I need to create instance of some repository, some
             | background job handler and some csv writer, then why would
             | I want to do it via DI container?
             | 
             | >DI
             | 
             | I'm talking about containers, just containers.
             | 
             | DI != DI containers
        
       | behnamoh wrote:
       | Genuine question: What design pattern works best here:
       | 
       | Let's say I want to write small functions that do one thing very
       | well:                   args = {LLM parameters, e.g., prompt}
       | 1. foo(args): calls the LLM API with args         2. goo
       | (foo(args)): uses backoff (retry) and makes sure the output is
       | JSON         3. hoo(goo(foo(args))): extracts and desers the JSON
       | 
       | At any point, things could go wrong. I could use a monadic
       | approach and turn each of these functions into a monad:
       | 1. foo: args -> Maybe(API_res)         2. goo: Maybe(API_res) ->
       | Maybe(JSON)         3. hoo: Maybe(JSON) -> Maybe(dict)
       | 
       | But before I knew about monads, I thought: wouldn't be cool if
       | when a function goes wrong and needs to be called again, it had
       | access to its "parent" function which called it? Like:
       | 
       | Currently args is only passed to foo. What if, depending on how
       | things went wrong, goo needed to see args?
       | 
       | One approach is to make foo pass its args as well:
       | foo: args -> args, output
       | 
       | Then goo would take that and do something with it. But what if
       | now hoo also needed to know about args to make sure the extracted
       | JSON conforms to the JSON schema mentioned in args? Now we'd have
       | to do:                   foo: args -> args, output         goo:
       | args, output -> args, output, JSON         goo: args, output,
       | JSON -> dict (deserialized JSON)
       | 
       | I think this is not "elegant". Is there any better solution?
        
         | nh23423fefe wrote:
         | foo should hold the args and be a command object, not a result
         | type
         | 
         | goo should take foo as argument and delegate to the command in
         | its loop
         | 
         | hoo shouldn't be a Maybe. if you want that function then lift
         | hoo instead of writing it, that's fmap hoo
        
       | jauntywundrkind wrote:
       | I wish we were seeing better hope for IoC in webdev today!
       | 
       | I feel like there's a general feeling that:
       | 
       | > _It is just passing dependencys as arguments._
       | 
       | (And: oh no, magic!)
       | 
       | That's often what consumers see, sure.
       | 
       | But it's also managed repositories of objects and factories. It's
       | also injection logic, with scope and conditional logic. It's also
       | runtime assembleable interception layers for objects. It's also
       | awareness methods to observe and track your managed repositories
       | & objects.
       | 
       | There's simple things we see. But zooming out from the trees I
       | think the forest here is something more than the sun of these
       | pieces. Programs are mostly here to juggle entities of various
       | sorts. Mostly we programmers write code that imperatively creates
       | & modifier objects & their references...
       | 
       | And Dependency Injection and Inversion of Control is having
       | explicit tooling & stable patterns for this construction. Having
       | actual places & tools for managing runtime objects.
       | 
       | I think it's so damned cool. It's so enticing to me, of being
       | expanded beyond a programmer tool. It could & should pioneer
       | waves of general systems research! This tech should offer
       | external hooks beyond the app, be integrated into repls & hosting
       | apis that let us talk to the computing objects of our world.
       | 
       | Invert the control! I cannot wait for us to stop doing all coding
       | bottom up, instantiating and passing everything from the
       | bottom.up, and starting to create some top down tools that manage
       | the entities of the runtime!
        
       ___________________________________________________________________
       (page generated 2024-02-21 23:01 UTC)