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.

Reply via email to