Elm is Coming

@krisajenkins

What's Hard?

Frontend Programming

  • Mirror the backend
  • plus Error-handling
  • plus Users
  • plus Marketing
  • plus Everyone else
  • plus Constantly in flux
  • plus Demands are on the rise

And…

Our tools suck.

Elm is…

  • Functional
  • A variant of Haskell
  • (Written in Haskell)
  • Compiles to JavaScript
  • Easy to learn
  • Structurally simple

Elm has…

  • Friendly static typing
  • Pure rendering
  • One-way data-flow
  • Immutable data
  • Pure functions
  • Control over side-effects

Elm also has..

  • Fast build tool
  • Package manager
  • Semver enforcement
  • And cool stuff

Overview of an Elm App

Two Datatypes, Two functions

Datatype 1: Model

type Model = Model
  {username : String
  ,password : String
  ,serverError : Maybe Http.Error}

Datatype 2: Action

type Action
  = ChangeUsername String
  | ChangePassword String
  | Submit
  | LoginResponse (Result Error AuthToken)

Function 1: Update

update : Action -> Model -> Model

Example

update : Action -> Model -> Model
update action model =
  case action of
    ...
    ChangeUsername s -> {model | username <- s}
    ...

But…

Sometimes we need to schedule future actions.

Function 1: Update (v2)

update : Action -> Model -> Model

…becomes:

update : Action -> Model -> (Model, Effects Action)

Example

update : Action -> Model -> (Model, Effects Action)
update action model =
  case action of
    ...
    Submit -> (model
              ,postForm "/login"
                        model.username
                        model.password)
    ...


postForm : ... -> Effects Action
postForm ... = LoginResponse ( ... )

Enhanced example

update : Action -> Model -> (Model, Effects Action)
update action model =
  case action of
    ...
    Submit -> ({model | loading <- True}
              ,postForm "/login"
                        model.username
                        model.password)
    ...

Function 2: Rendering

view : Model -> Html

Example

loginForm : Model -> Html
loginForm model =
  form []
       [input [type' "text"
              ,class "form-control"
              ,autofocus True]
              []
       [input [type' "password"
              ,class "form-control"]
              []
       ,button [class "btn btn-primary"
               ,type' "button"
               ,disabled (model.username == "" ||
                          model.password == "")]
               [text "Log In"]]

But…

An HTML UI is an event source.

Function 2: Rendering (v2)

view : Model -> Html

…becomes:

view : Address Action -> Model -> Html

Example

loginForm : Address Action -> Model -> Html
loginForm address model =
  form []
       [input [type' "text"
              ,class "form-control"
              ,onChange address Username
              ,autofocus True]
              []
       [input [type' "password"
              ,class "form-control"
              ,onChange address Password]
              []
       ,button [class "btn btn-primary"
               ,type' "button"
               ,disabled (model.username == "" ||
                          model.password == "")
               ,onClick address Submit]
               [text "Log In"]]

Elm Architecture

type Model

type Action

update : Action -> Model -> (Model, Effects Action)

view : Address Action -> Model -> Html

Simple Demo

Compare to MVC

Elm MVC
Model Model
Action -
View View
Update Controller

Huge Structural Difference

When It's Simple

M --- C --- V

MVC As It Grows

   M --- C --- V
              / \
             /   \
            /     \
           /       \
          /         \
         /           \
M - C - V     M - C - V
                     / \
                    /   \
                   /     \
                  /       \
                 /         \
                /           \
       M - C - V     M - C - V

Here's The Problem

Simple:

view : Address Action -> Model -> Html

Grows to

view : Address Action -> Model -> Everything

Here's The Solution

     M
    / \
   /   o
  m   / \
     m   m

     C
    / \
   /   o
  c   / \
     c   c

     V
    / \
   /   \
  v     v
         \
          \
           v

M --- C --- V

Demos

Parsing

Here's Some JSON

{
    spatialReference: {
        wkid: 4326,
        latestWkid: 4326
    },
    candidates: [
        {
            address: "Royal Festival Hall",
            location: {
                x: -0.11599726799954624,
                y: 51.50532882800047
            },
            score: 100,
            attributes: { },
            extent: {
                xmin: -0.120998,
                ymin: 51.500329,
                xmax: -0.110998,
                ymax: 51.510329
            }
        }
    ]
}

To Entypify The JSON

Define a Place

type alias Place =
  {address: String
  ,latitude: Float
  ,longitude: Float}

Decode the List of Places

decodePlaces : Decoder (List Candidate)
decodePlaces = "candidates" := (list decodePlace)

Decode one Place

decodePlace : Decoder Place
decodePlace =
  Place `map`   ("address" := string)
        `apply` (at ["location", "x"] float)
        `apply` (at ["location", "y"] float)

Done

Event-Tracking Analytics

Define an Analytics Event

type alias AnalyticsEvent =
  {category : String
  ,action : String}

Generate Actions

toAnalyticsEvent : Action -> Maybe AnalyticsEvent
toAnalyticsEvent action =
  case action of
    BuyProduct id           -> Just {category = "Buy",   action = "Product"}
    ShareProduct Twitter id -> Just {category = "Share", action = "Twitter"}
    ...
    _                       -> Nothing

Generate an Effect

toAnalyticsEffect : Action -> Effects Action
toAnalyticsEffect action =
  case toAnalyticsEvent action of
    Nothing -> none
    Just event -> sendEvent AnalyticsSent event

Augment Our Update Function

updateWithAnalytics : Action -> Model -> (Model, Effects Action)
updateWithAnalytics action model =
  let (newModel,newFx) = update action model
  in (newModel, batch [newFx, toAnalyticsEffect action])

Done

Links

Beeline

http://krisajenkins.github.io/beeline-demo/

Blog

http://blog.jenkster.com/

Sewing Browser

http://www.getstitching.com/

Lunar Lander Game

http://krisajenkins.github.io/lunarlander

Learn!

http://www.meetup.com/West-London-Hack-Night/