Hi Timothy - firstly, thank you for taking the time to read through and reply. I understand it would have been very easy to read them and move on thinking 'just a nutter on the mailing list who doesn't really understand what he's talking about', but I do really appreciate your feedback - thanks :)
You're right - openly, I think it took not only hammocking about Yo-yo, but also sitting down over the weekend writing up the side-by-side to really realise what Component and Yo-yo both provide. (I don't regret doing either, of course - without doing so I wouldn't have got close to thinking about it in this way!) I do agree that not everything about Spring/OOP is bad, and certainly that Clojure/Component has taken the good parts. What I've seen so far, though, is some people (me included, probably) seeing Component, thinking 'that's nice, a pattern I'm familiar with', and reverting to writing Clojure apps like they used to write Spring apps - with components for *everything*, components for wiring up other components, etc, giving them all sorts of names (a la 'the Kingdom of Nouns'). It's also Phoenix, in particular, that reminded people of Spring - I've tried to ensure I always make that distinction, apologies if that didn't come across. Incidentally, I wrote a first iteration of the side-by-side blog with the Component side written in this style, and then realised there was nothing in Component that mandated writing in that way; just that I and others had interpreted it that way - it was quite an 'aha' moment! I'd also not heard that advice about anonymous functions either - thanks! Thinking about it, I've come up with all sorts of workarounds to get closed-over variables out of closures. Having said that, I think there's still some legs in Yo-yo - given that it doesn't mandate writing apps in any style (only that the one top level function accepts a system latch) it's possible to write Yo-yo apps as you would a Component system, or using functional composition, or anywhere in between. At the very least, Yo-yo would help with managing Component's system at the REPL - the top-level function becomes: (defn make-system [f] (let [started-system (-> (c/system-map ...) c/start-system)] (try (f started-system) (finally (c/stop-system started-system))))) (defn -main [& args] (yoyo/set-system-fn! 'myapp.main/make-system) (yoyo/start!)) with the ability to then run (yoyo/reload!) etc from the REPL (without everyone having to write their own user namespace start/stop functions) I do also like the way that there aren't separate start/stop functions - maybe there's scope for a Lifecycle protocol that only involves one function instead? Maybe that's not even a good idea either, I don't know. I'll keep on experimenting, that's for sure :) Thanks again, James On Monday, 29 June 2015 02:49:43 UTC+1, tbc++ wrote: > > A few bits of feedback after seeing these examples. > > Firstly, I'd like to see a more fleshed-out rationale. Currently it sounds > a bit like cargo-culting, e.g. "Spring is bad, Component reminds people of > Spring, therefore Component is bad". I'd challenge several parts of that > rationale, but the first is that "spring is bad". Why is that so? Is it the > XML configuration? Because Component doesn't have that. Is it the > mutability? Because Component doesn't have that either. Sadly I'm afraid > some people seem to see polymorphic functions (protocols) and think "AAAHHH > OOP! OOP IS BAD!!". When that's not really the case. The worst parts of OOP > are mutability and encapsulation of state inside opaque objects. Component > (and clojure for that matter) discourages both of these, so I'm not sure I > see the problem. > > Secondly, I'm a bit leery of using anonymous functions instead of records. > I once worked on a system with a co-worker, and I asked him "why are you > using a record here...why not a closure?". He replied: "Because I can't see > what's inside a closure...it's opaque". That bit of advice has stuck with > me for some time. With something like component, if I have a function that > takes a component, I can look at that argument and see something like this: > > => #db.DBClient {:server "127.0.0.1" :port 4242 :schema "my-schema"} > > With Closures I get something like this: > > => <fn foo.bar.baz > > > That doesn't help much with debugging. > > With Records I get immutability plus a type I can extend to any protocols. > Also, since my protocol is clearly defined, it's simple to extend. I don't > have to worry about hidden functions some inner function may call on my > client. Protocols provide abstraction. > > So I guess that's my critique of Yo-Yo. I'd love to see a more in-depth > rationale, and I get nervous when people replace protocols with plain > functions, because normally I loose some expressiveness in the process. > > Timothy > > On Sun, Jun 28, 2015 at 8:03 AM, James Henderson <ja...@jarohen.me.uk > <javascript:>> 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 clo...@googlegroups.com >> <javascript:> >> 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 <javascript:> >> 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 <javascript:>. >> For more options, visit https://groups.google.com/d/optout. >> > > > > -- > “One of the main causes of the fall of the Roman Empire was that–lacking > zero–they had no way to indicate successful termination of their C > programs.” > (Robert Firth) > -- 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.