On Fri, Jul 3, 2015 at 2:19 PM, Thomas Heller <th.hel...@gmail.com> wrote:
> Hey James, > > "the webserver being a client" is really very simple. Basically instead of > starting one "app" you start two. Your actual "app" and the "web-app" that > depends on "app". One contains your business logic and the other everything > related to translating HTTP to app API calls. "app" doesn't know about the > web part. > Seems like you are describing hexagonal architecture. ( https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html) > > The component stuff also assumes that the web server itself is not a > component. A typical Servlet Container is built this way, it assumes that > it will host your app and not the other way around. I use http-kit but I > still want that hierarchy. Trying to turn the web server itself into > component just produces nightmares of cyclic dependencies and such. > > Can't really explain this very well, it is way too hot to think straight. > > I wanted to create a proper library out of my component stuff for a while > but never get around to it. I might do that some day to create an actual > example I can refer to. > > Cheers, > /thomas > > > On Friday, July 3, 2015 at 9:39:24 AM UTC+2, James Henderson wrote: >> >> 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 < >>>>>>> ja...@jarohen.me.uk> 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 < >>>>>>>>> ja...@jarohen.me.uk> 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 clo...@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+u...@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+u...@googlegroups.com. >>>>>>>>>> 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 clo...@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+u...@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+u...@googlegroups.com. >>>>>>>> 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 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. > -- 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 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.