Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Scenic City Summit 2017: Tame the frontend with Elm

Scenic City Summit 2017: Tame the frontend with Elm

Jeremy Fairbank

July 28, 2017
Tweet

More Decks by Jeremy Fairbank

Other Decks in Programming

Transcript

  1. Tame the frontend
    with Elm
    Jeremy Fairbank
    @elpapapollo / jfairbank

    View Slide

  2. Tame the frontend
    with Elm
    Jeremy Fairbank
    @elpapapollo / jfairbank

    View Slide

  3. Software is broken.
    We are here to fix it.
    Say [email protected]

    View Slide

  4. Happiness

    View Slide

  5. View Slide

  6. ✓ Easier to write code
    ✓ Easier to write tests
    ✓ Easier to refactor

    View Slide

  7. elm

    View Slide

  8. No runtime exceptions in
    practice.

    View Slide

  9. No undefined is not a
    function

    View Slide

  10. Fast

    View Slide

  11. One framework.
    No fatigue.
    Update
    View
    Model
    Messages

    View Slide

  12. elm

    View Slide

  13. Functional

    View Slide

  14. greet name =
    "Hello, " ++ name
    greet "Scenic City Summit"
    -- Hello, Scenic City Summit

    View Slide

  15. greet name =
    "Hello, " ++ name
    greet "Scenic City Summit"
    -- Hello, Scenic City Summit

    View Slide

  16. greet name =
    "Hello, " ++ name
    greet "Scenic City Summit"
    -- Hello, Scenic City Summit

    View Slide

  17. greet name =
    "Hello, " ++ name
    greet "Scenic City Summit"
    -- Hello, Scenic City Summit
    Single
    Expression

    View Slide

  18. greet name =
    "Hello, " ++ name
    greet "Scenic City Summit"
    -- Hello, Scenic City Summit

    View Slide

  19. greet name =
    "Hello, " ++ name
    greet "Scenic City Summit"
    -- Hello, Scenic City Summit

    View Slide

  20. Pure Data in
    Data out

    View Slide

  21. Pure No side
    effects

    View Slide

  22. Pure Predictable
    and Testable!

    View Slide

  23. add x y =
    x + y
    add 2 3 == 5
    add 2 3 == 5
    add 2 3 == 5

    View Slide

  24. add x y =
    x + y
    add 2 3 == 5
    add 2 3 == 5
    add 2 3 == 5

    View Slide

  25. add x y =
    x + y
    add 2 3 == 5
    add 2 3 == 5
    add 2 3 == 5

    View Slide

  26. Expressive
    Terse and declarative code

    View Slide

  27. function doubleNumbers(numbers) {
    const doubled = [];
    const l = numbers.length;
    for (let i = 0; i < l; i++) {
    doubled.push(numbers[i] * 2);
    }
    return doubled;
    }
    doubleNumbers([1, 2, 3, 4, 5]);
    // [2, 4, 6, 8, 10]
    Imperative

    View Slide

  28. function doubleNumbers(numbers) {
    const doubled = [];
    const l = numbers.length;
    for (let i = 0; i < l; i++) {
    doubled.push(numbers[i] * 2);
    }
    return doubled;
    }
    doubleNumbers([1, 2, 3, 4, 5]);
    // [2, 4, 6, 8, 10]
    Imperative
    ×

    View Slide

  29. myList = [1, 2, 3, 4, 5]
    double n = n * 2
    doubleNumbers list =
    List.map double list
    doubleNumbers myList -- [2, 4, 6, 8, 10]

    View Slide

  30. myList = [1, 2, 3, 4, 5]
    double n = n * 2
    doubleNumbers list =
    List.map double list
    doubleNumbers myList -- [2, 4, 6, 8, 10]

    View Slide

  31. myList = [1, 2, 3, 4, 5]
    double n = n * 2
    doubleNumbers list =
    List.map double list
    doubleNumbers myList -- [2, 4, 6, 8, 10]

    View Slide

  32. myList = [1, 2, 3, 4, 5]
    double n = n * 2
    doubleNumbers list =
    List.map double list
    doubleNumbers myList -- [2, 4, 6, 8, 10]

    View Slide

  33. myList = [1, 2, 3, 4, 5]
    double n = n * 2
    doubleNumbers list =
    List.map double list
    doubleNumbers myList -- [2, 4, 6, 8, 10]

    View Slide

  34. myList = [1, 2, 3, 4, 5]
    double n = n * 2
    doubleNumbers list =
    List.map double list
    doubleNumbers myList -- [2, 4, 6, 8, 10]

    View Slide

  35. Curried Functions
    Building blocks

    View Slide

  36. add x y = x + y
    add 1 2 -- 3
    (add 1) 2 -- 3

    View Slide

  37. add x y = x + y
    add 1 2 -- 3
    (add 1) 2 -- 3

    View Slide

  38. add x y = x + y
    add 1 2 -- 3
    (add 1) 2 -- 3

    View Slide

  39. add x y = x + y
    add 1 2 -- 3
    (add 1) 2 -- 3
    New function created

    View Slide

  40. increment = add 1
    increment 2 -- 3
    increment 41 -- 42

    View Slide

  41. increment = add 1
    increment 2 -- 3
    increment 41 -- 42

    View Slide

  42. increment = add 1
    increment 2 -- 3
    increment 41 -- 42

    View Slide

  43. Pipes
    Compose functions with
    expressive chaining

    View Slide

  44. greet name = "Hello, " ++ name
    exclaim phrase = phrase ++ "!"
    excitedGreeting name =
    exclaim (greet (String.toUpper name))

    View Slide

  45. greet name = "Hello, " ++ name
    exclaim phrase = phrase ++ "!"
    excitedGreeting name =
    exclaim (greet (String.toUpper name))

    View Slide

  46. excitedGreeting name =
    name
    |> String.toUpper
    |> greet
    |> exclaim
    excitedGreeting "Tucker"

    View Slide

  47. excitedGreeting name =
    name
    |> String.toUpper
    |> greet
    |> exclaim
    excitedGreeting "Tucker"

    View Slide

  48. "Tucker"
    |> String.toUpper
    |> greet
    |> exclaim

    View Slide

  49. |> String.toUpper "Tucker"
    |> greet
    |> exclaim

    View Slide

  50. "TUCKER"
    |> greet
    |> exclaim

    View Slide

  51. |> greet "TUCKER"
    |> exclaim

    View Slide

  52. "Hello, TUCKER"
    |> exclaim

    View Slide

  53. |> exclaim "Hello, TUCKER"

    View Slide

  54. "Hello, TUCKER!"

    View Slide

  55. No Runtime
    Exceptions

    View Slide

  56. Strong
    Static
    Types
    life : Int
    life = 42
    greeting : String
    greeting = "Hello World"
    isTrue : Bool
    isTrue = True
    numbers : List Int
    numbers = [1, 2, 3]

    View Slide

  57. Strong
    Static
    Types
    life : Int
    life = 42
    greeting : String
    greeting = "Hello World"
    isTrue : Bool
    isTrue = True
    numbers : List Int
    numbers = [1, 2, 3]

    View Slide

  58. Strong
    Static
    Types
    life : Int
    life = 42
    greeting : String
    greeting = "Hello World"
    isTrue : Bool
    isTrue = True
    numbers : List Int
    numbers = [1, 2, 3]

    View Slide

  59. Strong
    Static
    Types
    life : Int
    life = 42
    greeting : String
    greeting = "Hello World"
    isTrue : Bool
    isTrue = True
    numbers : List Int
    numbers = [1, 2, 3]

    View Slide

  60. Strong
    Static
    Types
    life : Int
    life = 42
    greeting : String
    greeting = "Hello World"
    isTrue : Bool
    isTrue = True
    numbers : List Int
    numbers = [1, 2, 3]

    View Slide

  61. greet : String -> String
    greet name =
    "Hello, " ++ name
    add : Int -> Int -> Int
    add x y =
    x + y

    View Slide

  62. greet : String -> String
    greet name =
    "Hello, " ++ name
    add : Int -> Int -> Int
    add x y =
    x + y

    View Slide

  63. greet : String -> String
    greet name =
    "Hello, " ++ name
    add : Int -> Int -> Int
    add x y =
    x + y

    View Slide

  64. greet : String -> String
    greet name =
    "Hello, " ++ name
    add : Int -> (Int -> Int)
    add x y =
    x + y

    View Slide

  65. The 2nd argument to function `add` is causing a mismatch.
    7| add 2 "3"
    ^^^
    Function `add` is expecting the 2nd argument to be:
    Int
    But it is:
    String
    Compile time static type checks

    View Slide

  66. Immutable Data
    Safe and Consistent

    View Slide

  67. dog : { name : String, age : Int }
    dog =
    { name = "Tucker"
    , age = 11
    }
    dog.name -- "Tucker"
    dog.age -- 11
    Records

    View Slide

  68. dog : { name : String, age : Int }
    dog =
    { name = "Tucker"
    , age = 11
    }
    dog.name -- "Tucker"
    dog.age -- 11
    Records

    View Slide

  69. dog : { name : String, age : Int }
    dog =
    { name = "Tucker"
    , age = 11
    }
    dog.name -- "Tucker"
    dog.age -- 11
    Records

    View Slide

  70. dog : { name : String, age : Int }
    dog =
    { name = "Tucker"
    , age = 11
    }
    dog.name -- "Tucker"
    dog.age -- 11
    Records

    View Slide

  71. haveBirthday dog =
    { dog | age = dog.age + 1 }
    dog = { name = "Tucker", age = 11 }
    olderDog = haveBirthday dog
    olderDog.age -- 12
    olderDog.name -- "Tucker"
    dog.age -- 11
    dog.name -- "Tucker"
    Create New Data

    View Slide

  72. haveBirthday dog =
    { dog | age = dog.age + 1 }
    dog = { name = "Tucker", age = 11 }
    olderDog = haveBirthday dog
    olderDog.age -- 12
    olderDog.name -- "Tucker"
    dog.age -- 11
    dog.name -- "Tucker"
    Create New Data

    View Slide

  73. haveBirthday dog =
    { dog | age = dog.age + 1 }
    dog = { name = "Tucker", age = 11 }
    olderDog = haveBirthday dog
    olderDog.age -- 12
    olderDog.name -- "Tucker"
    dog.age -- 11
    dog.name -- "Tucker"
    Create New Data

    View Slide

  74. haveBirthday dog =
    { dog | age = dog.age + 1 }
    dog = { name = "Tucker", age = 11 }
    olderDog = haveBirthday dog
    olderDog.age -- 12
    olderDog.name -- "Tucker"
    dog.age -- 11
    dog.name -- "Tucker"
    Create New Data

    View Slide

  75. haveBirthday dog =
    { dog | age = dog.age + 1 }
    dog = { name = "Tucker", age = 11 }
    olderDog = haveBirthday dog
    olderDog.age -- 12
    olderDog.name -- "Tucker"
    dog.age -- 11
    dog.name -- "Tucker"
    Create New Data

    View Slide

  76. haveBirthday dog =
    { dog | age = dog.age + 1 }
    dog = { name = "Tucker", age = 11 }
    olderDog = haveBirthday dog
    olderDog.age -- 12
    olderDog.name -- "Tucker"
    dog.age -- 11
    dog.name -- "Tucker"
    Create New Data

    View Slide

  77. Custom Types
    Domain-specific code

    View Slide

  78. type alias Dog =
    { name : String
    , age : Int
    , breed : Breed
    }
    type Breed
    = Sheltie
    | Poodle

    View Slide

  79. type alias Dog =
    { name : String
    , age : Int
    , breed : Breed
    }
    type Breed
    = Sheltie
    | Poodle

    View Slide

  80. type alias Dog =
    { name : String
    , age : Int
    , breed : Breed
    }
    type Breed
    = Sheltie
    | Poodle
    Union Type

    View Slide

  81. dog : Dog
    dog =
    { name = "Tucker"
    , age = 11
    , breed = Sheltie
    }

    View Slide

  82. dog : Dog
    dog =
    { name = "Tucker"
    , age = 11
    , breed = Sheltie
    }

    View Slide

  83. dog : Dog
    dog =
    { name = "Tucker"
    , age = 11
    , breed = Sheltie
    }

    View Slide

  84. dog : Dog
    dog =
    { name = "Tucker"
    , age = 11
    , breed = Shelty
    }
    Misspelled.
    Won’t compile!

    View Slide

  85. No null or
    undefined

    View Slide

  86. type Maybe a
    = Just a
    | Nothing

    View Slide

  87. type Maybe a
    = Just a
    | Nothing
    Wraps the
    successful value

    View Slide

  88. type Maybe a
    = Just a
    | Nothing
    Wraps the
    successful value
    Type Variable

    View Slide

  89. type Maybe a
    = Just a
    | Nothing Represents no result
    or missing value

    View Slide

  90. type Maybe a
    = Just a
    | Nothing
    Either I have Just the value a,
    or I have Nothing.

    View Slide

  91. divide : Float -> Float -> Maybe Float
    divide x y =
    if y == 0 then
    Nothing
    else
    Just (x / y)
    divide 4 2 -- Just 2
    divide 4 0 -- Nothing

    View Slide

  92. divide : Float -> Float -> Maybe Float
    divide x y =
    if y == 0 then
    Nothing
    else
    Just (x / y)
    divide 4 2 -- Just 2
    divide 4 0 -- Nothing

    View Slide

  93. divide : Float -> Float -> Maybe Float
    divide x y =
    if y == 0 then
    Nothing
    else
    Just (x / y)
    divide 4 2 -- Just 2
    divide 4 0 -- Nothing

    View Slide

  94. divide : Float -> Float -> Maybe Float
    divide x y =
    if y == 0 then
    Nothing
    else
    Just (x / y)
    divide 4 2 -- Just 2
    divide 4 0 -- Nothing

    View Slide

  95. divide : Float -> Float -> Maybe Float
    divide x y =
    if y == 0 then
    Nothing
    else
    Just (x / y)
    divide 4 2 -- Just 2
    divide 4 0 -- Nothing

    View Slide

  96. divide : Float -> Float -> Maybe Float
    divide x y =
    if y == 0 then
    Nothing
    else
    Just (x / y)
    divide 4 2 -- Just 2
    divide 4 0 -- Nothing

    View Slide

  97. case divide 4 2 of
    Just n ->
    "Result is " ++ (toString n)
    Nothing ->
    "No Result"

    View Slide

  98. case divide 4 2 of
    Just n ->
    "Result is " ++ (toString n)
    Nothing ->
    "No Result"

    View Slide

  99. case divide 4 2 of
    Just n ->
    "Result is " ++ (toString n)
    Nothing ->
    "No Result"

    View Slide

  100. case divide 4 2 of
    Just n ->
    "Result is " ++ (toString n)
    Nothing ->
    "No Result"

    View Slide

  101. case divide 4 2 of
    Just n ->
    "Result is " ++ (toString n)
    -- Nothing ->
    -- "No Result"

    View Slide

  102. Exhaustive matching
    This `case` does not have branches for all possibilities.
    21|> case divide 4 2 of
    22|> Just n ->
    23|> "Result is " ++ (toString n)
    You need to account for the following values:
    Maybe.Nothing
    Add a branch to cover this pattern!

    View Slide

  103. Update
    View
    Model
    Messages
    The Elm
    Architecture

    View Slide

  104. model
    Update View

    View Slide

  105. model
    Update View
    VDOM

    View Slide

  106. model
    Update View

    View Slide

  107. model
    Update View

    View Slide

  108. model
    Update View

    View Slide

  109. model
    Update View

    View Slide

  110. model
    Update View

    View Slide

  111. model
    Update View
    VDOM

    View Slide

  112. Demos
    The Elm Architecture in Action

    View Slide

  113. Getting
    Started
    • elm-lang.org
    • elm-lang.org/examples
    • guide.elm-lang.org
    • www.elm-tutorial.org
    • builtwithelm.co
    • Slack
    • elmlang.herokuapp.com

    View Slide

  114. Thanks!
    Jeremy Fairbank
    @elpapapollo / jfairbank
    Slides: bit.ly/scs-elm

    View Slide