Hi James, Agreed, and I did feel a little dirty using a protocol simply to satisfy the swap out for testing (when in fact redef isn't *that* bad).
I had made a flawed assumption all along that accessing a protocol method was different than a normal function (I though the 'cache' and 'queue' carried their functions with them so (store cache payload) and (push queue payload)). Now I understand they symmetrical it makes a lot more sense, and provides a lot more freedom. On 25 February 2015 at 17:44, James Reeves <ja...@booleanknot.com> wrote: > 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. -- 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.