Hey Thomas, thanks for your e-mail :)
On Monday, 29 June 2015 11:25:44 UTC+1, Thomas Heller wrote:
>
> Hey,
>
> interesting approach but I don't like the nesting and "manual" wiring of
> dependencies.
>
I've found people at both ends of that particular spectrum - some that
won't live with DI, some that won't live without it :) I guess a library
like Yo-yo has two options - either be opinionated about it, or let people
choose one or the other. In this case, I've chosen to let people choose -
there's nothing about Yo-yo that mandates the nesting (except the top-level
function) - what you do within that is up to you.
> I don't quite like that every with-* function remains on the stack as
> well, but it shouldn't hurt that much.
>
Hmm - I was wondering about that too. Maybe an approach similar to
trampoline would help here?
> An uncaught exception will also take down your entire system, but I guess
> you'd have a try/catch in your "latch" anyways.
>
I'm not sure it will? If there's an exception thrown during system startup,
the components will then have an opportunity to stop themselves (in the
reverse order) because of their try/finally's - I'd say this is the
behaviour we'd want, in order to avoid half-started systems. Once the
system's started, and (latch) called, an uncaught exception in the
components won't stop the system - because it'll be thrown on a different
thread, if I understand correctly? Certainly need to write some test cases
around it!
>
> But what I miss the most is an instance of your "app" (ie. all components
> together). You create it yourself in the example but I really want that
> always. Sometimes you just want to access your system from the outside just
> to see whats up (eg. REPL into a live system). I also consider the
> webserver to be a "client" of my "app" and not part of it (or another layer
> of it if you will), but that is a topic for another day.
>
>
Yep, I agree with this - I've been using some workarounds to get values out
of the system, none of them particularly pretty. Interesting idea about the
webserver being a client of the app - would be good to see where you take
that?
> Way way back in the day I used to work with (and on) PicoContainer which
> was/is a dependency injection and lifecycle management container. I tried
> writing a DSL for it (in Groovy, this was 2003 or so) but concluded that
> Java already was good enough to set everything up, a DSL (or XML) is
> overkill. All you need to describe a "Component" is:
>
> a) what are its dependencies
> b) how do I start it
> c) how do I stop it
>
> In that light I wrote my own "dependency injection" helper functions since
> nothing like Stuart's Component existed at the time I got into Clojure. I
> don't like Component due to its invasive protocol but in essence I do the
> same.
>
> In my system I just set up a map of components and use that as a
> descriptor for wiring:
>
> {:a {:depends-on []
> :start my.components.a/start
> :stop my.components.a/stop}
> :b {:depends-on [:a]
> :start my.components.b/start
> :stop my.components.b/stop}}
>
> The key in the outer map becomes whatever the :start function returns and
> is refered to it by its name :a (the key of the map). The :start function
> of :b is called as (my.components.b/start instance-of-a). An instance of a
> component is treated as an opaque value and other components interact with
> it only via its "public" interface (ie. my.components.a). Whether this is
> done via a protocol or not doesn't matter. When a shutdown is requested the
> :stop function is called with the instance of the component as the argument.
>
> That is about it. Mocking is just assoc over default descriptor map and I
> have helper functions to only do partial start/stop calls if only a
> specific component is needed (eg. I only need :a).
>
> Like I said it basically does the same stuff as Component, just a little
> less invasive since I think a component should not know about the container
> it runs in.
>
Looks another interesting approach :) I'm currently hacking on some similar
ideas myself - think there's plenty of room for iteration in this area at
the moment!
> Hope that was somewhat useful as feedback to Yo-Yo.
>
Certainly was! Thanks! :)
>
> Cheers,
> /thomas
>
>
> On Sunday, June 28, 2015 at 4:03:34 PM UTC+2, James Henderson wrote:
>>
>> As promised, have blogged: 'Yo-yo & Component - Side by Side
>> <https://github.com/james-henderson/yoyo/blob/master/articles/side-by-side.org>
>> '
>>
>> Contents:
>>
>>
>> - Making components
>>
>> <https://github.com/james-henderson/yoyo/blob/master/articles/side-by-side.org#making-components>
>> - Using a component as a dependency
>>
>> <https://github.com/james-henderson/yoyo/blob/master/articles/side-by-side.org#using-a-component-as-a-dependency>
>> - Serving a REST API
>>
>> <https://github.com/james-henderson/yoyo/blob/master/articles/side-by-side.org#serving-a-rest-api>
>> - Wiring it all up
>>
>> <https://github.com/james-henderson/yoyo/blob/master/articles/side-by-side.org#wiring-it-all-up>
>> - Yo-yo / Component Interoperability
>>
>> <https://github.com/james-henderson/yoyo/blob/master/articles/side-by-side.org#yo-yocomponent-interoperability>
>> - Mockable Services
>>
>> <https://github.com/james-henderson/yoyo/blob/master/articles/side-by-side.org#mockable-services>
>> - ‘Mocking out’ dependencies
>>
>> <https://github.com/james-henderson/yoyo/blob/master/articles/mocking-out-dependencies>
>>
>> Let me know what you think!
>>
>> Cheers,
>>
>> James
>>
>> On Thursday, 25 June 2015 09:25:56 UTC+1, James Henderson wrote:
>>>
>>> Seems like the next step for this would be for me to put together a blog
>>> with an example Component system, and its equivalent Yoyo system?! :)
>>> Should have time for that over the weekend.
>>>
>>> James
>>>
>>> On Thursday, 25 June 2015 09:05:39 UTC+1, James Henderson wrote:
>>>>
>>>>
>>>>
>>>> On Wednesday, 24 June 2015 11:17:41 UTC+1, Atamert Ölçgen wrote:
>>>>>
>>>>>
>>>>>
>>>>> On Tue, Jun 23, 2015 at 11:47 PM, James Henderson <[email protected]
>>>>> > wrote:
>>>>>
>>>>>> Hi Atamert - thanks :)
>>>>>>
>>>>>> I thought it might be preferable to keep the call to (latch)explicit
>>>>>> - it means that ylet can be used in nested calls, too - for example,
>>>>>> to set up and compose groups of components/sub-systems: (contrived
>>>>>> example,
>>>>>> though!)
>>>>>>
>>>>>> ;; (docs for ylet at
>>>>>> https://github.com/james-henderson/yoyo#introducing-ylet )
>>>>>>
>>>>>> (require '[yoyo :refer [ylet]])
>>>>>>
>>>>>> (defn with-connections [config f]
>>>>>> (ylet [db-pool (with-db-pool (:db config))
>>>>>> es-conn (with-es-connection (:elasticsearch config))]
>>>>>>
>>>>>> (f {:db-pool db-pool
>>>>>> :es-conn es-conn})))
>>>>>>
>>>>>> (defn make-system [latch]
>>>>>> (let [config ...]
>>>>>> (ylet [connections (with-connections system)
>>>>>> _ (with-webserver {:handler (make-handler (merge connections
>>>>>> {:config
>>>>>> config}))
>>>>>> :port 3000})]
>>>>>> (latch))))
>>>>>>
>>>>>>
>>>>>> How would you see the with-* functions working, btw?
>>>>>>
>>>>>
>>>>> I think the general idea should be to provide a clean API to the
>>>>> consumer (of your lib). Perhaps something that accepts a start function,
>>>>> a
>>>>> stop function and some sort of main loop (f in your example).
>>>>>
>>>>
>>>> Not sure I understand what you mean here? Tbh, I was trying to get away
>>>> from the idea of separate start & stop functions - it seems 'cleaner' to
>>>> me
>>>> without them! (although of course that's subjective).
>>>>
>>>> Also, the 'with-*' functions here are consumer code - the only Yo-yo
>>>> functions/macros in this example are 'run-system!' and 'ylet'. Yo-yo
>>>> itself
>>>> is *tiny* (<100 LoC) - my aim was for a library that solely dealt with
>>>> starting/stopping a provided system, and *no more* :)
>>>>
>>>> Maybe it'd be worth fleshing out an example of what you were looking
>>>> for?
>>>>
>>>> Cheers,
>>>>
>>>> James
>>>>
>>>>
>>>>>
>>>>>>
>>>>>> Cheers,
>>>>>>
>>>>>> James
>>>>>>
>>>>>> On Tuesday, 23 June 2015 09:57:16 UTC+1, Atamert Ölçgen wrote:
>>>>>>>
>>>>>>> Hi James,
>>>>>>>
>>>>>>> Interesting idea. Thanks for sharing.
>>>>>>>
>>>>>>> I think you can simplify this:
>>>>>>>
>>>>>>> (yoyo/run-system!
>>>>>>> (fn [latch]
>>>>>>> (ylet [db-pool (with-db-pool {...})
>>>>>>> :let [server-opts {:handler (make-handler {:db-pool
>>>>>>> db-pool})
>>>>>>> :port 3000}]
>>>>>>> web-server (with-web-server server-opts)]
>>>>>>> (do-this web-server)
>>>>>>> (do-that db-pool web-server)
>>>>>>> (latch))))
>>>>>>>
>>>>>>>
>>>>>>> to:
>>>>>>>
>>>>>>> (yoyo/foo! [db-pool (with-db-pool {...})
>>>>>>> :let [server-opts {:handler (make-handler {:db-pool
>>>>>>> db-pool})
>>>>>>> :port 3000}]
>>>>>>> web-server (with-web-server server-opts)]
>>>>>>> (do-this web-server)
>>>>>>> (do-that db-pool web-server))
>>>>>>>
>>>>>>>
>>>>>>> I believe with-* function can also be simplified further.
>>>>>>>
>>>>>>>
>>>>>>> On Tue, Jun 23, 2015 at 1:18 AM, James Henderson <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hi all,
>>>>>>>>
>>>>>>>> I've just released an early version of 'Yo-yo', a protocol-less,
>>>>>>>> function composition-based alternative to Component. It's still in its
>>>>>>>> early stages, so feedback would be very much appreciated!
>>>>>>>>
>>>>>>>> https://github.com/james-henderson/yoyo
>>>>>>>>
>>>>>>>> Yo-yo was also an experiment to see what could be de-coupled from
>>>>>>>> the concept of 'reloadable systems', so you won't find any
>>>>>>>> configuration,
>>>>>>>> dependency injection, etc - just a way to write a system that can be
>>>>>>>> easily
>>>>>>>> started, stopped, and reloaded.
>>>>>>>>
>>>>>>>> Fundamentally, we start by assuming there's a function available
>>>>>>>> that only returns 'when the system stops' - a 'latch', say. If we had
>>>>>>>> such
>>>>>>>> a function, we could start our system, call that function, then stop
>>>>>>>> the
>>>>>>>> system (closing any necessary resources). A database pool, for
>>>>>>>> example,
>>>>>>>> might look like this:
>>>>>>>>
>>>>>>>> (defn with-db-pool [db-config f]
>>>>>>>> (let [db-pool (start-pool! db-config)]
>>>>>>>> (try
>>>>>>>> (f db-pool)
>>>>>>>>
>>>>>>>> (finally
>>>>>>>> (stop-pool! db-pool)))))
>>>>>>>>
>>>>>>>> Here, we're assuming that we'll be passed 'f', the 'latch'
>>>>>>>> function. A web server would be similar, and, because they're both
>>>>>>>> functions, they're very simple to compose:
>>>>>>>>
>>>>>>>> (with-db-pool {...}
>>>>>>>> (fn [db-pool]
>>>>>>>> (with-web-server {:handler (make-handler {:db-pool db-pool})
>>>>>>>> :port ...}
>>>>>>>> (fn [web-server]
>>>>>>>> ;; TODO: Ah. We've run out of turtles. :(
>>>>>>>> ))))
>>>>>>>>
>>>>>>>> This is where Yo-yo comes in - there’s a function called
>>>>>>>> run-system!, which takes a function that accepts a latch:
>>>>>>>>
>>>>>>>> (:require [yoyo])
>>>>>>>>
>>>>>>>> (yoyo/run-system!
>>>>>>>> (fn [latch]
>>>>>>>> (with-db-pool {...}
>>>>>>>> (fn [db-pool]
>>>>>>>> (with-web-server {:handler (make-handler {:db-pool db-pool}) ;
>>>>>>>> n.b. we have access to the db-pool here - no need for global state!
>>>>>>>> :port ...}
>>>>>>>> (fn [web-server]
>>>>>>>> (latch))))))) ; Aha!
>>>>>>>>
>>>>>>>> run-system! then returns a promise - deliver any value to it, and
>>>>>>>> it'll stop the system.
>>>>>>>>
>>>>>>>> And that's pretty much it! There are a few more functions - mostly
>>>>>>>> to do with easily starting/stopping/reloading a system through the
>>>>>>>> REPL,
>>>>>>>> and a macro to simplify the 'function staircase' - these are covered
>>>>>>>> in
>>>>>>>> more detail in the README. There are some also common components - a
>>>>>>>> database pool, a web server, and a simple integration for existing
>>>>>>>> Component systems.
>>>>>>>>
>>>>>>>> It'd be great to hear your thoughts/ideas, whatever they may be -
>>>>>>>> either through here, e-mail, Github, or Twitter - thanks!
>>>>>>>>
>>>>>>>> James
>>>>>>>>
>>>>>>>> --
>>>>>>>> You received this message because you are subscribed to the Google
>>>>>>>> Groups "Clojure" group.
>>>>>>>> To post to this group, send email to [email protected]
>>>>>>>> Note that posts from new members are moderated - please be patient
>>>>>>>> with your first post.
>>>>>>>> To unsubscribe from this group, send email to
>>>>>>>> [email protected]
>>>>>>>> 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 [email protected].
>>>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Kind Regards,
>>>>>>> Atamert Ölçgen
>>>>>>>
>>>>>>> ◻◼◻
>>>>>>> ◻◻◼
>>>>>>> ◼◼◼
>>>>>>>
>>>>>>> www.muhuk.com
>>>>>>>
>>>>>> --
>>>>>> You received this message because you are subscribed to the Google
>>>>>> Groups "Clojure" group.
>>>>>> To post to this group, send email to [email protected]
>>>>>> Note that posts from new members are moderated - please be patient
>>>>>> with your first post.
>>>>>> To unsubscribe from this group, send email to
>>>>>> [email protected]
>>>>>> 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 [email protected].
>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Kind Regards,
>>>>> Atamert Ölçgen
>>>>>
>>>>> ◻◼◻
>>>>> ◻◻◼
>>>>> ◼◼◼
>>>>>
>>>>> www.muhuk.com
>>>>>
>>>>
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
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 [email protected].
For more options, visit https://groups.google.com/d/optout.