IntelliJ + Cursive
and a bit of Stuart Sierra's reloaded workflow
Karol Andrusieczko
Clojure Meetup, 26.08.2015
Eyeota - they pay for my food
Digital advertising industry. Rapidly growing startup.
The global leader for local audience data with 1.3 billion unique profiles in Europe, APAC and the Americas.
Our partners are:
- advertisers
- publishers
- data suppliers
What's the project about?
WebAPI
Cassandra
ElasticSearch
Postgres (for legacy)
Ring (Immutant)
Compojure
Liberator
Cursive demo
Why Cursive
- IntelliJ gives the AST
- You don't have to run the code to get suggestions
- Flawless navigation
- Hints
- Refactoring
- Compilation errors / warnings live
- arity warnings
- unused variables
- Kibit embedded
- require/import support, dependency cycles detection
Manipulating syntax, not text
Drawbacks
- Will be non-free in the future (prices ~PyCharm)
- Sometimes it doesn't understand protocols/records
- Sometimes it doesn't understand macros
Advantages
- Mature IDE / one for all
- Great intelligence
- auto-completion
- navigation
- refactoring
- Shortcuts
- Great REPL
- Fantastic tests support
- Debugging
- RegExp refactoring
Reloaded workflow
by Stuart Sierra
Realoded workflow
Two important things:
clojure.tools.namespace.repl
NO GLOBAL STATE
Realoded workflow
The idea
To be able to shut the application down, discard any transient state it might have built up, start it again, and return to a similar state (...) in less than a second.
Realoded workflow
How?
- application put into an object
- you can construct an instance of the application (possibly many times)
- no global state
- really, no global state
Realoded workflow
What's a global state?
(def state-a (ref {}))
(def state-b (atom 0))
; hidden dependencies coming from outside
(defn op1 []
(dosync
(alter state-a ...)))
(defn op2 []
(dosync
(swap! state-b ...)))
(let [state-a (ref {})
state-b (atom 0)]
(defn op1 []
(dosync
(alter state-a ...)))
(defn op2 []
(dosync
(swap! state-b ...))))
Realoded workflow
How to avoid global state?
(defn constructor []
{:a (ref {})
:b (atom 0)})
; makes function dependencies clear
(defn op1 [state]
(dosync
(alter (:a state) ...)))
(defn op2 [state]
(dosync
(swap! (:b state) ...)))
Realoded workflow
Really easy to test!
(defn constructor []
{:a (ref {:initial "awesome test!"})
:b (atom 0)})
(deftest test-op1
(let [state (constructor)]
(is (= ... (op1 state)))))
and reload! :)
Realoded workflow
Also wrong - global state
(def ^:dynamic *resource*)
(defn- internal-op1 []
... *resource* ...)
(defn op1 [arg]
(internal-op1 ...))
assumptions:
- only one resource at the time
- working on one thread
Realoded workflow
But... but... what about my db connection?!
(defn init! []
(connect-to-database!)
(create-thread-pools!)
(start-background-processes!)
(start-web-server!))
Realoded workflow
Constructor
;; In src/com/example/my_project/system.clj
(ns com.example.my-project.system)
(defn system
"Returns a new instance of the whole application."
[]
...)
{:db {:uri "datomic:mem://dev"}
:scheduler #<ScheduledThreadPoolExecutorService ...>
:cache #<Atom {}>
:handler #<Fn ...>
:server #<Jetty ...>}
Realoded workflow
Different constructors
(defrecord System
[storage config web-service])
(defn dev-system []
(->System (mem-store)
(local-config {:a 1 :b 2})
(mock-web-service)))
(defn prod-system []
(let [config (zookeeper-config)
storage (sql-store config)
service (web-srv config storage)]
(->System storage config service)))
Realoded workflow
start and stop
;; In src/com/example/my_project/system.clj
(defn start
"Performs side effects to initialize the system, acquire resources,
and start it running. Returns an updated instance of the system."
[system]
...)
(defn stop
"Performs side effects to shut down the system and release its
resources. Returns an updated instance of the system."
[system]
...)
Realoded workflow
dev/user.clj and demo
Links
- Cursive: https://cursiveclojure.com/eap.html
- C. Fleming on Cursive: https://www.youtube.com/watch?v=vt1y2FbWQMg
- Stuart Sierra's reloaded workflow article: http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded
- Stuart Sierra's talk: http://www.infoq.com/presentations/Clojure-Large-scale-patterns-techniques
IntelliJ + Cursive
By Karol Andrusieczko
IntelliJ + Cursive
- 2,226