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.