5 ms·
Functional approaches to dependency injection (2016)
- oweiler 8y agoSadly there has never been Part 2.
- garethrowlands 8y agoThere's a book now though, see https://pragprog.com/book/swdddf/domain-modeling-made-functional https://pragprog.com/book/swdddf/domain-modeling-made-functi...
- megaman22 8y agoIt does seem like most of his efforts were redirected into his book lately, which is understandable. I picked it up a while back and have to say I'd recommend it.
- RobertRoberts 8y agoCan someone clarify if this author's methods are actually inline with the core principles of functional programming? I've been doing OOPs from very early in my career (I run into FP from time to time but never as a core of my own work), and much of the example he's implementing here seems like make-work simply to enforce a specific paradigm. Am I missing something? For example, at first his concepts seem brilliant, until you get to the refactoring steps, which feel painful. Is this the end result of high-level extreme veteran coders use of FP? With OOPs, simple inheritance & factories seems like it would solve all the dependency issues he's addressing.
- dwohnitmok 8y agoMost of what the author is talking about in the refactoring section has little to do with trying to address dependencies per se. Therefore from the perspective of strictly trying to address the problem of "I have dependencies that I want to be interchangeable" that section is mostly irrelevant. In the refactoring section he's mainly dealing with things like trying to minimize exceptions with `Result` instead and maintaining syntactically linear control flow. So essentially yes that section is make-work if all you care about is dependency injection. It's not if you care about other things beyond dependency injection. That work is not necessary for dependency injection with FP.
- bunderbunder 8y agoI've always found ScottW to be pretty pragmatic. If Martin Odersky favors multiparadigm programming that nonetheless leans toward object-oriented methods, Scott Wlaschin favors leaning toward functional methods as a default. As far as whether he's in line with "core principles of functional programming", that's maybe a phrase that's well-designed to start a fight. Even more so than in object-oriented languages, different ways of doing things tend to cluster around different functional languages. In broad strokes, what he's doing seems fine coming from a F# developer. I think it would translate well enough to Haskell, though I'm nowhere near as experienced in that language. In Clojure, on the other hand, I'm guessing you'd want to do something completely different.
- default-kramer 8y ago> The downside of course, is that there are now five extra parameters for the function, which looks painful. (Of course, the equivalent method in the OO version also had these five dependencies, but they were implicit). In my opinion though, this pain is actually helpful! I'm definitely in favor of making dependencies explicit, but I wish there was a typed language that allowed me to avoid mentioning "less important" dependencies when I want to. Logging is a perfect example: function log(msg: string) = ImplicitDependencies<ILogInfo>().Write(msg) Let's imagine that "ImplicitDependencies" is some special keyword. The compiler would give the "log" function a type of (string -> (implicit ILogInfo) -> unit). But my code is allowed to say that its type is (string -> unit) if it wants. Now if I use this "log" function in UpdateCustomerProfile, then UpdateCustomerProfile gets an (implicit ILogInfo) parameter too. The compiler would also give me some way to designate a function as "root level" meaning that all implicit dependencies must be resolved. I'd imagine something like Racket's parameterize for this. (https://docs.racket-lang.org/guide/parameterize.html https://docs.racket-lang.org/guide/parameterize.html) The idea is, most of the time, I don't want to keep mentioning logging in my type signatures. I just want to silently kick it up the call stack.
- gliese1337 8y agoScala almost has this. You can declare a function with "implicit" arguments, and the compiler will look for something that matches the requirements in each calling scope and insert it automatically. It does not, however, automatically infer the implicit parameters based on usage of implicit arguments in the function body, though.
- adrice727 8y agoDotty is moving in this direction with Implicit Function Types. https://dotty.epfl.ch/docs/reference/implicit-function-types.html https://dotty.epfl.ch/docs/reference/implicit-function-types... https://www.youtube.com/watch?v=YXDm3WHZT5g&feature=youtu.be https://www.youtube.com/watch?v=YXDm3WHZT5g&feature=youtu.be
- dragonwriter 8y agoOther than the fact that the implicit dependencies are declared as parameters (with an “implicit” modifier)) in function definitions and implicit only at the call site (which, IMO, is less awkward than the proposed syntax), Scala has something like this (the method of resolving the implicits may be different than you imagine, but it's not entirely clear to me what your resolution mechanism is.) https://docs.scala-lang.org/tour/implicit-parameters.html https://docs.scala-lang.org/tour/implicit-parameters.html
- wtetzner 8y agoIf F# had taken OCaml's module system, functors would be the obvious way to do dependency injection, and would have been supported out-of-the-box. I realize there were difficulties in integrating with the rest of the .NET platform/ecosystem, but it's really too bad that the module system was left out, as it's one of the best parts about OCaml.
- deleted 8y ago[deleted]
- Nelkins 8y agoWhat can you achieve using OCaml modules that you can't do using objects with a constructor in F#?
- wtetzner 8y agoThere are a few advantages of modules. One is that they can encapsulate types along-side functions/values. Also, it can be advantageous that functors are applied at compile time. The really cool one though is abstract types. You can distinguish types purely in the type system, with no change to run-time representation, using module signatures that don't specify the concrete type of a type entry.
- smarrenbartlet 8y agoNot once have I ever seen a codebase where OO 'design patterns' have led to ease of development or modularity, every time they have made development worse. These principles should be kept as far away from functional programming as possible.
- kyleperik 8y agoFor languages that support monkey patching you don't dependency injection. A lot of the design patterns I used to adore and look at as if they were rare gems in a sea of bad code. Over time my opinions have changed. Many patterns are good, but I don't really like to think of those as patterns. A pattern implies repetition. Something that you can used each time you have a situation that warrents it. In my opinion, this openly contradicts "Don't repeat yourself". So I think we should start trading design patterns for simple and well designed languages. No code always beats good code.
- bunderbunder 8y ago> For languages that support monkey patching you don't dependency injection. What am I missing here? We've got to be working with different definitions of the term "dependency injection" or something. Using monkey patching as a complete replacement for dependency injection seems absolutely bonkers to me. The codebase I'm imagining when I here that is one where no module's run-time behavior can be understood by simply reading its source code, because every single one of its run-time dependencies is being monkey patched in from some where else entirely. It's also one where, to take the same class and instantiate two different copies with two different sets of run-time dependencies, I'd have to do something wacky with the monkey patching instead of just creating them with different constructor arguments.
- kyleperik 8y agoI know what you're talking about, I realize that's how most people think of as monkey patching. That's what I thought at first. But when I tried structuring a python project with Dependency Injection it seemed overly complex. Instead of just making modules I had to put everything in a class. I had to write code to decide what things are being injected where. It didn't look like python anymore, so I stopped doing it, and I've never had problems, and I've written much less code. I only ever use monkey patching for testing. People talk about how it makes it easier to switch out other implementations, but in reality it's easier. You just import a different module.
- zeveb 8y ago