Transcript

Components!Taming Clojure applications

David Dossot

Every application, ever*

● Subsystem lifecycle

● Long running processes

● Connections pools

● Caches

* almost

The Clojure Curse*

* http://www.winestockwebdesign.com/Essays/Lisp_Curse.html

● Clojure can do anything

● No official app framework

● NIH is a risk

● We went there...

Take #1 ~ Atoms ?

(def ^:dynamic server (atom nil))

(defn start [config]

(reset! server

(make-server config)))

(defn stop []

(.stop @server))

Take #1 ~ Atoms ✘

● Easy :)

● Shared state :(

● All over the place :(

● Reload unfriendly :(

● No dependencies :(

Take #2 ~ Maps ?

(defn start [execution-context config]

(assoc execution-context

:server (make-server config)))

(defn stop [execution-context]

(.stop (:server execution-context))

(dissoc execution-context :server))

Take #2 ~ Maps ✘

● Pure functions :)

● Reload friendly :)

● All in one place :)

● Ad-hoc lifecycle :(

● No dependencies :(

Take #3 ~ Components ?

(defrecord Server [server config]

component/Lifecycle

(start [this]

(if server ; already started

this

(assoc this :server (make-server config))))

(stop [this]

(if-not server ; already stopped

this

(do

(.stop server)

(assoc this :server nil)))))

Take #3 ~ Components ✔

● Pure functions :)

● Reload friendly :)

● All in one place :)

● Lifecycle API :)

● Dependencies :)

Caveat emptor

● Invasive● All fns that reify the module's behaviour

● Wish clj had Erlang's parameterized modules*

● Records can be weird● lein clean is your friend

* experimental feature, now removed :(

Resources

https://github.com/stuartsierra/component

https://youtu.be/13cmHf_kt-Q

top related