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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. No runtime exceptions in
    practice.

    View full-size slide

  6. No undefined is not a
    function

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  14. Pure Data in
    Data out

    View full-size slide

  15. Pure No side
    effects

    View full-size slide

  16. Pure Predictable
    and Testable!

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  20. Expressive
    Terse and declarative code

    View full-size slide

  21. 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 full-size slide

  22. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  29. Curried Functions
    Building blocks

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  37. Pipes
    Compose functions with
    expressive chaining

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  44. "TUCKER"
    |> greet
    |> exclaim

    View full-size slide

  45. |> greet "TUCKER"
    |> exclaim

    View full-size slide

  46. "Hello, TUCKER"
    |> exclaim

    View full-size slide

  47. |> exclaim "Hello, TUCKER"

    View full-size slide

  48. "Hello, TUCKER!"

    View full-size slide

  49. No Runtime
    Exceptions

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  59. 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 full-size slide

  60. Immutable Data
    Safe and Consistent

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  65. 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 full-size slide

  66. 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 full-size slide

  67. 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 full-size slide

  68. 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 full-size slide

  69. 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 full-size slide

  70. 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 full-size slide

  71. Custom Types
    Domain-specific code

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  79. No null or
    undefined

    View full-size slide

  80. type Maybe a
    = Just a
    | Nothing

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  85. 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 full-size slide

  86. 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 full-size slide

  87. 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 full-size slide

  88. 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 full-size slide

  89. 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 full-size slide

  90. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  96. 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 full-size slide

  97. Update
    View
    Model
    Messages
    The Elm
    Architecture

    View full-size slide

  98. model
    Update View

    View full-size slide

  99. model
    Update View
    VDOM

    View full-size slide

  100. model
    Update View

    View full-size slide

  101. model
    Update View

    View full-size slide

  102. model
    Update View

    View full-size slide

  103. model
    Update View

    View full-size slide

  104. model
    Update View

    View full-size slide

  105. model
    Update View
    VDOM

    View full-size slide

  106. Demos
    The Elm Architecture in Action

    View full-size slide

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

    View full-size slide

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

    View full-size slide