REACTIVE APPLICATIONS
WITH OM
PIERRE-YVES RITSCHARD
@PYR
WEBMARDI
Slide 2
Slide 2 text
@PYR
CTO at exoscale, swiss cloud hosting
Open source developer: pithos, cyanite, riemann, collectd,
cloudstack
Cassandra MVP
Slide 3
Slide 3 text
AIM OF THIS TALK
An introduction to clojure & clojurescript
Show-casing a different method of building SPAs
Slide 4
Slide 4 text
OUTLINE
What is Om ?
Clojure(script) whirlwind tour
Better views with React
An Om walkthrough
Slide 5
Slide 5 text
OM
Slide 6
Slide 6 text
WHAT IT SAYS ON THE BOX
A ClojureScript interface to Facebook's React.
https://github.com/omcljs/om
Slide 7
Slide 7 text
OM SPECIFICS
Small facade (< 2kLoC) for React
No two-way binding!
Data-based approach to UI
Promotes immutability
Interacts well with concurrency routines
Slide 8
Slide 8 text
OM IN THE LARGE
Circle CI
Prismatic
Percursor
Goya
Slide 9
Slide 9 text
OM AT EXOSCALE
Warp
Internal tools
Our portal is still Angular.JS
Slide 10
Slide 10 text
BETTER VIEWS WITH REACT
Slide 11
Slide 11 text
WHAT IT SAYS ON THE BOX
A JavaScript library for building user interfaces
https://facebook.github.io/react
Slide 12
Slide 12 text
JUST THE UI
React takes care of the view and does not care about the rest of
the application structure. As a library it integrates well with other
projects, such as Backbone.
Slide 13
Slide 13 text
VIRTUAL DOM
Multiple buffering approach for the DOM. Changes are
produced on a virtual DOM, differences are produced to the
actual DOM in a single step.
Slide 14
Slide 14 text
DATA FLOW
Departure from two-way binding. Easier to reason about. Say
goodbye to d
i
g
e
s
t a
l
r
e
a
d
y i
n p
r
o
g
r
e
s
s
.
Slide 15
Slide 15 text
A COMPONENT BASED APPROACH
Each component is responsible for a subset of the DOM and may
implement functions which correspond to elements of the
component's lifecycle:
render (or renderState)
willMount
didMount
willUnmount
didUnmount
Slide 16
Slide 16 text
THE PROBLEM WITH REACT
r
e
n
d
e
r
: f
u
n
c
t
i
o
n (
) {
r
e
t
u
r
n (
<
d
i
v
>
<
h
3
>
T
O
D
O
<
/
h
3
>
<
T
o
d
o
L
i
s
t i
t
e
m
s
=
{
t
h
i
s
.
s
t
a
t
e
.
i
t
e
m
s
} /
>
<
f
o
r
m o
n
S
u
b
m
i
t
=
{
t
h
i
s
.
h
a
n
d
l
e
S
u
b
m
i
t
}
>
<
i
n
p
u
t o
n
C
h
a
n
g
e
=
{
t
h
i
s
.
o
n
C
h
a
n
g
e
} v
a
l
u
e
=
{
t
h
i
s
.
s
t
a
t
e
.
t
e
x
t
} /
>
<
b
u
t
t
o
n
>
{
'
A
d
d #
' + (
t
h
i
s
.
s
t
a
t
e
.
i
t
e
m
s
.
l
e
n
g
t
h + 1
)
}
<
/
b
u
t
t
o
n
>
<
/
f
o
r
m
>
<
/
d
i
v
>
)
;
}
Slide 17
Slide 17 text
CLOJURE(SCRIPT): A WHIRLWIND TOUR
Slide 18
Slide 18 text
WHAT IT SAYS ON THE BOX
Clojure is a dynamic programming language that
targets the Java Virtual Machine (and the CLR,
and JavaScript).
http://clojure.org
Slide 19
Slide 19 text
CLOJURE SPECIFICS
Dynamically typed LISP
Homo-iconic
Macros
Functional programming language
Immutable data structures & STM
Runtime polymorphism
Host independant
Slide 20
Slide 20 text
CLOJURE LIBRARIES & TOOLING
Typing
Pattern-matching
Concurrency routines
Building and running
Slide 21
Slide 21 text
DYNAMICALLY TYPED LISP
(
+ 1 2
) ;
; =
> 3
(
g
e
t {
:
f
o
o "
b
a
r
"
} :
f
o
o
) ;
; =
> "
b
a
r
"
(
c
o
u
n
t [
:
a :
b :
c :
d
]
) ;
; =
> 4
(
l
e
t [
n 4
]
(
* n n
)
) ;
; =
> 1
6
Slide 22
Slide 22 text
DYNAMICALLY TYPED LISP: VARIABLES
(
d
e
f m
y
-
v
a
r "
h
e
l
l
o
"
) ;
; =
> #
'
m
y
-
v
a
r
(
d
e
f
n f
a
c
t
o [
n
]
(
r
e
d
u
c
e * (
m
a
p i
n
c (
r
a
n
g
e n
)
)
)
) ;
; =
> #
'
f
a
c
t
o
Slide 23
Slide 23 text
DYNAMICALLY TYPED LISP: LOOPS AND CONDITIONALS
(
i
f c
o
n
d
i
t
i
o
n
?
t
r
u
e
-
f
o
r
m
f
a
l
s
e
-
f
o
r
m
)
(
w
h
e
n c
o
n
d
i
t
i
o
n
?
t
r
u
e
-
f
o
r
m
1
t
r
u
e
-
f
o
r
m
2
)
(
d
o
s
e
q [
i (
r
a
n
g
e 1
0
)
]
(
p
r
i
n
t
l
n i
)
)
0
Slide 24
Slide 24 text
HOMO ICONIC
;
; k
e
y
w
o
r
d
s
:
f
i
r
s
t
-
n
a
m
e
;
; m
a
p
s
{
:
u
s
e
r "
p
y
r
"
:
f
i
r
s
t
-
n
a
m
e "
P
i
e
r
r
e
-
Y
v
e
s
"
:
l
a
s
t
-
n
a
m
e "
R
i
t
s
c
h
a
r
d
"
}
;
; v
e
c
t
o
r
s
[
0 1 2 :
f
o
o 3 4 :
b
a
r
]
;
; s
e
t
s
#
{
:
e
g
g
p
l
a
n
t :
z
u
c
c
h
i
n
i :
p
o
t
a
t
o :
c
a
r
o
t
}
;
; f
u
n
c
t
i
o
n
s
#
(
+ % 1
)
;
; r
e
g
e
x
#
"
^
m
y n
a
m
e i
s (
.
*
)
$
"
Slide 25
Slide 25 text
MACROS
(
d
e
f
m
a
c
r
o u
n
l
e
s
s [
e
x
p & b
o
d
y
]
(
i
f
-
n
o
t ~
e
x
p (
d
o ~
@
b
o
d
y
)
)
)
(
u
n
l
e
s
s s
o
m
e
-
c
o
n
d
i
t
i
o
n
d
o
-
t
h
i
s
d
o
-
t
h
a
t
)
Slide 26
Slide 26 text
MACROS
(
d
e
f
n f
a
c
t
o [
n
]
(
-
>
> (
r
a
n
g
e 1
0
)
(
m
a
p i
n
c
)
(
r
e
d
u
c
e *
)
)
)
Slide 27
Slide 27 text
DESTRUCTURING
(
d
e
f u
s
e
r
{
:
u
s
e
r "
p
y
r
"
:
f
i
r
s
t
-
n
a
m
e "
P
i
e
r
r
e
-
Y
v
e
s
"
:
l
a
s
t
-
n
a
m
e "
R
i
t
s
c
h
a
r
d
"
}
)
(
l
e
t [
{
:
k
e
y
s [
f
i
r
s
t
-
n
a
m
e l
a
s
t
-
n
a
m
e
]
} u
s
e
r
]
(
p
r
i
n
t
l
n "
H
e
l
l
o
" f
i
r
s
t
-
n
a
m
e l
a
s
t
-
n
a
m
e
)
)
Slide 28
Slide 28 text
FUNCTIONAL PROGRAMMING
It is better to have 100 functions operate on one
data structure than 10 functions on 10 data
structures.
—Alan Perlis
(
-
> {
:
u
s
e
r "
p
y
r
"
:
h
i
s
t
o
r
y [
]
:
s
t
a
t
s {
:
s
e
s
s
i
o
n
-
c
o
u
n
t 0
:
l
o
g
g
e
d
-
i
n f
a
l
s
e
}
}
(
a
s
s
o
c
-
i
n [
:
s
t
a
t
s :
l
o
g
g
e
d
-
i
n
] t
r
u
e
)
(
u
p
d
a
t
e
-
i
n [
:
s
t
a
t
s :
s
e
s
s
i
o
n
-
c
o
u
n
t
] i
n
c
)
(
u
p
d
a
t
e
-
i
n [
:
h
i
s
t
o
r
y
] c
o
n
j {
:
a
c
t
i
o
n :
l
o
g
-
i
n :
u
s
e
r :
p
y
r
}
)
)
Slide 29
Slide 29 text
FUNCTIONAL PROGRAMMING (CONT.)
much better than underscore.js
;
; c
o
m
p
o
s
i
t
i
o
n
(
c
o
m
p n
a
m
e k
e
y
)
(
m
a
p (
c
o
m
p n
a
m
e k
e
y
) {
:
a
c
t
i
o
n :
l
o
g
-
i
n :
u
s
e
r "
p
y
r
"
}
) ;
; =
> [
"
a
c
t
i
o
n
" "
u
s
e
r
"
]
;
; p
a
r
t
i
a
l a
p
p
l
i
c
a
t
i
o
n / c
u
r
r
y
i
n
g
(
d
e
f m
y
-
i
n
c (
p
a
r
t
i
a
l + 1
)
)
;
; c
l
o
s
u
r
e
s
(
d
e
f
n i
n
c
r
e
m
e
n
t
-
b
y [
n
]
(
f
n [
x
]
(
+ n x
)
)
)
(
m
a
p (
i
n
c
r
e
m
e
n
t
-
b
y 3
) (
r
a
n
g
e 3
)
) ;
; =
> [
3 4 5
]
Slide 30
Slide 30 text
IMMUTABLE DATASTRUCTURES
(
d
e
f u
s
e
r
-
d
a
t
a
{
:
u
s
e
r "
p
y
r
"
:
s
t
a
t
s {
:
s
e
s
s
i
o
n
-
c
o
u
n
t 0
}
}
)
(
d
e
f
n r
e
c
o
r
d
-
s
e
s
s
i
o
n
[
u
d
]
(
u
p
d
a
t
e
-
i
n u
d [
:
s
t
a
t
s :
s
e
s
s
i
o
n
-
c
o
u
n
t
] i
n
c
)
)
(
r
e
c
o
r
d
-
s
e
s
s
i
o
n u
s
e
r
-
d
a
t
a
) ;
; =
> {
:
u
s
e
r "
p
y
r
" :
s
t
a
t
s {
:
s
e
s
s
i
o
n
-
c
o
u
n
t 1
}
}
u
s
e
r
-
d
a
t
a ;
; =
> {
:
u
s
e
r "
p
y
r
" :
s
t
a
t
s {
:
s
e
s
s
i
o
n
-
c
o
u
n
t 0
}
}
Slide 31
Slide 31 text
STM
(
d
e
f u
s
e
r
-
d
a
t
a
(
a
t
o
m {
:
u
s
e
r "
p
y
r
"
:
s
t
a
t
s {
:
s
e
s
s
i
o
n
-
c
o
u
n
t 0
}
}
)
)
(
d
e
f
n r
e
c
o
r
d
-
s
e
s
s
i
o
n
[
u
d
]
(
u
p
d
a
t
e
-
i
n u
d [
:
s
t
a
t
s :
s
e
s
s
i
o
n
-
c
o
u
n
t
] i
n
c
)
)
(
s
w
a
p
! u
s
e
r
-
d
a
t
a r
e
c
o
r
d
-
s
e
s
s
i
o
n
) ;
; =
> {
:
u
s
e
r "
p
y
r
"
;
; :
s
t
a
t
s {
:
s
e
s
s
i
o
n
-
c
o
u
n
t 1
}
}
@
u
s
e
r
-
d
a
t
a ;
; =
> {
:
u
s
e
r "
p
y
r
"
;
; :
s
t
a
t
s {
:
s
e
s
s
i
o
n
-
c
o
u
n
t 1
}
}
Slide 32
Slide 32 text
RUNTIME POLYMORPHISM: MULTIMETHODS
(
d
e
f
m
u
l
t
i h
a
n
d
l
e
-
e
v
e
n
t :
a
c
t
i
o
n
)
(
d
e
f
m
e
t
h
o
d h
a
n
d
l
e
-
e
v
e
n
t :
l
o
g
-
i
n
[
{
:
k
e
y
s [
u
s
e
r
]
}
]
(
p
r
i
n
t
l
n "
u
s
e
r
" u
s
e
r "
h
a
s l
o
g
g
e
d i
n
"
)
)
(
d
e
f
m
e
t
h
o
d h
a
n
d
l
e
-
e
v
e
n
t :
l
o
g
-
o
u
t
[
{
:
k
e
y
s [
u
s
e
r
]
}
]
(
p
r
i
n
t
l
n "
u
s
e
r
" u
s
e
r "
h
a
s l
o
g
g
e
d i
n
"
)
)
(
h
a
n
d
l
e
-
e
v
e
n
t {
:
a
c
t
i
o
n :
l
o
g
-
i
n :
u
s
e
r "
p
y
r
"
}
)
(
h
a
n
d
l
e
-
e
v
e
n
t {
:
a
c
t
i
o
n :
l
o
g
-
o
u
t :
u
s
e
r "
p
y
r
"
}
)
Slide 33
Slide 33 text
RUNTIME POLYMORPHISM: PROTOCOLS
(
d
e
f
p
r
o
t
o
c
o
l K
V
D
a
t
a
b
a
s
e
(
s
e
t
k
e
y
! [
t
h
i
s k v
]
)
(
g
e
t
k
e
y [
t
h
i
s k
]
)
)
(
d
e
f
n a
t
o
m
-
d
a
t
a
b
a
s
e
[
]
(
l
e
t [
d
b (
a
t
o
m {
}
)
]
(
r
e
i
f
y K
V
D
a
t
a
b
a
s
e
(
s
e
t
k
e
y
! [
t
h
i
s k v
]
(
s
w
a
p
! d
b a
s
s
o
c k v
)
)
(
g
e
t
k
e
y [
t
h
i
s k
]
(
g
e
t @
d
b k
)
)
)
)
)
Slide 34
Slide 34 text
NAMESPACES
(
n
s w
e
b
a
p
p
.
f
r
o
n
t
e
n
d
(
:
r
e
q
u
i
r
e [
o
m
.
d
o
m :
a
s d
o
m
]
[
s
a
b
l
o
n
o
.
c
o
r
e :
r
e
f
e
r
-
m
a
c
r
o
s [
h
t
m
l
]
]
)
)
Slide 35
Slide 35 text
HOST INDEPENDANT
JVM, CLR, Javascript (relies on Google Closure). Interop is a first
class citizen:
(
.
l
o
g j
s
/
w
i
n
d
o
w
.
c
o
n
s
o
l
e "
h
e
l
l
o
"
)
Slide 36
Slide 36 text
SIMPLE EXAMPLE: AN HTTP + JSON REQUEST:
(
n
s f
o
o
b
a
r
(
:
r
e
q
u
i
r
e [
a
j
a
x
.
c
o
r
e :
r
e
f
e
r [
G
E
T
]
]
)
)
(
d
e
f
n h
a
n
d
l
e
-
r
e
s
p
o
n
s
e
[
d
a
t
a
]
.
.
.
)
;
; A
u
t
o
m
a
t
i
c
a
l
l
y i
n
f
e
r
s f
o
r
m
a
t f
r
o
m C
o
n
t
e
n
t
-
T
y
p
e
(
G
E
T "
/
m
y
-
e
n
d
p
o
i
n
t
" {
:
h
a
n
d
l
e
r h
a
n
d
l
e
-
r
e
s
p
o
n
s
e
}
)
;
; H
i
n
t a
t f
o
r
m
a
t
(
P
U
T "
/
m
y
-
e
n
d
p
o
i
n
t
" {
:
p
a
r
a
m
s {
:
f
o
o "
b
a
r
"
} :
f
o
r
m
a
t :
j
s
o
n
}
)
Slide 37
Slide 37 text
CLOJURESCRIPT ESSENTIAL LIBS: CORE.ASYNC
(
n
s t
a
b
l
e
f
l
i
p
.
c
o
r
e
(
:
r
e
q
u
i
r
e
-
m
a
c
r
o
s [
c
l
j
s
.
c
o
r
e
.
a
s
y
n
c
.
m
a
c
r
o
s :
r
e
f
e
r [
g
o
]
]
)
(
:
r
e
q
u
i
r
e [
c
l
j
s
.
c
o
r
e
.
a
s
y
n
c :
r
e
f
e
r [
t
i
m
e
o
u
t <
!
]
]
)
)
(
g
o
(
l
o
o
p [
[
c
u
r & n
e
x
t
] (
c
y
c
l
e [
"
┬
─
┬
ノ( º _ º
ノ)
"
"
(
╯
°
□
°
)╯
︵ ┻
━
┻
"
"
(
╯
°
□
°
)╯ ┬
─
┬
"
"
(
╯
°
□
°
)╯ ┻
━
┻
"
"
(
╯
°
□
°
)╯ ┬
─
┬
"
"
(
╯
°
□
°
)╯ ┻
━
┻
"
]
)
]
(
.
r
e
p
l
a
c
e
S
t
a
t
e j
s
/
w
i
n
d
o
w
.
h
i
s
t
o
r
y #
j
s {
} "
" (
s
t
r "
/
#
" c
u
r
)
)
(
<
! (
t
i
m
e
o
u
t 1
0
0
0
)
)
(
r
e
c
u
r n
e
x
t
)
)
)
Slide 38
Slide 38 text
CLOJURESCRIPT ESSENTIAL LIBS: CORE.MATCH
(
d
o
s
e
q [
n (
r
a
n
g
e 1 1
0
1
)
]
(
p
r
i
n
t
l
n
(
m
a
t
c
h [
(
m
o
d n 3
) (
m
o
d n 5
)
]
[
0 0
] "
F
i
z
z
B
u
z
z
"
[
0 _
] "
F
i
z
z
"
[
_ 0
] "
B
u
z
z
"
:
e
l
s
e n
)
)
)
BUILDING CLOJURESCRIPT
Not bound to a specific build tool
People usually choose (upside: no grunt or gulp
debate)
leiningen
Slide 41
Slide 41 text
BUILDING CLOJURESCRIPT
(
d
e
f
p
r
o
j
e
c
t m
y
-
p
r
o
j
e
c
t "
0
.
1
.
0
"
:
d
e
p
e
n
d
e
n
c
i
e
s [
[
o
r
g
.
c
l
o
j
u
r
e
/
c
l
o
j
u
r
e "
1
.
6
.
0
"
]
[
o
r
g
.
c
l
o
j
u
r
e
/
c
l
o
j
u
r
e
s
c
r
i
p
t "
0
.
0
-
3
1
2
6
"
]
[
o
r
g
.
o
m
c
l
j
s
/
o
m "
0
.
8
.
8
"
]
:
p
l
u
g
i
n
s [
[
l
e
i
n
-
c
l
j
s
b
u
i
l
d "
1
.
0
.
5
"
]
]
:
c
l
j
s
b
u
i
l
d {
:
b
u
i
l
d
s [
{
:
i
d "
d
e
v
"
:
s
o
u
r
c
e
-
p
a
t
h
s [
"
s
r
c
"
]
:
c
o
m
p
i
l
e
r
{
:
m
a
i
n "
j
o
b
s
.
f
r
o
n
t
e
n
d
"
:
o
u
t
p
u
t
-
t
o "
r
e
s
o
u
r
c
e
s
/
p
u
b
l
i
c
/
j
s
/
a
p
p
.
j
s
"
:
o
u
t
p
u
t
-
d
i
r "
r
e
s
o
u
r
c
e
s
/
p
u
b
l
i
c
/
j
s
"
:
o
p
t
i
m
i
z
a
t
i
o
n
s :
n
o
n
e
:
s
o
u
r
c
e
-
m
a
p t
r
u
e
}
}
]
}
)
Slide 42
Slide 42 text
COMPILING AND RUNNING
l
e
i
n c
l
j
s
b
u
i
l
d o
n
c
e
l
e
i
n c
l
j
s
b
u
i
l
d a
u
t
o
Slide 43
Slide 43 text
OM WALKTHROUGH
Slide 44
Slide 44 text
BINDING CLOJURESCRIPT AND REACT
All application state is stored in an atom.
Changes in an atom result in UI updates
Binds to react through protocols
Slide 45
Slide 45 text
BINDING CLOJURESCRIPT AND REACT: PROTOCOLS
A component reifies: IRenderState or IRender
(
f
n [
a
p
p o
w
n
e
r
]
(
r
e
i
f
y
I
R
e
n
d
e
r
(
r
e
n
d
e
r [
t
h
i
s
]
(
d
o
m
/
h
1 "
h
e
l
l
o
"
)
)
)
)
Slide 46
Slide 46 text
OM APPLICATION BASICS
Applications are trees of components bound to a part of the
application state which generate nodes in the virtual dom.
Slide 47
Slide 47 text
OM APPLICATION BASICS
(
d
e
f a
p
p
-
s
t
a
t
e
(
a
t
o
m {
:
j
o
b
s [
{
:
t
i
t
l
e "
d
e
v
e
l
o
p
e
r
"
:
c
o
m
p
a
n
y "
r
a
i
l
s s
h
o
p
"
}
{
:
t
i
t
l
e "
s
y
s
a
d
m
i
n
"
:
c
o
m
p
a
n
y "
p
h
p s
h
o
p
"
}
]
}
)
)
(
d
e
f
c
o
m
p
o
n
e
n
t j
o
b
-
l
i
n
e [
p
o
s
i
t
i
o
n o
w
n
e
r
]
(
r
e
n
d
e
r [
t
h
i
s
]
(
l
e
t [
t
i
t
l
e (
:
t
i
t
l
e a
p
p
)
c
o
m
p
a
n
y (
:
c
o
m
p
a
n
y p
o
s
i
t
i
o
n
)
]
(
h
t
m
l
[
:
l
i (
s
t
r t
i
t
l
e " a
t " c
o
m
p
a
n
y
)
]
)
)
)
)
(
d
e
f
c
o
m
p
o
n
e
n
t j
o
b
-
l
i
s
t [
a
p
p o
w
n
e
r
]
(
r
e
n
d
e
r [
t
h
i
s
]
(
l
e
t [
j
o
b
s (
:
j
o
b
s a
p
p
)
]
(
h
t
m
l
[
:
u
l (
o
m
/
b
u
i
l
d
-
a
l
l j
o
b
-
l
i
n
e j
o
b
s
)
]
)
)
)
)
(
o
m
/
r
o
o
t j
o
b
-
l
i
s
t a
p
p
-
s
t
a
t
e
)
Slide 48
Slide 48 text
OM APPLICATION BASICS
Slide 49
Slide 49 text
ROUTING
There is no routing component in om.
It's easy to build one leveraging the application state
Example approach: https://github.com/pyr/om-
jobs/blob/master/src/jobs/router.cljs
;
; P
a
i
r
s o
f r
o
u
t
e t
o c
o
m
p
o
n
e
n
t
(
d
e
f r
o
u
t
e
s
[
"
/
" v
i
e
w
s
/
j
o
b
s
"
/
j
o
b
/
:
i
d
" v
i
e
w
s
/
j
o
b
"
/
p
o
s
t
" v
i
e
w
s
/
j
o
b
-
p
o
s
t
]
)
(
l
e
t [
r
o
u
t
e
r (
r
o
u
t
e
r
/
i
n
i
t r
o
u
t
e
s a
p
p
-
s
t
a
t
e
)
t
a
r
g
e
t {
:
t
a
r
g
e
t (
.
g
e
t
E
l
e
m
e
n
t
B
y
I
d j
s
/
d
o
c
u
m
e
n
t "
a
p
p
"
)
}
]
(
o
m
/
r
o
o
t r
o
u
t
e
r a
p
p
-
s
t
a
t
e t
a
r
g
e
t
)
)
Slide 50
Slide 50 text
USER INPUT
Two approaches:
Local component state
Circling back to the global app-state
Slide 51
Slide 51 text
USER INPUT: LOCAL COMPONENT STATE
(
d
e
f
c
o
m
p
o
n
e
n
t j
o
b
-
p
o
s
t
[
a
p
p o
w
n
e
r
]
(
r
e
n
d
e
r
-
s
t
a
t
e [
t
h
i
s s
t
a
t
e
]
(
l
e
t [
t
i
t
l
e (
:
t
i
t
l
e s
t
a
t
e
)
c
o
m
p
a
n
y (
:
c
o
m
p
a
n
y s
t
a
t
e
)
c
r
e
a
t
e
! (
:
c
r
e
a
t
e
! a
p
p
)
-
>
s
t
a
t
e (
f
n [
k
]
(
f
n [
e
v
e
n
t
]
(
o
m
/
s
e
t
-
s
t
a
t
e
! o
w
n
e
r [
k
]
(
-
> e
v
e
n
t .
-
t
a
r
g
e
t .
-
v
a
l
u
e
)
)
)
)
]
(
h
t
m
l
[
:
f
o
r
m
[
:
l
a
b
e
l "
t
i
t
l
e
"
]
[
:
i
n
p
u
t {
:
t
y
p
e "
t
e
x
t
"
:
v
a
l
u
e t
i
t
l
e
:
o
n
-
c
h
a
n
g
e (
-
>
s
t
a
t
e :
t
i
t
l
e
)
}
]
[
:
l
a
b
e
l "
c
o
m
p
a
n
y
"
]
[
:
i
n
p
u
t {
:
t
y
p
e "
t
e
x
t
"
:
v
a
l
u
e c
o
m
p
a
n
y
:
o
n
-
c
h
a
n
g
e (
-
>
s
t
a
t
e :
c
o
m
p
a
n
y
)
}
]
[
:
i
n
p
u
t {
:
t
y
p
e "
s
u
b
m
i
t
"
:
o
n
-
c
l
i
c
k (
f
n [
_
] (
c
r
e
a
t
e
! s
t
a
t
e
)
)
}
]
]
)
)
)
)
Slide 52
Slide 52 text
USER INPUT: GLOBAL STATE
(
d
e
f m
o
d
e
l
-
c
h
a
n (
c
h
a
n
)
)
(
g
o
(
l
o
o
p [
a
c
t
i
o
n (
<
! m
o
d
e
l
-
c
h
a
n
)
]
(
l
e
t [
t
y
p
e (
:
t
y
p
e a
c
t
i
o
n
)
i
d (
:
i
d a
c
t
i
o
n
)
]
(
c
o
n
d
p = t
y
p
e
:
d
e
l
e
t
e (
s
w
a
p
! a
p
p
-
s
t
a
t
e d
i
s
s
o
c i
d
)
:
c
r
e
a
t
e (
s
w
a
p
! a
p
p
-
s
t
a
t
e a
s
s
o
c i
d a
c
t
i
o
n
)
)
)
)
)
(
d
e
f
c
o
m
p
o
n
e
n
t j
o
b
-
l
i
n
e
[
a
p
p o
w
n
e
r
]
(
r
e
n
d
e
r [
t
h
i
s
]
[
:
l
i [
:
d
i
v [
:
p (
:
t
i
t
l
e a
p
p
) " a
t " (
:
c
o
m
p
a
n
y a
p
p
)
]
[
:
b
u
t
t
o
n {
:
o
n
-
c
l
i
c
k (
f
n [
_
] (
>
! m
o
d
e
l
-
c
h
a
n
{
:
t
y
p
e :
d
e
l
e
t
e
:
i
d (
:
i
d a
p
p
)
}
)
)
}
]
]
]
)
)
Slide 53
Slide 53 text
OM USE-CASES
Slide 54
Slide 54 text
COMPARED TO ANGULAR
More up-front work
Better reasoning around components
Not a fit for small CRUD apps
Slide 55
Slide 55 text
BEST FITS
Complex app logic
Websockets / SSE (event-stream)
Multiple presentation of a single source of data
Slide 56
Slide 56 text
WHAT WE DID NOT SAY
Infinite undo
Component mixins
Targets Node.JS
Targets JavascriptCore
HTML templates
Source maps
REPLs
Slide 57
Slide 57 text
GOING FURTHER
Om:
Angular to Om:
A simple job board:
https://github.com/omcljs/om
http://spootnik.org/entries/2014/10/26_from-angularjs-to-
om-a-walk-through.html
https://github.com/pyr/om-jobs