3 ms·
What the author is really arguing against is configuring objects at construction time with their dependencies, rather than calling a function with one or more p
by cseleborg 5y ago
What the author is really arguing against is configuring objects at construction time with their dependencies, rather than calling a function with one or more parameters being a dependency. The latter is a lot easier to reason about and run in a test.
- eru 5y agoIf you have curried / partial application, 'construction time' and 'calling time' blur a bit.
- cseleborg 5y agoIndeed, it's never quite black and white. The author's obviously referring to the crazy trends in the Java community back when Design Patterns were the only game in town. I have myself worked on code built like this, it's usually very difficult to retrofit into a unit test. Hell, I've even written some AbstractSingletonFactories myself...
- inopinatus 5y agoThis seems congruent to the object<>closure equivalence. Nevertheless the resulting code reads quite differently. Any kind of early binding to dependencies can read like a “COME FROM” at times (especially debugging time), and all that extra state burns memory. In Ruby one of my favourite calling conventions is to pass self to the methods, rather than the constructor, of collaborator objects.
- eru 5y ago> This seems congruent to the object<>closure equivalence. Nevertheless the resulting code reads quite differently. To write functional code that looks a bit more like OOP, I guess you want 'open recursion'. Open recursion is what allows you to do the equivalent of overwriting methods in subclasses when doing FP. See eg https://www.cs.ox.ac.uk/people/ralf.hinze/talks/Open.pdf https://www.cs.ox.ac.uk/people/ralf.hinze/talks/Open.pdf or https://journal.stuffwithstuff.com/2013/08/26/what-is-open-recursion/ https://journal.stuffwithstuff.com/2013/08/26/what-is-open-r...
- kgeist 5y agoIt really depends. In a large desktop project of ours (we can call it "monolith"), we had manual construction of dependencies, and it quickly became a hard to understand spaghetti mess. A clean declarative DI framework like in the Java world would save us a lot of trouble. On the other hand, we now mostly write small microservices in Go, and manual DI is more than enough. Passing interfaces to functions directly instead of at construction time sounds like a leaky abstraction, because I as client should not care that some function relies on another function as an implementation detail. Functional languages solve it with currying and in this context I don't see semantic difference between currying and saving a dependency in a class/struct in OOP languages, they're analogous.
- gpderetta 5y agoIn a large server project of ours, we had a sophisticate declarative DI framework, and it quickly became a hard to understand spaghetti mess of config files. A clean manual construction of dependencies would have saved a lot of troubles. Snark aside (but the sentence above is really what happened at $PREVIOUS_JOB), I think there is value in assigning dependencies declaratively, but I think it is better done in a proper programming language (with IDE support, compile-time error checking, proper parametrization and escape to procedural code, testing, etc.), not in an xml file (and no, json or yaml are not better).