Skip to content
 
 

Latest commit

 

History

37 Commits

Folders and files

NameName
Last commit message
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.

About

Reloaded components à la carte

Resources

Stars

1 star

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages