How to get rid of global data in Compojure application

There is a note at http://mindbat.com/2013/03/clojurewest-2013-day-one-notes/ that states:

  • defing refs and atoms at the top level are basically global mutable state through singles, please avoid
  • recommend using constructor functions to return the state variables you want to use, then pass that state along each function

I think this is good advice, but I'm not quite sure how to implement this in a Ring / Compojure application. Can someone give a concrete example of how this will work?

I am particularly interested in combining defroutes, initand appthus getting rid of global variables in this area.

+5
source share
2 answers

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.

, "", :)

+5

, , , , , , , 2 :

:

(ns data)
(def users (atom []))

(ns pages)
(defn home []
    (do-something data/@users)

(defn save []
    (let [u @users]
       (swap! data/users ....)

:

(ns data)
(def- users (atom []))
(defn get-users [] @users)
(defn update-user [user] (swap! @users ...))

(ns pages)
; use the functions exposed by data ns to interact with data rather then poking the atom directly.

, . - , .

+2

All Articles