Good foor for thought. Thanks both. On 2 Mar 2015 23:43, "Jonah Benton" <jo...@jonah.com> wrote:
> Hi Colin, for me this is usually an Invented Here/Not Invented Here > question. > > When I'm inventing a thing with state and a lifecycle I'll define it as a > Record and slap the Lifecycle protocol implementation onto it. I'd do that > with your Registry. > > When I'm using a thing someone else made, usually that thing will have its > own state and implementation encapsulation and its own lifecycle, so I'll > make a simple Component only to manage it. I won't have that Component play > any other privileged role in regards to accessing the NIH thing or getting > to its internal state. Database connection is a canonical example- as often > discussed functions that do something with a database should take a > connection parameter, not a Component parameter from which they have to > extract a connection. > > That all said, sometimes I'll have multiple implementations of Invented > Here things that the app needs just one of at runtime- say, Registry > implementations backed by different underlying technology that are > appropriate for different application use cases. In that case it starts to > smell like an NIH thing and I'll see if I can treat it that way and make a > single Component that can be told which Registry to manage. Sometimes that > works, but sometimes it makes sense to extend the protocol to the > individual implementations. > > Jonah > > > > On Mon, Mar 2, 2015 at 6:32 PM, Dylan Butman <dbut...@gmail.com> wrote: > >> I would do the latter. >> >> I like the extend types to component/Lifecycle wherever possible. The >> goal is to have all components in your system only interact via protocols. >> This way, you have established interfaces between components, and if you >> want to swap an implementation, you just satisfy the protocol. So adapting >> your example >> >> (defprotocol IRegistry >> (register-with [registry cb spec])) >> >> I also like to provide all reference as arguments instead of assoc'ing >> them inside component/start. This allows them to be more easily used in >> other parts of the system, and gives you the opportunity to validate the >> references, continuing the idea of protocol interface >> >> (defn validate-system >> "validate the portion of the system contained within the component" >> [schema cmp] >> (s/validate {s/Keyword s/Any} schema) >> (->> (select-keys cmp (keys schema)) >> (s/validate schema))) >> >> (defrecord Registry [state] >> Lifecycle >> (start [this] >> (validate-system {:state clojure.lang.Atom} this) ;; this could be >> more general, let's be specific though >> ;; start the registry >> this) >> (stop [this] >> ;; stop the registry >> this) >> IRegistry >> (register-with [registry cb spec] >> (swap! state :assoc cb spec))) >> >> (defrecrod UsesRegistry [registry] >> Lifecycle >> (start [this] >> (validate-system {:registry (s/pred (partial satisfies? >> IRegistry))} this) >> >> this) >> (stop [this] >> this)) >> >> >> On Sunday, March 1, 2015 at 7:50:58 AM UTC-5, Colin Yates wrote: >>> >>> If I have a stateful thing with a lifecycle then is the system component >>> the instance of the thing or a wrapper that contains the thing. >>> >>> For example, let's say I have a registry of clients that want to be >>> polled then I might have the following: >>> >>> (defrecord Registry [state]) >>> (defn register-with [registry cb spec] (swap! (:state registry) :assoc >>> cb spec)) >>> (defn start [registry] ...) >>> (defn stop [registry] ...) >>> (den some-other-thing [..] ....) >>> >>> Great. >>> >>> Now I want to expose that and use Stuart's excellent component library >>> (which I really wish a global 'everything has been defined, now the actual >>> system is starting' lifecycle event, but anyway). I seem to find most >>> examples do: >>> >>> (defrecord RegistryComponent [] >>> component/Lifecycle >>> (start [this] >>> (let [registry (->Registry (atom {}))] >>> (start registry) >>> (assoc this :registry registry)) >>> (stop [this] >>> (stop (:registry this)) >>> (assoc this :registry nil))) >>> >>> Other components get the RegistryComponent but then have to unravel the >>> actual :registry. >>> >>> Another approach would be to adjust the actual Registry and that that >>> implement the lifecycle: >>> >>> (defn register-with [registry cb spec] (swap! (:state registry) :assoc >>> cb spec)) >>> (defn start [registry] ...) >>> (defn stop [registry] ...) >>> (den some-other-thing [..] ....) >>> (defrecord Registry [state] >>> component/Lifecycle >>> (start [this] (start this) this) >>> (stop [this] (stop this) this)) >>> >>> On the one hand, the Lifecycle component can be viewed as separate from >>> the thing it is managing, and this wrapping and unwrapping is only a >>> concern of Components. Nothing outside of a Lifecycle instance worries >>> about it and nothing ever receives a Lifecycle instance. >>> >>> On the other hand, it all felt a little bit OO-ish - and actually I >>> don't quite see the 'vanilla' Registry implementing the Lifecycle component >>> as complecting anything inappropriate. The Lifecycle instance is only >>> describing behaviour - there is no separate 'thing'. >>> >>> Is that correct or have I missed something? 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.