>
>
> > As it sounds a lot like your definition of OOP to me.
>
> For sure, this code relies on messages passing. It is "functional" in the 
> old sense that the messages are functions -- a usage of the word 
> "functional" that any Lisper would have understood for decades. But it is 
> not "functional" in the newer sense of "immutable". 
>
> However, I avoid the things I dislike most about OOP: instantiating 
> objects, and having an outside Dependency Injection system that decides 
> what the dependencies of this code should be. As much as possible, I try to 
> write "start" and "stop" functions that take responsibility for initiating 
> whatever needs to be initiated for this namespace. 
>
>
> So it sounds like you went and re-built component, but this time 
> around message passing, and mutable actors.

And without records, which was the thing I felt was unnecessary in 
Component. 


A slightly simplified example: 
>
> (ns mercury.message-queue
>   (:require
>    [mercury.datastore :as datastore]
>    [manifold.stream :as stream]
>    [manifold.deferred :as deferred]
>    [taoensso.timbre :as timbre]
>    [clojure.test :as test]))
>
> (def ^:private message-stream (atom nil))
>
> (defn enqueue
>   [message eventual-result]
>   {:pre [
>    (keyword? (:field-to-sort-by message))
>  (number? (:offset message))
>  (number? (:limit message))
>   ]}
>   (stream/put! @message-stream
>     [
>      (fn [db-connection]
>  (try 
>       (datastore/execute message db-connection)
>   (catch Exception e (timbre/log :trace (str "The was an exception when we 
> tried to call the datastore layer: " e)))))
>      eventual-result
>     ]))
>
> (defn- worker
>   [db-connection]
>   (loop [message-vector @(stream/take! @message-stream)]
>       (let [message-fn (first message-vector)
>             eventual-result (second message-vector)]
>         (deliver eventual-result (message-fn db-connection)))
>     (if (= @message-stream ::stop)
>       (datastore/stop db-connection)
>       (recur @(stream/take! @message-stream)))))
>
> (defn start
>   [map-of-config-info]
>   (swap! message-stream (fn [old-stream] (stream/stream)))
>   (dotimes [_ 10]
>     (future (worker (datastore/start map-of-config-info)))))
>
> (defn stop []
>   (swap! message-stream (fn [old-stream] ::stop)))
>   
>   
>
 
 

> The "start" method spins up some workers and makes sure they each have a 
> database connection. 
>

The "stop" function sets in motion events that cause each worker to shut 
down its own database connection. 

 

>
>
>
> On Sunday, June 21, 2015 at 7:10:42 PM UTC-4, tbc++ wrote:
> I'd like to see an example of this "functional worker" style you mention. 
> As it sounds a lot like your definition of OOP to me. Not to mention that 
> anything that talks to a queue is performing io and is therefore not 
> functionally pure. So it sounds like you went and re-built component, but 
> this time around message passing, and mutable actors.
>
> On Sunday, June 21, 2015, Lawrence Krubner <lawr...@rollioforce.com> wrote:
> There are ways to handle dependencies without going down the OOP route 
> that Stuart Sierra took. However, there are a lot of good ideas in Stuart 
> Sierra's Component library, and to the extent that you can borrow those 
> ideas, you end up with code that resembles "best practice" in the Clojure 
> community. 
>
> For me, one "Big Idea" that I got from Stuart Sierra is that there should 
> be a "start" method that can be called either from the REPL or from -main 
> (for when you app runs as a daemon). The other "Big Idea" I got was that 
> there should be functions for handling the lifecycle of all the components 
> in your app, so you can easily start and stop and restart. So nowadays my 
> "core.clj" tends to look like this: 
>
> (ns salesslick.core
>   (:gen-class)
>   (:require
>    [salesslick.start :as start]
>    [salesslick.stop :as stop]))
>
> ;; what you would call from the REPL to re-initate the app
> (defn start []
>   (try
>     (start/start)
>     (catch Exception e (println e))))
>
> (defn stop []
>   (try
>     (stop/stop)
>     (catch Exception e (println e))))
>
> ;; Enable command-line invocation
> (defn -main [& args]
>   (.addShutdownHook (Runtime/getRuntime)
>     (Thread.
>       #(do (println "Salesslick is shutting down")
>         (stop))))
>   (start))
>
> So I can call "start" and "stop" from the REPL, or, if the app is running 
> as a daemon, "start" gets called by -main, and "stop" is registered as a 
> shutDownHook. 
>
> These are great ideas that I got from Stuart Sierra, however, I did not 
> feel the need to go as far toward OOP as Stuart Sierra did. And some of 
> things he has suggested as "best practice" really strike me as odd. To be 
> honest, some of the things he said were astonishing and went against 
> everything I have learned over the years. I'm thinking of what he says in 
> these 2 videos: 
>
> http://www.infoq.com/presentations/Clojure-Large-scale-patterns-techniques
>
> Stuart Sierra - Components Just Enough Structure
>
> At one point he says that "Object Oriented code has the advantage that it 
> is obvious where you configure your code." 
>
> Wow!!! What can I say about that!!! 
>
> I have lost entire days because I was dragged into stupid, tedious 
> meetings whose subject was "How should we refactor these fat Rails models?" 
>
> I've been dragged into incredibly boring meetings to discuss Rails versus 
> Sinatra, where the main thing under discussion was really the issue of 
> configuration. 
>
> When I am on my deathbed, looking back, I will recall some days fondly, 
> and other days I will recall as wasted, and the most sadly wasted days of 
> all are the days I was forced to discuss Dependency Injection with my 
> co-workers. 
>
> None of my experiences allow me to agree with Stuart Sierra that OOP makes 
> it obvious how to configure an app. 
>
> Still, without a doubt, there are good ideas in Stuart Sierra's Component 
> library, and it is worth digging into them to find the good ideas. 
>
> The place where I diverge from Stuart Sierra is in his use of Records. His 
> main concern seems to be making dependencies visible. It's the same issue 
> that Alex Miller focuses on here: 
>
> http://tech.puredanger.com/2014/01/03/clojure-dependency-injection/
>
> My own preference for making dependancies obvious is to use :pre 
> assertions. I'm looking at Typed Clojure as a possibility for going further 
> down that road. 
>
> There might be use cases where it is fundamentally imperative to use 
> something like Stuart Sierra's pseudo-OOP style, but I have not met those 
> use cases yet. Most of the work I do tends to be the kind of thing where I 
> can spin up some internal "workers" and have them pull work off a queue. I 
> can initiate the workers from my "start" function and stop them with the 
> "stop" function. Typically, each worker will have its own connection to 1 
> or more databases, and each worker takes responsibility for closing its 
> database connections once the "stop" function has been called. 
>
> All of this is easy to do within the Functional Paradigm. 
>
> I think there is a fascinating sociological question that haunts the 
> Clojure community, regarding OOP. Many of the best Clojure developers spent 
> 10 or 20 years doing OOP before they came to Clojure, so how much do they 
> bring OOP with them because they feel its natural, and they feel it natural 
> because they spent so many years with the OOP style? 
>
>
>
>
>
>
>
>
>
>
>
>
>
> On Wednesday, June 17, 2015 at 10:15:21 PM UTC-4, Xiangtao Zhou wrote:
> hi guys,
>
> Constructing simple clojure project is trival, just make functions. if the 
> project grows large, with more datasources, message queue, and other 
> storages, dependencies problem is on the table. 
>
> One solution is stuartsierra/component,  using system to configure 
> dependencies graph, make component and dependencies resolution separate.
>
> If we make namespace must run with code block that init the namespace, 
> like the "start" method in component, is this a good way to solve the 
> dependencies?
>
> because when the namespace is required the first time, the init block 
> worked once.
>
> any suggestion is appreciated.
>
>
> - Joe
> -- 
> 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.
>
>
> -- 
> “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.

Reply via email to