The question you should be asking is: do I need polymorphism? If the services you're passing in are distinct and not interchangeable, then you can just use functions:
(defn my-service [cache queue payload] (cache/store cache payload) (queue/push queue payload)) On the other hand, if the services have some common functionality that can be abstracted, use protocols: (defn my-service [listeners payload] (doseq [l listeners] (listener/deliver l payload))) It's worth noting that protocols methods and functions have the same syntax, so you can easily convert a function into a protocol. For instance, let's say you've written the first example using functions: (defn my-service [cache queue payload] (cache/store cache payload) (queue/push queue payload)) But for testing purposes, you want to be able to overload the queue with a stubbed version. Well, that's no problem; you can just change the queue/push function into a method on a protocol. Any code that uses queue/push will act the same, but now we have different behaviour depending on the configuration. - James On 25 February 2015 at 13:22, Colin Yates <colin.ya...@gmail.com> wrote: > Hi, > > I ran into a bit of a brick wall when thinking about how to register to > and dispatch to multiple micro-services and it made me realise the > underlying tension came from not having peace about a fundamental design > decision; how do you access your collaborators. Note: I am specifically > talking about 'providers of functionality' as oppose to state. I think > everybody agrees that passing state around is a "good thing" (e.g. *db* is > so 90s, (defn my-thing-which-needs-a-db [db] ...) is where it is at). > > One option is to receive instances of a service (probably some > implementation of a defprotocol): > > (den my-service [service-1 service-2 payload] > (some-method service-1) > (some-method service-2)) > > The other is to directly reach into the collaborator's namespace: > > (den my-service [payload] > (service-1-ns/some-function) > (service-2-ns/some-function)) > > (maybe some config is passed into my-service which the other services use. > > The first approach has a much smaller coupling and makes it much easier to > reason about. If there is coupling then it is on the protocol of the > collaborator. It is therefore trivial to unit-test as you can stub out the > collaborators without redef. It also has echoes of OO services, which might > be just fine. > > The second approach means you don't end up passing collaborators deep down > hierarchy graphs (which I haven't run into actually - Clojure tends to have > a much 'flatter' graph then Java). It does mean testing etc. requires > redefs. > > My inclination is to go for the first as it seems simpler, but I still > have an allergic reaction to using protocols like this (because of the OO > trap). > > This clearly isn't new ground, but I could find surprisingly little blogs > and discussion about this. It is also something that only really becomes a > problem in the larger scale as well. > > What do you all do? > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.