Taming the wild fronteer
Adventures in Clojurescript
by John Stevenson
@jr0cket practicalli.github.io/clojurescript
@jr0cket
Speaker, author, conference organiser
& community obsessed developer.
Loves Clojure, Spacemacs, Cats, Cycling & Agile development.
@Heroku
@SalesforceDevs
In a galaxy far, far away…
Taming The Wild Fronteer
Javascript is a highly pervasive platform...
Javascript as a platform is everywhere
@jr0cket
Many programming
languages have
their quirks…
@jr0cket
www.destroyallsoftware.com/talks/wat
A common view of Javascript as a language
@jr0cket
Complex languages
… are not easily
reasoned about by
humans
@jr0cket
Josh Smith - Tweet
Original Gif
ClojureScript
A general purpose language made from decades of design
From Javascript to Clojurescript
f(x) -> (f x)
;; First element of a list is a function call
var foo = “bar” -> (def foo “bar”)
;; bind a name to a value or function
@jr0cket
Clojurescript - basic syntax
(ns clojure.awesome ) ;; define a namespace (scoping)
(defn function-name [args] (behaviour)) ;; define a function, with arguments
(function-name data) ;; call a function with the data as its argument
(def name “data-or-value”) ;; bind a name to data within the namespace scope
(let [name “data-or-value”]) ;; bind a name to a data within the let scope (local)
:keyword-name ;; a keyword is a name (symbol) that points to itself
;; Chaining functions: Thread the result of the first fn into the argument of the next fn
(-> (function-a “data”)
(function-b ,,,) ;; In Clojure commas , are whitespace
(function-c ,,, “data”))
Built-in immutable data structures
Model state and any other data with built-in (hash) maps,
vectors (arrays), (linked) lists, (unique) sets
(list 1 2 3 4 5) ‘(“fish” “chips” 42)
(vec ‘(1 2 3 4)) [1 2 3 4]
{:key “value”} {:name “John” :skill “conferencing”}
(set ‘(1 2 3 4 4)) #{1 2 3 4}
Clojure - a few core functions
(map fn collection) ;; map a fn over a collection, return new collection
(reduce fn collection) ;; return the value of combining elements in collection with fn
(for [x collection] (fn x)) ;; iterate over the elements of a collection
(filter fn collection) ;; return a collection of values that comply with the filter fn
(get {:veg “kale” :fruit “kiwi”} :fruit) ;; return value pointed to by keyword
(:fruit {:veg “kale” :fruit “kiwi”}) ;; return value pointed to by keyword
(conj collection value) ;; conjoin a value to the collection
(assoc collection coll) ;; add a collection to the collection
(update {:a 1} :a fn) ;; update value pointed to by the key in a map with the fn
ClojureScript:
Managing complexity
A pragmatic approach to purity
The Complexity Iceberg
- @krisajenkins
● complexity is very
dangerous when hidden
● You can't know what a
function does for certain if it
has side effects
Side Effects
Pure Functions
The results of the function are purely determined by its initial output and its own code
- no external influence, a function only uses local values
- referential transparency (the function can be replaced by its value)
Impure Functions - side causes
Eliminating Side Effects
Functional programming is about eliminating side effects where you can,
controlling them where you can't - @krisajenkins
The features in Functional Programming come from a
desire to reduce side effects
Design idiom:
Composing
functions
together
You can think of functional
design as evaluating one or
more functions in series of
functions
The Map Reduce Sandwich
Clojure - the Map Reduce Sandwich
Clojure - the Map Reduce Sandwich
Pure Functions & Immutability = Parallelism
In simple terms: run the same code across multiple CPU’s / Threads
Parallelism - pmap
pmap - the same as map but in parallel
Parallelism - reduce
Significantly lower completion time running in parallel using Immutable data
structures
https://github.com/aphyr/tesser
Managing State
State changes should be managed easily
Safe State changes
Changing state safely by changing it atomically
● Software Transactional Memory (STM)
○ Gives an mechanism like an in-memory atomic database that manages mutable state changes
under the covers
● Atoms
● Refs
● core.async
Concurrency syntax - atoms
An online card game has players that can join and have their winnings tracked
Concurrency syntax - atoms
The join-game function adds players to the atom by their name, but only up to 2
players
Concurrency syntax - refs
join-game-safely adds players to ref & alters their account & game account
ClojureScript - Functional Web
Immutability & composable functions for Web Apps
See Clojurescript for Skeptics:
https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
jQuery over all JavaScript frameworks
See Clojurescript for Skeptics:
https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
See Clojurescript for Skeptics:
https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
Google Closure tools & libraries
See Clojurescript for Skeptics:
https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
Examples of Clojurescript
● Goya - pixel editor with
undo
https://jackschaedler.githu
b.io/goya/
● CircleCI
● Style.com
● Klipse - web-based dev tool
& library for live-code
examples in blogs /
workshops
Getting Started with
Clojurescript
Clojurescript Environments
Nashorn
- built into JVM, access Java classes
- Oracle Nashorn: A Next-Generation JavaScript Engine for the JVM
Browser-REPL
- built into modern browsers (Chrome, Firefox, etc)
- commonly used for client side web apps
Node.js
- great for command line utilities and microservices!
Common Clojurescript Tooling
Leiningen
- build automation tool for Clojure & Clojurescript
Figwheel (leiningen plugin)
- defacto tool for client side web apps
- live reload
- multi-broadcast (eg simultaneous dev & test outputs)
Full-stack projects: Chestnut
https://github.com/plexus/chestnut
- leiningen template for Clojure/ClojureScript apps based
- with Om, Reagent, or Rum
- instant reloading of Clojure, ClojureScript, and CSS
- browser-connected REPL included
lein new chestnut project-name
Self-hosted Clojurescript Environments
Instant startup times, great for command line tools
Lumo (cross-platform)
- https://github.com/anmonteiro/lumo
Plank (Mac & Linux)
- http://planck-repl.org/
Understanding React
Basic concepts of React
https://facebook.github.io/react/
https://github.com/reactjs
React Basics (conceptual)
React provides an efficient way to update the view
What React Provides
React is only the view
The view should update the state,
not the DOM
Reactive Frameworks
All the varieties of life, plus all the Javascript varieties too...
Javascript & Clojurescript frameworks
Javascript
● React.js via cljsjs
● Vue.js ???
Clojurescript
● Om / Om-next
● Reagent / Reframe
● Rum
More at https://clojurescript.org/community/libraries
React.js
Using React.js within Clojurescript
Simple Calculator with React.js
Reagent
Clojurescript can directly use the React.js library thanks to cljsjs.github.io
React.js
React.js
React.js
React.js
React.js
React.js
Om / Om-next
ClojureScript interface to Facebook's React
Om / Om-next
Models the React.js API
Rapidly re-render the UI from the root due via Immutable data structures
- UIs are snapshot-able and undoable without implementation complexity
Om supports features not currently present in React:
- Global state management facilities built in
- Components may have arbitrary data dependencies, not limited to props & state
- Component construction intercepted via :instrument. Simplifies debugging
- Stream all application state deltas via :tx-listen. Simplifies on/offline sync
- Customizable semantics
Om core functions
om.core/IRender
- Render a Om component into the DOM
- uses reify to provide a specific implementation of the om/IRender interface
om.core/IInitState
- maintains a local state (eg. for managing user input data)
om.core/IRenderState
- Render a Om component into the DOM
- renders component on change in local & global state
Om core functions
om.dom/div attributes content
- creates a <div> tag in react
- all react tags need to be wrapped in a div in order to be rendered
- om.dom/… has all the other tags too - h1, h2, p, a … (sablono can be used instead)
#js
- converts clojure maps into Javascript objects
- nest #js functions to to create JS objects - eg. for inline styles
Om Cursors
A cursor is an atom & a path to a location in the atom
app-state :schedule 0
Components use the cursor to refer to pieces of the app state
- without knowing where they are in the state tree
- updating app state is simple as the cursor is in the correct part of the app
state
Reagent
Interactive development
Reagent
Reagent provides a minimalistic interface between ClojureScript and React
- define efficient React components using nothing but plain ClojureScript
functions and data
- describe your UI using a Hiccup syntax
[:div [:h1 “Heading”]
[:div [:p “Paragraph” ]
[:a {:href “/link.html”} “link text”]]]
- define arbitrarily complex UIs using a couple of basic concepts
- fast enough by default that you rarely have to care about performance.
Reagent Core functions
reagent.core/render
- Render a Reagent component into the DOM
- First argument is either a vector (Reagent Hiccup syntax) or a React element
reagent.core/atom
- Like clojure.core/atom, plus it tracks components that deref atom & re-renders them
Helper functions
Reagent used Clojurescript functions for conversion from
- Clojure Maps to Javascript Objects
- Clojurescript vectors to Javascript arrays
clj->js
- convert from Clojurescript to Javascript
js->clj
- convert from Javascript to Clojurescript
Reagent Examples
http://timothypratley.blogspot.co.uk/2017/01/reagent-deep-dive-part-1.html
- Uses Klipse to display interactive code snippets for Reagent
- Includes use of SVG and Web3D libraries too
Graph example - http://leaderboardx.herokuapp.com/
Reframe
A micro-framework for Reagent
Re-frame
a pattern for writing SPAs in ClojureScript, using Reagent.
a framework with pure functions which transform data
Architecturally implements "a perpetual loop".
Build apps by writing pure functions for certain parts of
the loop that transform the data
- Re-frame looks after the conveyance of data around the
loop, into and out of the transforming functions you write
- tag line of "Derived Values, Flowing".
Rum
A micro-framework for Reagent
Rum
Rum is a client/server library for HTML UI. In ClojureScript, it works as React wrapper, in Clojure, it is a static HTML
generator.
- Simple semantics: Rum is arguably smaller, simpler and more straightforward than React itself.
- Decomplected: Rum is a library, not a framework. Use only the parts you need, throw away or replace what you don’t
need, combine different approaches in a single app, or even combine Rum with other frameworks.
- No enforced state model: Unlike Om, Reagent or Quiescent, Rum does not dictate where to keep your state. Instead, it
works well with any storage: persistent data structures, atoms, DataScript, JavaScript objects, localStorage or any custom
solution you can think of.
- Extensible: the API is stable and explicitly defined, including the API between Rum internals. It lets you build custom
behaviours that change components in significant ways.
- Minimal codebase: You can become a Rum expert just by reading its source code (~900 lines).
Rum - at ClojureX
https://skillsmatter.com/skillscasts/9149-modern-web-apps-with-rum
Other ClojureScript examples
Interactive development
Figwheel (flappy birds example)
Take a journey into Clojurescript
Clojurescript.org & ClojureDocs.org
londonclojurians.org
- 4 events per month
- Possibly the most active language-specific
developer communitie in London
Learning by teaching others
I really started thinking in Clojure when I started talking to & teaching others
- Coding dojos
- talks on Clojure (starting with the basics, showing the art of the possible)
- moving on to running conferences
- workshops at hack days
Thank you
@jr0cket
jr0cket.co.uk
slideshare.net/jr0cket
You unlock this door with
the key of imagination,
Beyond it is another
dimension
… a dimension of sound
Sound design of a language evolved over many
years
… a dimension of sight
REPL driven development showing you clearly
what your code is doing
… a dimension of mind
Thinking Functionally, of pure functions &
immutability
… of things and ideas
Merging of data structures & behaviour in one
syntax - homoiconicity
You have just crossed over to...
The Clojurescript Zone
The boundaries are only your imagination

Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

  • 1.
    Taming the wildfronteer Adventures in Clojurescript by John Stevenson @jr0cket practicalli.github.io/clojurescript
  • 2.
    @jr0cket Speaker, author, conferenceorganiser & community obsessed developer. Loves Clojure, Spacemacs, Cats, Cycling & Agile development. @Heroku @SalesforceDevs In a galaxy far, far away…
  • 3.
    Taming The WildFronteer Javascript is a highly pervasive platform...
  • 4.
    Javascript as aplatform is everywhere @jr0cket
  • 5.
    Many programming languages have theirquirks… @jr0cket www.destroyallsoftware.com/talks/wat
  • 6.
    A common viewof Javascript as a language @jr0cket
  • 7.
    Complex languages … arenot easily reasoned about by humans @jr0cket Josh Smith - Tweet Original Gif
  • 8.
    ClojureScript A general purposelanguage made from decades of design
  • 9.
    From Javascript toClojurescript f(x) -> (f x) ;; First element of a list is a function call var foo = “bar” -> (def foo “bar”) ;; bind a name to a value or function @jr0cket
  • 10.
    Clojurescript - basicsyntax (ns clojure.awesome ) ;; define a namespace (scoping) (defn function-name [args] (behaviour)) ;; define a function, with arguments (function-name data) ;; call a function with the data as its argument (def name “data-or-value”) ;; bind a name to data within the namespace scope (let [name “data-or-value”]) ;; bind a name to a data within the let scope (local) :keyword-name ;; a keyword is a name (symbol) that points to itself ;; Chaining functions: Thread the result of the first fn into the argument of the next fn (-> (function-a “data”) (function-b ,,,) ;; In Clojure commas , are whitespace (function-c ,,, “data”))
  • 11.
    Built-in immutable datastructures Model state and any other data with built-in (hash) maps, vectors (arrays), (linked) lists, (unique) sets (list 1 2 3 4 5) ‘(“fish” “chips” 42) (vec ‘(1 2 3 4)) [1 2 3 4] {:key “value”} {:name “John” :skill “conferencing”} (set ‘(1 2 3 4 4)) #{1 2 3 4}
  • 12.
    Clojure - afew core functions (map fn collection) ;; map a fn over a collection, return new collection (reduce fn collection) ;; return the value of combining elements in collection with fn (for [x collection] (fn x)) ;; iterate over the elements of a collection (filter fn collection) ;; return a collection of values that comply with the filter fn (get {:veg “kale” :fruit “kiwi”} :fruit) ;; return value pointed to by keyword (:fruit {:veg “kale” :fruit “kiwi”}) ;; return value pointed to by keyword (conj collection value) ;; conjoin a value to the collection (assoc collection coll) ;; add a collection to the collection (update {:a 1} :a fn) ;; update value pointed to by the key in a map with the fn
  • 13.
  • 14.
    The Complexity Iceberg -@krisajenkins ● complexity is very dangerous when hidden ● You can't know what a function does for certain if it has side effects
  • 15.
  • 16.
    Pure Functions The resultsof the function are purely determined by its initial output and its own code - no external influence, a function only uses local values - referential transparency (the function can be replaced by its value)
  • 17.
    Impure Functions -side causes
  • 18.
    Eliminating Side Effects Functionalprogramming is about eliminating side effects where you can, controlling them where you can't - @krisajenkins The features in Functional Programming come from a desire to reduce side effects
  • 19.
    Design idiom: Composing functions together You canthink of functional design as evaluating one or more functions in series of functions
  • 20.
  • 21.
    Clojure - theMap Reduce Sandwich
  • 22.
    Clojure - theMap Reduce Sandwich
  • 23.
    Pure Functions &Immutability = Parallelism In simple terms: run the same code across multiple CPU’s / Threads
  • 24.
    Parallelism - pmap pmap- the same as map but in parallel
  • 25.
    Parallelism - reduce Significantlylower completion time running in parallel using Immutable data structures https://github.com/aphyr/tesser
  • 26.
    Managing State State changesshould be managed easily
  • 27.
    Safe State changes Changingstate safely by changing it atomically ● Software Transactional Memory (STM) ○ Gives an mechanism like an in-memory atomic database that manages mutable state changes under the covers ● Atoms ● Refs ● core.async
  • 28.
    Concurrency syntax -atoms An online card game has players that can join and have their winnings tracked
  • 29.
    Concurrency syntax -atoms The join-game function adds players to the atom by their name, but only up to 2 players
  • 30.
    Concurrency syntax -refs join-game-safely adds players to ref & alters their account & game account
  • 31.
    ClojureScript - FunctionalWeb Immutability & composable functions for Web Apps
  • 32.
    See Clojurescript forSkeptics: https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
  • 34.
    jQuery over allJavaScript frameworks See Clojurescript for Skeptics: https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
  • 35.
    See Clojurescript forSkeptics: https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
  • 36.
  • 37.
    See Clojurescript forSkeptics: https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
  • 39.
    Examples of Clojurescript ●Goya - pixel editor with undo https://jackschaedler.githu b.io/goya/ ● CircleCI ● Style.com ● Klipse - web-based dev tool & library for live-code examples in blogs / workshops
  • 40.
  • 41.
    Clojurescript Environments Nashorn - builtinto JVM, access Java classes - Oracle Nashorn: A Next-Generation JavaScript Engine for the JVM Browser-REPL - built into modern browsers (Chrome, Firefox, etc) - commonly used for client side web apps Node.js - great for command line utilities and microservices!
  • 42.
    Common Clojurescript Tooling Leiningen -build automation tool for Clojure & Clojurescript Figwheel (leiningen plugin) - defacto tool for client side web apps - live reload - multi-broadcast (eg simultaneous dev & test outputs)
  • 43.
    Full-stack projects: Chestnut https://github.com/plexus/chestnut -leiningen template for Clojure/ClojureScript apps based - with Om, Reagent, or Rum - instant reloading of Clojure, ClojureScript, and CSS - browser-connected REPL included lein new chestnut project-name
  • 44.
    Self-hosted Clojurescript Environments Instantstartup times, great for command line tools Lumo (cross-platform) - https://github.com/anmonteiro/lumo Plank (Mac & Linux) - http://planck-repl.org/
  • 45.
  • 46.
  • 47.
    React Basics (conceptual) Reactprovides an efficient way to update the view
  • 48.
    What React Provides Reactis only the view The view should update the state, not the DOM
  • 49.
    Reactive Frameworks All thevarieties of life, plus all the Javascript varieties too...
  • 50.
    Javascript & Clojurescriptframeworks Javascript ● React.js via cljsjs ● Vue.js ??? Clojurescript ● Om / Om-next ● Reagent / Reframe ● Rum More at https://clojurescript.org/community/libraries
  • 51.
  • 52.
  • 53.
    Reagent Clojurescript can directlyuse the React.js library thanks to cljsjs.github.io
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
    Om / Om-next ClojureScriptinterface to Facebook's React
  • 61.
    Om / Om-next Modelsthe React.js API Rapidly re-render the UI from the root due via Immutable data structures - UIs are snapshot-able and undoable without implementation complexity Om supports features not currently present in React: - Global state management facilities built in - Components may have arbitrary data dependencies, not limited to props & state - Component construction intercepted via :instrument. Simplifies debugging - Stream all application state deltas via :tx-listen. Simplifies on/offline sync - Customizable semantics
  • 62.
    Om core functions om.core/IRender -Render a Om component into the DOM - uses reify to provide a specific implementation of the om/IRender interface om.core/IInitState - maintains a local state (eg. for managing user input data) om.core/IRenderState - Render a Om component into the DOM - renders component on change in local & global state
  • 63.
    Om core functions om.dom/divattributes content - creates a <div> tag in react - all react tags need to be wrapped in a div in order to be rendered - om.dom/… has all the other tags too - h1, h2, p, a … (sablono can be used instead) #js - converts clojure maps into Javascript objects - nest #js functions to to create JS objects - eg. for inline styles
  • 64.
    Om Cursors A cursoris an atom & a path to a location in the atom app-state :schedule 0 Components use the cursor to refer to pieces of the app state - without knowing where they are in the state tree - updating app state is simple as the cursor is in the correct part of the app state
  • 66.
  • 68.
    Reagent Reagent provides aminimalistic interface between ClojureScript and React - define efficient React components using nothing but plain ClojureScript functions and data - describe your UI using a Hiccup syntax [:div [:h1 “Heading”] [:div [:p “Paragraph” ] [:a {:href “/link.html”} “link text”]]] - define arbitrarily complex UIs using a couple of basic concepts - fast enough by default that you rarely have to care about performance.
  • 69.
    Reagent Core functions reagent.core/render -Render a Reagent component into the DOM - First argument is either a vector (Reagent Hiccup syntax) or a React element reagent.core/atom - Like clojure.core/atom, plus it tracks components that deref atom & re-renders them
  • 70.
    Helper functions Reagent usedClojurescript functions for conversion from - Clojure Maps to Javascript Objects - Clojurescript vectors to Javascript arrays clj->js - convert from Clojurescript to Javascript js->clj - convert from Javascript to Clojurescript
  • 71.
    Reagent Examples http://timothypratley.blogspot.co.uk/2017/01/reagent-deep-dive-part-1.html - UsesKlipse to display interactive code snippets for Reagent - Includes use of SVG and Web3D libraries too Graph example - http://leaderboardx.herokuapp.com/
  • 73.
  • 74.
    Re-frame a pattern forwriting SPAs in ClojureScript, using Reagent. a framework with pure functions which transform data Architecturally implements "a perpetual loop". Build apps by writing pure functions for certain parts of the loop that transform the data - Re-frame looks after the conveyance of data around the loop, into and out of the transforming functions you write - tag line of "Derived Values, Flowing".
  • 75.
  • 76.
    Rum Rum is aclient/server library for HTML UI. In ClojureScript, it works as React wrapper, in Clojure, it is a static HTML generator. - Simple semantics: Rum is arguably smaller, simpler and more straightforward than React itself. - Decomplected: Rum is a library, not a framework. Use only the parts you need, throw away or replace what you don’t need, combine different approaches in a single app, or even combine Rum with other frameworks. - No enforced state model: Unlike Om, Reagent or Quiescent, Rum does not dictate where to keep your state. Instead, it works well with any storage: persistent data structures, atoms, DataScript, JavaScript objects, localStorage or any custom solution you can think of. - Extensible: the API is stable and explicitly defined, including the API between Rum internals. It lets you build custom behaviours that change components in significant ways. - Minimal codebase: You can become a Rum expert just by reading its source code (~900 lines).
  • 77.
    Rum - atClojureX https://skillsmatter.com/skillscasts/9149-modern-web-apps-with-rum
  • 78.
  • 79.
  • 80.
    Take a journeyinto Clojurescript
  • 81.
  • 83.
    londonclojurians.org - 4 eventsper month - Possibly the most active language-specific developer communitie in London
  • 84.
    Learning by teachingothers I really started thinking in Clojure when I started talking to & teaching others - Coding dojos - talks on Clojure (starting with the basics, showing the art of the possible) - moving on to running conferences - workshops at hack days
  • 85.
  • 86.
    You unlock thisdoor with the key of imagination, Beyond it is another dimension
  • 87.
    … a dimensionof sound Sound design of a language evolved over many years
  • 88.
    … a dimensionof sight REPL driven development showing you clearly what your code is doing
  • 89.
    … a dimensionof mind Thinking Functionally, of pure functions & immutability
  • 90.
    … of thingsand ideas Merging of data structures & behaviour in one syntax - homoiconicity
  • 91.
    You have justcrossed over to... The Clojurescript Zone The boundaries are only your imagination