Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

!

Slide 3

Slide 3 text

Good morning Buchapest!

Slide 4

Slide 4 text

@Jack_Franklin

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

The great tooling problem

Slide 9

Slide 9 text

We must accept that complex applications are hard to build

Slide 10

Slide 10 text

And that no tool / language can ever make them truly easy

Slide 11

Slide 11 text

Trends in Complex JavaScript Applications

Slide 12

Slide 12 text

Two Way Data Binding

Slide 13

Slide 13 text

Object.observe

Slide 14

Slide 14 text

MVC / MVVC / MCVCVMMCVCCC

Slide 15

Slide 15 text

"Let's replicate Rails"

Slide 16

Slide 16 text

We can do better

Slide 17

Slide 17 text

Component based approach

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Components » Angular 2 (thanks Tim!) » Ember » Vue.js » React

Slide 20

Slide 20 text

Who actually likes JavaScript these days?!

Slide 21

Slide 21 text

Explicit about state

Slide 22

Slide 22 text

Single source of truth

Slide 23

Slide 23 text

Views represent state view(state) => HTML

Slide 24

Slide 24 text

View functions are pure view(state1) => HTML1 view(state1) => HTML1 view(state2) => HTML2

Slide 25

Slide 25 text

Explicitly define all actions that can modify state function addTodo() { return { type: 'USER_ADD_TODO', text: 'Buy Milk' } }

Slide 26

Slide 26 text

Have update functions that can handle actions update(action, state) => newState

Slide 27

Slide 27 text

These are pure, too update(a1, s1) => newState1 update(a1, s1) => newState1

Slide 28

Slide 28 text

update encapsulates most business logic

Slide 29

Slide 29 text

Unidirectional Data Flow user clicks -> action -> update(action, state) -> view(newState)

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Side Effects

Slide 32

Slide 32 text

Async actions user clicks -> asyncActionFires -> update(action, state) -> view(newState) -> asyncActionReturns -> update(action, state) -> view(newState)

Slide 33

Slide 33 text

Explicit Side Effects update(action, state) => (newState, command)

Slide 34

Slide 34 text

user clicks -> action -> update(action, state) => (newState, cmdA) -> view(newState) (cmdARuns) -> cmdA returns -> update(action, state) => (newestState, none) -> view(newestState) || no commands

Slide 35

Slide 35 text

Explicit vs Magic

Slide 36

Slide 36 text

Magic! function setNewUser(name) { $scope.user = { name : 'jack' }; }

Slide 37

Slide 37 text

Explicit! function update(action, state) { switch (action.type) { case 'NEW_USER': return Object.assign({}, state, { user: { name: action.name } }); } }

Slide 38

Slide 38 text

Even more explicit! type Msg = NewUser String | LogOut

Slide 39

Slide 39 text

Even more explicit because the compiler says so update msg model = case msg of NewUser name -> { model | user = name } This `case` does not have branches for all possibilities. 22|> case msg of You need to account for the following values: LogOut Add a branch to cover this pattern!

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

Elm: a language to solve these problems.

Slide 42

Slide 42 text

Elm, my Dear Watson -- Sherlock Holmes

Slide 43

Slide 43 text

Not the finished article

Slide 44

Slide 44 text

Not the perfect language (yet?!)

Slide 45

Slide 45 text

No runtime errors!

Slide 46

Slide 46 text

» Functional » Typed » Compiled

Slide 47

Slide 47 text

» Expressive, clear code » Self documenting » Robust

Slide 48

Slide 48 text

Learning curve ahead!

Slide 49

Slide 49 text

Expressive, clear code

Slide 50

Slide 50 text

Functional Programming add(1, 2) (add 1 2)

Slide 51

Slide 51 text

List.map (\x -> x + 2) [1, 2, 3, 4] List.map ((+) 2) [1, 2, 3, 4]

Slide 52

Slide 52 text

Pipes incrementWeight (incrementHeight (incrementAge (makePerson "jack"))) makePerson "jack" |> incrementAge |> incrementHeight |> incrementWeight

Slide 53

Slide 53 text

Clean syntax incrementAge person = { person | age = person.age + 1 } add x y = x + y addTwo = add 2

Slide 54

Slide 54 text

Self documenting

Slide 55

Slide 55 text

Types Dynamic languages are a foolish friend.

Slide 56

Slide 56 text

!♥ ❤ ❤!

Slide 57

Slide 57 text

Types add : Int -> Int -> Int isEven : Int -> Bool

Slide 58

Slide 58 text

Union Types type Filter = ShowAll | ShowCompleted | ShowActive showTodos : Filter -> List Todo -> List Todo showTodos filter todos = case filter of ShowAll -> todos ShowCompleted -> List.filter (\t -> t.complete) todos ShowActive -> List.filter (\t -> not t.complete) todos

Slide 59

Slide 59 text

Union Types ! They can be checked by the compiler (typos are spotted) ! Compiler ensures all are dealt with in case ... of ! Easy to change / add a new one: add it and fix each compiler error!

Slide 60

Slide 60 text

Type variables someFunc : a -> b -> a someFunc : Int -> Bool -> Int someFunc : String -> Bool -> String someFunc : String -> Int -> String

Slide 61

Slide 61 text

Type aliases type alias Person = { name : String , age : Int } incrementAge : Person -> Person incrementAge person = { person | person.age = person.age + 1 }

Slide 62

Slide 62 text

! Clearer code, typed in your domain specific objects. ! Compiler can guarantee you're meeting the type requirements. ! No more 'undefined is not a function' !

Slide 63

Slide 63 text

type alias Person = { name : String , age : Int }

Slide 64

Slide 64 text

Robust

Slide 65

Slide 65 text

Immutability brings guarantees var person = { name: 'Jack', age: 24 }; incrementAge(person); // has this mutated? // does it return a new person? // #javascript

Slide 66

Slide 66 text

Sweet, sweet Elm let person = { name = "Jack", age = 24 } in incrementAge person ! person is untouched ! incrementAge has to return a new person ! goodbye mutation bugs

Slide 67

Slide 67 text

Modules ! Everything is scoped ! Modules explicitly declare what they expose ! Modules explicitly declare what they import

Slide 68

Slide 68 text

Dealing with nothing No more null.

Slide 69

Slide 69 text

Maybe type Maybe a = Just a | Nothing It's either Just some value, or Nothing.

Slide 70

Slide 70 text

Maybe type alias Model = { user : Maybe User } view : Model -> Html Msg view model = case model.user of Nothing -> div [] [ text "No user!" ] Just user -> div [] [ text ("Logged in as " ++ user.name) ]

Slide 71

Slide 71 text

You must handle all cases of missing / pending data

Slide 72

Slide 72 text

Task A module for async actions that might fail (HTTP). Task errType successType Task String User - if it fails, fail with a String - if it succeeds, succeed with a User

Slide 73

Slide 73 text

You have to deal with errors. Task doesn't let you not. (We'll come back to this later).

Slide 74

Slide 74 text

Reactivity » Data changes » Async activities

Slide 75

Slide 75 text

Commands and Subcriptions » Cmd : an async thing that Elm should run for you » Sub : a subscription to some data you care about that might change

Slide 76

Slide 76 text

Adjustment time This does take time to get used to » Syntax » Types » Immutablility » Compiling! » Maybe and explicit error handling

Slide 77

Slide 77 text

Elm: no runtime errors

Slide 78

Slide 78 text

user clicks -> action -> update(action, state) -> view(newState) || run command -> command causes new action -> update(action, state) -> view(newState) || no commands

Slide 79

Slide 79 text

The Elm Architecture

Slide 80

Slide 80 text

The three parts: model : Model view : Model -> Html Msg update : Msg -> Model -> Model

Slide 81

Slide 81 text

Counter

Slide 82

Slide 82 text

Live coding... !

Slide 83

Slide 83 text

Use these slides if the live coding goes dreadfully And Jack failed miserably. (Check if anyone's left in the room).

Slide 84

Slide 84 text

First, define your Model type alias Model = Int initialModel : Model initialModel = 0

Slide 85

Slide 85 text

Secondly, define your Msgs type Msg = Increment | Decrement

Slide 86

Slide 86 text

Thirdly, define your update: update : Msg -> Model -> Model update msg model = case msg of Increment -> model + 1 Decrement -> model - 1

Slide 87

Slide 87 text

Fourthly, define your view: view : Model -> Html Msg view model = div [] [ button [ onClick Decrement ] [ text "-" ] , div [] [ text (toString model) ] , button [ onClick Increment ] [ text "+" ] ]

Slide 88

Slide 88 text

Finally, hook it all up! main = Html.App.beginnerProgram { model = initialModel , view = view , update = update }

Slide 89

Slide 89 text

! We left the view until last. ! Explained all our logic before the UI. ! Notice how easy update would be to test.

Slide 90

Slide 90 text

Commands

Slide 91

Slide 91 text

Whenever you need to perform some background work, you have to give Elm a command. Elm will go off, perform the command, and call your update function once it's done.

Slide 92

Slide 92 text

Fetching someone's GitHub data.

Slide 93

Slide 93 text

Firstly, define the model: type alias GithubPerson = { name : String , company : String } type alias Model = { username : String , githubPerson : Maybe GithubPerson }

Slide 94

Slide 94 text

Secondly, define your Msgs type Msg = NewGithubData GithubPerson | FetchGithubData | FetchError Http.Error

Slide 95

Slide 95 text

Thirdly, define your update (and note the new type) update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of FetchError error -> -- deal with error here in reality NewGithubData person -> ( { model | githubPerson = Just person }, Cmd.none ) FetchGithubData -> ( model, fetchGithubData model.username )

Slide 96

Slide 96 text

Fourthly, define your view: view : Model -> Html Msg view model = case model.githubPerson of Just person -> div [] [ text (person.name ++ ", " ++ person.company) ] Nothing -> div [] [ button [ onClick FetchGithubData ] [ text "Load!" ] ]

Slide 97

Slide 97 text

Fifthly (new step), define your init: initialModel : Model initialModel = { username = "jackfranklin" , githubPerson = Nothing } init : ( Model, Cmd Msg ) init = ( initialModel, Cmd.none )

Slide 98

Slide 98 text

Finally, hook it all together! main = Html.App.program { init = init , view = view , update = update , subscriptions = \_ -> Sub.none }

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

That feels like a lot of code! -- All of you.

Slide 101

Slide 101 text

Boilerplate vs Explicitness

Slide 102

Slide 102 text

Benefits increase as application grows

Slide 103

Slide 103 text

Fetching Data

Slide 104

Slide 104 text

Decoding JSON githubDecoder : Json.Decoder GithubPerson githubDecoder = Json.object2 GithubPerson ("name" := Json.string) ("company" := Json.string)

Slide 105

Slide 105 text

Making the request fetchGithubData : String -> Cmd Msg fetchGithubData username = Http.get githubDecoder (apiUrl username) |> Task.perform FetchError NewGithubData

Slide 106

Slide 106 text

Http.get : Json.Decode.Decoder a -> String -> Task Http.Error a » takes a decoder that decodes into type a and a string (the URL) » returns a Task that either fails with Http.Error or succeeds with type a

Slide 107

Slide 107 text

Task.perform : (a -> Msg) -> (c -> Msg) -> Task a c -> Cmd Msg Task.perform : errorHander successHandler task » takes a task that will fail or succeed » takes an error function that can convert the failure to a Msg » takes a success function that can convert the success to a Msg » Returns a Cmd that will perform the task in the background.

Slide 108

Slide 108 text

github.com/jackfranklin/elm-for-js- developers

Slide 109

Slide 109 text

Scaling your application

Slide 110

Slide 110 text

It's just components all the way down!

Slide 111

Slide 111 text

The Elm Ecosystem

Slide 112

Slide 112 text

elm reactor Easily run a project in the browser with no tooling required.

Slide 113

Slide 113 text

elm package Semantic versioning ensured. ~/git/elm-statey > elm package diff Comparing jackfranklin/elm-statey 2.0.0 to local changes... This is a MAJOR change. ------ Changes to module Statey - MAJOR ------ Changed: - makeState : String -> Statey.State + makeState : Statey.State

Slide 114

Slide 114 text

elm format

Slide 115

Slide 115 text

There's so much more I haven't covered.

Slide 116

Slide 116 text

So, why / when should you use Elm?

Slide 117

Slide 117 text

You're fed up of undefined function errors that take up loads of time

Slide 118

Slide 118 text

You're fed up of packages on npm breaking semantic versioning

Slide 119

Slide 119 text

You want to develop with the confidence of Types and a clever compiler to back you up

Slide 120

Slide 120 text

You're happy to "ride the wave" and deal with a language still growing and settling down

Slide 121

Slide 121 text

You're happy to build more packages than depend on existing solutions which may not exist in Elm

Slide 122

Slide 122 text

But what if this talk has put me off Elm?

Slide 123

Slide 123 text

Elm does take time to learn, so please don't give up after 30 minutes of slides! guide.elm-lang.org

Slide 124

Slide 124 text

Elm the language brings many concepts that are language agnostic

Slide 125

Slide 125 text

The Elm Architecture

Slide 126

Slide 126 text

Explicitness across your application

Slide 127

Slide 127 text

Types

Slide 128

Slide 128 text

Immutability / Functional Programming

Slide 129

Slide 129 text

Defining your application step by step 1. Define your model. 2. Define your actions. 3. Define your update function. 4. Define your view. 5. Repeat.

Slide 130

Slide 130 text

Will everyone be writing Elm in 1/2/5 years?

Slide 131

Slide 131 text

No content

Slide 132

Slide 132 text

» javascriptplayground.com/elm-jscamp.html » guide.elm-lang.org » elm-lang.org/docs » elm-lang.org/community

Slide 133

Slide 133 text

@Jack_Franklin javascriptplayground.com

Slide 134

Slide 134 text

! Thank you !