Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

91
Taming the wild fronteer Adventures in Clojurescript by John Stevenson @jr0cket practicalli.github.io/clojurescript

Transcript of Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Page 1: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Taming the wild fronteerAdventures in Clojurescript

by John Stevenson @jr0cket practicalli.github.io/clojurescript

Page 2: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

@jr0cketSpeaker, author, conference organiser

& community obsessed developer.

Loves Clojure, Spacemacs, Cats, Cycling & Agile development.

@Heroku@SalesforceDevs

In a galaxy far, far away…

Page 3: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Taming The Wild FronteerJavascript is a highly pervasive platform...

Page 4: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Javascript as a platform is everywhere

@jr0cket

Page 5: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Many programming languages have their quirks…

@jr0cket

www.destroyallsoftware.com/talks/wat

Page 6: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

A common view of Javascript as a language

@jr0cket

Page 8: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

ClojureScriptA general purpose language made from decades of design

Page 9: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 10: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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”))

Page 11: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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}

Page 12: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 13: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

ClojureScript:Managing complexityA pragmatic approach to purity

Page 14: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 15: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Side Effects

Page 16: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Pure FunctionsThe 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)

Page 17: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Impure Functions - side causes

Page 18: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 19: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Design idiom:Composing functions together

You can think of functional design as evaluating one or more functions in series of functions

Page 20: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

The Map Reduce Sandwich

Page 21: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Clojure - the Map Reduce Sandwich

Page 22: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Clojure - the Map Reduce Sandwich

Page 23: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Pure Functions & Immutability = ParallelismIn simple terms: run the same code across multiple CPU’s / Threads

Page 24: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Parallelism - pmappmap - the same as map but in parallel

Page 25: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Parallelism - reduceSignificantly lower completion time running in parallel using Immutable data structures

https://github.com/aphyr/tesser

Page 26: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Managing StateState changes should be managed easily

Page 27: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 28: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Concurrency syntax - atoms

An online card game has players that can join and have their winnings tracked

Page 29: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Concurrency syntax - atoms

The join-game function adds players to the atom by their name, but only up to 2 players

Page 30: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Concurrency syntax - refsjoin-game-safely adds players to ref & alters their account & game account

Page 31: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

ClojureScript - Functional WebImmutability & composable functions for Web Apps

Page 32: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

See Clojurescript for Skeptics: https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s

Page 33: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Page 34: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

jQuery over all JavaScript frameworks

See Clojurescript for Skeptics: https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s

Page 35: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

See Clojurescript for Skeptics: https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s

Page 36: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Google Closure tools & libraries

Page 37: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

See Clojurescript for Skeptics: https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s

Page 38: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Page 39: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Examples of Clojurescript

● Goya - pixel editor with undo https://jackschaedler.github.io/goya/

● CircleCI● Style.com● Klipse - web-based dev tool

& library for live-code examples in blogs / workshops

Page 40: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Getting Started with Clojurescript

Page 41: Progscon 2017: Taming the wild fronteer - Adventures in 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!

Page 42: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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)

Page 43: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 44: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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/

Page 45: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Understanding ReactBasic concepts of React

Page 47: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

React Basics (conceptual)

React provides an efficient way to update the view

Page 48: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

What React Provides

React is only the view

The view should update the state,not the DOM

Page 49: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Reactive FrameworksAll the varieties of life, plus all the Javascript varieties too...

Page 50: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Javascript & Clojurescript frameworks

Javascript

● React.js via cljsjs● Vue.js ???

Clojurescript

● Om / Om-next● Reagent / Reframe● Rum

More at https://clojurescript.org/community/libraries

Page 51: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

React.jsUsing React.js within Clojurescript

Page 52: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Simple Calculator with React.js

Page 53: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Reagent

Clojurescript can directly use the React.js library thanks to cljsjs.github.io

Page 54: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

React.js

Page 55: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

React.js

Page 56: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

React.js

Page 57: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

React.js

Page 58: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

React.js

Page 59: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

React.js

Page 60: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Om / Om-nextClojureScript interface to Facebook's React

Page 61: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Om / Om-nextModels 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

Page 62: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 63: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 64: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 65: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Page 66: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

ReagentInteractive development

Page 67: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Page 68: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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.

Page 69: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 70: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 71: Progscon 2017: Taming the wild fronteer - Adventures in 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/

Page 72: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Page 73: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

ReframeA micro-framework for Reagent

Page 74: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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".

Page 75: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

RumA micro-framework for Reagent

Page 76: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

RumRum 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).

Page 77: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Rum - at ClojureX

https://skillsmatter.com/skillscasts/9149-modern-web-apps-with-rum

Page 78: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Other ClojureScript examplesInteractive development

Page 79: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Figwheel (flappy birds example)

Page 80: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Take a journey into Clojurescript

Page 81: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Clojurescript.org & ClojureDocs.org

Page 82: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Page 83: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

londonclojurians.org

- 4 events per month- Possibly the most active language-specific

developer communitie in London

Page 84: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

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

Page 85: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

Thank you

@jr0cketjr0cket.co.uk

slideshare.net/jr0cket

Page 86: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

You unlock this door with

the key of imagination,

Beyond it is another

dimension

Page 87: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

… a dimension of sound

Sound design of a language evolved over many

years

Page 88: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

… a dimension of sight

REPL driven development showing you clearly

what your code is doing

Page 89: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

… a dimension of mind

Thinking Functionally, of pure functions &

immutability

Page 90: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

… of things and ideas

Merging of data structures & behaviour in one

syntax - homoiconicity

Page 91: Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript

You have just crossed over to...

The Clojurescript Zone

The boundaries are only your imagination