>
>
> > 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 <[email protected]> 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 [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.
>
>
> --
> “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 [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.