Upload
william-farrell
View
202
Download
3
Embed Size (px)
Citation preview
Who am I?
I’m the Lead Software Architect at MojoTech in Providence, RI, that’s who.
We’re a software consultancy, and we’ve built many web and mobile apps.
What can you expect to learn?
• How hermeticity is an example of functional design thinking
• How to identify “leaks” in not-so-hermetic systems
• How to leverage Clojure to build and manage hermetic systems
Why is hermeticity desirable?;; ...
(ns determinism (:require [hermeticity]))
(defn system [well-defined-input] well-defined-output)
;; ...
What’s wrong with libraries?(defproject motrics "0.1.0-SNAPSHOT" :description "Mojotech Metrics" :url "https://github.com/mojotech/motrics" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :repositories {"elasticsearch-releases" "https://maven.elasticsearch.org/releases"} :dependencies [[org.clojure/clojure "1.7.0"] [com.stuartsierra/component "0.3.1"] [com.taoensso/timbre "4.2.1"] [com.taoensso/carmine "2.12.2"] [com.github.kstyrc/embedded-redis "0.6"] [org.elasticsearch/elasticsearch "2.2.0"] [org.elasticsearch.plugin/shield "2.2.0"] [environ "1.0.2"] [tentacles "0.5.1"] [suspendable "0.1.0"]] :main ^:skip-aot motrics.core :target-path "target/%s" :test-paths ["src/test"] :source-paths ["src/main"] :min-lein-version "2.0.0" :profiles {:uberjar {:aot :all} :dev {:jvm-opts ["-Xmx300m"] :source-paths ["src/dev"] :repl-options {:init-ns motrics.repl} :dependencies [[reloaded.repl "0.2.1"]]}})
What’s wrong with services? $ ping api.github.com ping: cannot resolve api.github.com: Unknown host ping: cannot resolve api.github.com: Unknown host ping: cannot resolve api.github.com: Unknown host ping: cannot resolve api.github.com: Unknown host ping: cannot resolve api.github.com: Unknown host ping: cannot resolve api.github.com: Unknown host ping: cannot resolve api.github.com: Unknown host
What are components?(defrecord ExampleComponent [options cache database scheduler] component/Lifecycle
(start [this] (println ";; Starting ExampleComponent") ;; In the 'start' method, a component may assume that its ;; dependencies are available and have already been started. (assoc this :admin (get-user database "admin")))
(stop [this] (println ";; Stopping ExampleComponent") ;; Likewise, in the 'stop' method, a component may assume that its ;; dependencies will not be stopped until AFTER it is stopped. this))
What are systems?(defn example-system [config-options] (let [{:keys [host port]} config-options] (component/system-map :db (new-database host port) :scheduler (new-scheduler) :app (component/using (example-component config-options) {:database :db :scheduler :scheduler}))))
Embed Elasticsearch(defrecord EmbeddedElasticsearchServer [config] component/Lifecycle
(component/start [this] (update this :node #(or % (-> (:elasticsearch-server config) (update :settings (partial merge default-node-settings)) (elasticsearch/new-node) (elasticsearch/start-node)))))
(component/stop [this] (some-> this :node elasticsearch/stop-node) (dissoc this :node))
suspendable/Suspendable
(suspendable/suspend [this] this)
(suspendable/resume [this that] (if (= (-> this :config :elasticsearch-server) (-> that :config :elasticsearch-server)) (assoc this :node (:node that)) (do (component/stop that) (component/start this)))))
REPL namespace
(ns my-app.repl (:require [reloaded.repl :as repl :refer [system start stop go reset reset-all]] [com.stuartsierra.component :as component] [my-app.elasticsearch :refer [new-embedded-elasticsearch-server]] [my-app.core :as my-app] [my-app.config :as config]))
Manage services(def config (merge config/config {:elasticsearch-server {:settings {"cluster.name" "elasticsearch" "http.enabled" "true" "http.host" "127.0.0.1" "http.port" "9200" "transport.host" "127.0.0.1" "transport.tcp.port" "9300"}}}))
(repl/set-init! #(-> (component/system-map :worker-service (my-app/new-worker-service config) :embedded-elasticsearch-server (new-embedded-elasticsearch-server config)) (component/system-using {:worker-service [:embedded-elasticsearch-server]})))
Embeddable Services
• datomic
• zookeeper
• h2
• kafka
• elasticsearch
• rabbitmq
• postgresql
• redis
• neo4j
• and more!
How do we reproduce random?(defn random-seq "Generate a lazy sequence of random numbers based on an intial seed." [seed n] (let [r (java.util.Random. seed)] (repeatedly #(.nextInt r n))))
(take 5 (random-seq 1 10)) ;;-> (2 5 7 1 8)
(take 5 (random-seq 1 10)) ;;-> (2 5 7 1 8)
(take 5 (random-seq 2 10)) ;;-> (3 6 5 5 9)
How can we model time?(defn application [from-tick to-tick] “Run our important application.” (let [clock (new-clock from-tick to-tick)] ;; ... ))
;; Run from tick 0 to 100 (application 0 100)
;; Run from tick 0 to 200 (application 0 200)
;; Run from tick 200 to 300 (application 200 300)
What did we learn?
• How to evaluate systems and find leaks
• How to plug leaks when you find them
• How to make good trade-offs when building hermetic systems