Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
* System ** What is it? System owes to [[https://github.com/stuartsierra/component][component]] both in spirit and in name. The component library helps implementing the reloaded pattern as championed by Stuart Sierra. System is built on top of it, offering a set of readymade components. This idea is to expand the set over time with contributions from the community. It currently includes: - [[https://github.com/mmcgrana/ring][Jetty]] (HTTP server) - [[http://http-kit.org/][HTTP kit]] (Async HTTP server) - [[http://www.datomic.com/][Datomic]] (Immutable database) - [[http://www.h2database.com/][H2]] (H2 relational database) - [[http://clojuremongodb.info/][Monger]] (MongoDB client) - [[https://github.com/ptaoussanis/sente][Sente]] (Websockets/Ajax communications library) - [[https://github.com/clojure/tools.nrepl][nREPL]] (Clojure network REPL ) - [[http://clojurerabbitmq.info/][Langohr]] (RabbitMQ client) ** Motivation A good REPL experience is a prerogative of Lisp languages. [[https://github.com/stuartsierra/reloaded][Reloaded]] components enable this goodness in Clojureland. Since they require an amount of setup, the first steps when starting a new project are generally devoted to infrastructure. My first attempt to tackle the boilerplate was a Leiningen [[https://github.com/danielsz/back-end-template][template]]. The problem is that Leiningen templates are hard to maintain and difficult to retrofit on existing projects. I was finding myself repeatedly updating the template for future use. Then it dawned on me that a library would better fit the bill. And so *system* came to light. It’s now the first dependency I add to any project, allowing me to focus from the get-go on the substance of my application. ** Is it good? [[https://news.ycombinator.com/item?id=3067434][Yes.]] ** Installation Add the following to the Leiningen dependencies in project.clj. #+BEGIN_SRC [org.danielsz/system "0.1.0-SNAPSHOT"] #+END_SRC ** Usage First, assemble your system(s) in a namespace of your choosing. Here we define two systems, development and production. #+BEGIN_SRC clojure (ns my-app.systems (:require [com.stuartsierra.component :as component] (system.components [jetty :refer [new-web-server]] [repl-server :refer [new-repl-server]] [datomic :refer [new-datomic-db]] [mongo :refer [new-mongo-db]]) [my-app.webapp :refer [handler]] [environ.core :refer [env]])) (defn dev-system [] (component/system-map :datomic-db (new-datomic-db (env :db-url)) :mongo-db (new-mongo-db) :web (new-web-server (env :http-port) handler))) (defn prod-system [] "Assembles and returns components for a production application" [] (component/system-map :datomic-db (new-datomic-db (env :db-url)) :mongo-db (new-mongo-db (env :mongo-url)) :web (new-web-server (env :http-port) handler) :repl-server (new-repl-server (env :repl-port)))) #+END_SRC *Note:* Component allows you to define dependency relationships within systems. Be sure to consult component’s API to see the range of options. Then, in user.clj: #+BEGIN_SRC clojure (ns user (:require [reloaded.repl :refer [system init start stop go reset]] [my-app.systems :refer [dev-system]])) (reloaded.repl/set-init! dev-system) #+END_SRC You can then manipulate the system in the REPL: ~(go)~, ~(reset)~ or ~(stop)~. The system map is accessible at any time, it resides in a var named, as you can guess, ~system~. In production, in core.clj: #+BEGIN_SRC clojure (ns my-app.core (:gen-class) (:require [my-app.systems :refer [prod-system]])) (defn -main [] "Start the application" (alter-var-root #'prod-system component/start) #+END_SRC Or, if you want to keep a handler on your system in production: #+BEGIN_SRC clojure (ns my-app.core (:gen-class) (:require [reloaded.repl :refer [system init start stop go reset]] [my-app.systems :refer [prod-system]])) (defn -main [] "Start the application" (reloaded.repl/set-init! prod-system) (go)) #+END_SRC ** The Reloaded pattern Here are a couple of links that are sure to shed more light on the motivations of the reloaded workflow. The canonical reference: [[http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded][My Clojure Workflow, Reloaded]] And more references touching on the topic. - [[http://www.infoq.com/presentations/Clojure-Large-scale-patterns-techniques][Clojure in the Large]] - [[http://martintrojer.github.io/clojure/2013/09/07/retrofitting-the-reloaded-pattern-into-clojure-projects/][Retrofitting the Reloaded pattern into Clojure projects]] - [[http://software-ninja-ninja.blogspot.co.il/2014/04/5-faces-of-dependency-injection-in.html][5 faces of dependency injection in Clojure]] - [[https://github.com/weavejester/reloaded.repl][REPL functions to support the reloaded workflow]] ** Contributing Please fork and issue a pull request to add more components. Please don't forget to include tests. You can refer to the existing ones to get started. ** Credits I wish to thank [[https://github.com/stuartsierra][Stuart Sierra]] for the pioneering and guidance. Special thanks to [[https://github.com/weavejester][James Reeves]] for the [[https://github.com/weavejester/reloaded.repl][reloaded.rep]]l library and general inspiration. Thanks to [[https://github.com/ptaoussanis][Peter Taoussanis]], the friendly OSS contributor, who helped to ‘componentize’ [[https://github.com/ptaoussanis/sente][sente]], an amazing library on its own right.