Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dependency management in Clojure

schaueho
February 20, 2016

Dependency management in Clojure

Dependencies between components are one of the primary drivers of the flexibility of any bigger applications. Clojure provides a number of tools to manage dependencies, some are built-in, some are built on libraries. We’ll look at basic building blocks like higher-order functions and protocols, but also at libraries like Stuart Sierra’s component.

Presentation by Holger Schauer at ClojureD, Berlin, 2016-02-20

schaueho

February 20, 2016
Tweet

More Decks by schaueho

Other Decks in Programming

Transcript

  1. View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. (ns playitloud.ui-player
    (:require [playitloud.simple-player :refer [play]]))
    (defn play-pressed [randomize]
    (println "User pressed play")
    (play randomize))

    View Slide

  8. (ns playitloud.ui-player
    (:require [playitloud.simple-player :refer [play]]))
    (defn play-pressed [randomize]
    (println "User pressed play")
    (play randomize))
    (ns playitloud.simple-player
    (:require [playitloud.speaker :refer [blare]]
    [playitloud.musiccoll :refer [get-songs]]))
    (defn play [randomize]
    (let [songs (get-songs)
    songs (if randomize (shuffle songs) songs)]
    (map (fn [song]
    (blare song))
    songs)))

    View Slide

  9. (ns playitloud.ui-player
    (:require [playitloud.simple-player :refer [play]]))
    (defn play-pressed [randomize]
    (println "User pressed play")
    (play randomize))
    (ns playitloud.simple-player
    (:require [playitloud.speaker :refer [blare]]
    [playitloud.musiccoll :refer [get-songs]]))
    (defn play [randomize]
    (let [songs (get-songs)
    songs (if randomize (shuffle songs) songs)]
    (map (fn [song]
    (blare song))
    songs)))
    (ns playitloud.speaker)
    (defn blare [song]
    (let [result (str "Speaker plays " song)]
    (println result)
    result))

    View Slide

  10. View Slide

  11. (ns playitloud.ho.player)
    (defn play [blarefn songgetterfn randomize]
    (let [songs (songgetterfn)
    songs (if randomize (shuffle songs) songs)]
    (map (fn [song]
    (blarefn song))
    songs)))

    View Slide

  12. (ns playitloud.ho.player)
    (defn play [blarefn songgetterfn randomize]
    (let [songs (songgetterfn)
    songs (if randomize (shuffle songs) songs)]
    (map (fn [song]
    (blarefn song))
    songs)))
    ; ---------------------------------------------------
    (ns playitloud.ho.ui-player
    (:require [playitloud.ho.player :as ho :refer [play]]
    [playitloud.speaker :as speaker]
    [playitloud.headphone :as headphone]
    [playitloud.blue-streamer :as streamer]
    [playitloud.musiccoll :refer [get-songs]]))
    (defn play-pressed [speaker randomize]
    (println "User pressed play")
    (condp = speaker
    :speaker (play speaker/blare get-songs randomize)
    :headphone (play headphone/blare get-songs randomize)
    :stream (play streamer/blare get-songs randomize)))

    View Slide

  13. (defn make-playfn
    "Returns a function that will play all songs"
    [blarefn songgetterfn]
    (fn ; Plays all songs, potentially randomized
    [randomize]
    (let [songs (songgetterfn)
    songs (if randomize (shuffle songs) songs)]
    (map (fn [song]
    (blarefn song))
    songs))))

    View Slide

  14. (ns playitloud.ho.play-config [...]
    (def speaker-play (make-playfn speaker/blare get-songs))
    (def headphone-play (make-playfn headphone/blare get-songs))
    (def stream-play (make-playfn streamer/blare get-songs))
    (defn select-playfn [speaker]
    (condp = speaker
    :speaker speaker-play
    :headphone headphone-play
    :stream stream-play))
    (ns playitloud.ho.clos-ui-player
    (:require [playitloud.ho.play-config :refer [select-playfn]]))
    (defn play-pressed [output randomize]
    (let [playfn (select-playfn output)]
    (playfn randomize)))

    View Slide

  15. (ns playitloud.services.config)
    (def ^:dynamic *services*
    {:blare playitloud.speaker/blare
    :get-songs playitloud.musiccoll/get-songs})

    View Slide

  16. (ns playitloud.services.config)
    (def ^:dynamic *services*
    {:blare playitloud.speaker/blare
    :get-songs playitloud.musiccoll/get-songs})
    (ns playitloud.services.player
    (:require [playitloud.services.config :refer [*services*]]))
    (defn- blare [sound]
    ((:blare *services*) sound))
    (defn- get-songs []
    ((:get-songs *services*)))

    View Slide

  17. (ns playitloud.services.config)
    (def ^:dynamic *services*
    {:blare playitloud.speaker/blare
    :get-songs playitloud.musiccoll/get-songs})
    (ns playitloud.services.player
    (:require [playitloud.services.config :refer [*services*]]))
    (defn- blare [sound]
    ((:blare *services*) sound))
    (defn- get-songs []
    ((:get-songs *services*)))
    (defn play [randomize]
    (let [songs (get-songs)
    songs (if randomize (shuffle songs) songs)]
    (map (fn [song]
    (blare song))
    songs)))

    View Slide

  18. (ns playitloud.sig.output-device
    (:require [de.find-method.funsig :refer [defsig]]))
    (defsig blare "Play sound loudly!" [sound])

    View Slide

  19. (ns playitloud.sig.output-device
    (:require [de.find-method.funsig :refer [defsig]]))
    (defsig blare "Play sound loudly!" [sound])
    (ns playitloud.sig.speaker
    (:require [de.find-method.funsig :refer [defimpl]]
    [playitloud.sig.output-device :refer [blare]]))
    (defimpl blare [sound]
    (let [result (str "Speaker plays " sound)]
    (println result)
    result))

    View Slide

  20. (ns playitloud.sig.output-device
    (:require [de.find-method.funsig :refer [defsig]]))
    (defsig blare "Play sound loudly!" [sound])
    (ns playitloud.sig.speaker
    (:require [de.find-method.funsig :refer [defimpl]]
    [playitloud.sig.output-device :refer [blare]]))
    (defimpl blare [sound]
    (let [result (str "Speaker plays " sound)]
    (println result)
    result))
    (ns playitloud.sig.player
    (:require [playitloud.sig.output-device :refer [blare]]
    [playitloud.musiccoll :as mc :refer [get-songs]]))
    (defn play [randomize]
    (let [songs (get-songs)
    songs (if randomize (shuffle songs) songs)]
    (map (fn [song]
    (blare song))
    songs)))

    View Slide

  21. (ns playitloud.proto.output-device)
    (defprotocol OutputDevice
    (blare [device sound])
    (inc-volume [device])
    (dec-volume [device]))
    (ns playitloud.proto.speaker
    (:require [playitloud.proto.output-device
    :as output :refer :all]))
    (defrecord Speaker [volume]
    OutputDevice
    (blare [_ sound]
    (let [result (str "Speaker plays " sound)]
    (println result)
    result))
    ;[...]

    View Slide

  22. (ns playitloud.proto.player
    (:require [playitloud.proto.output-device :as output]
    [playitloud.musiccoll :as mc]))
    (defn play [output-device randomize]
    (let [songs (mc/get-songs)
    songs (if randomize (shuffle songs) songs)]
    (map (fn [song]
    (output/blare output-device song))
    songs)))

    View Slide

  23. View Slide

  24. View Slide

  25. View Slide

  26. View Slide

  27. with-...

    View Slide

  28. with-...
    binding map

    View Slide

  29. View Slide

  30. (ns playitloud.comp.streamer
    (:require [com.stuartsierra.component :as component]
    [playitloud.comp.output-device :as output :refer :all]
    [playitloud.comp.remote-connection :as remote]))
    (defrecord BlueStreamer [connection volume]
    OutputDevice
    (blare [streamer sound]
    ;... normal protocol/record implementation ...)
    component/Lifecycle
    (start [streamer]
    (println "BlueStreamer starting")
    (connect (:connection streamer) streamer)
    (assoc streamer :status :connected))
    (stop [streamer]
    (println "BlueStreamer stopping")
    (disconnect (:connection streamer) streamer)
    (->> (assoc streamer :status :disconnected)
    (dissoc :connection))))
    (defn new-blue-streamer [config]
    (->BlueStreamer nil (:default-volume config)))

    View Slide

  31. (ns playitloud.comp.config
    (:require [com.stuartsierra.component :as component]
    [playitloud.comp.blue-connection :as blueconn]
    [playitloud.comp.streamer :as streamer]
    [playitloud.comp.player :as player]))
    (def default-config
    {:bt-conn {:name "Fabuluous-Connectivity" :port "1234"}
    :default-volume 5})
    (defn make-player-system
    "Setup the player system"
    ([]
    (make-player-system default-config))
    ([config]
    (component/system-map
    :connection (blueconn/new-connection config)
    :output-device (component/using
    (streamer/new-blue-streamer config)
    [:connection])
    :player (component/using
    (player/new-player)
    [:output-device]))))

    View Slide

  32. fun-a
    A
    fun-b fun-a
    A
    B
    B A

    View Slide

  33. View Slide

  34. View Slide

  35. View Slide

  36. View Slide

  37. View Slide