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.

Reply via email to