What I understand from Stuart's conversations looks something like this:
(ns state.core)
(defn create-user-module [] (atom []))
(defn add-user [module user]
(swap! module conj user))
(defn get-users [module]
@module)
Now in your "core" there is no global state, since functions that manipulate the state expect to receive it as a parameter. This makes it easy to test, since you can create a new instance of a “user module” for each test. In addition, the clients of this module do not have to worry about what they get in the create-user-module function, they just need to pass it without checking, so you can change the implementation of the user module whenever you want. Stewart also talks about creating protocols for these modules if you have more than one implementation.
, - 1 , compojure - , -, , :
(ns state.web
(:use compojure.core)
(:require [state.core :as core]))
(defn web-module [user-module]
(routes
(GET "/all" [] (core/get-users user-module))))
- webapp, . , , - - , "" , :
(ns state.main
(:require state.core
state.web)
(:use ring.adapter.jetty))
(defn start []
(let [user-module (state.core/create-user-module)
web-module (state.web/web-module user-module)]
(run-jetty web-module {:port 3000 :join? false})))
(defn stop [app]
(.stop app))
start main. , lein-run.
, , init ( lein ring), , webapp . lein ring java fw Java, , , , , - :
(ns state.web
(:use compojure.core)
(:require [state.core :as core]))
(def module-deps (atom {})
(defn init-app [] (swap! module-deps conj [:user-module (core/create-user-module)]))
(defroutes web-module []
(GET "/all" [] (core/get-users (:user-module @module-deps))))
- , , , , "" , , , java.
, "", :)