Codemash 2017: Toward a Better Front-end Architecture: Elm

Codemash 2017: Toward a Better Front-end Architecture: Elm

94bd558238b69c45d3d3e15797ae94f7?s=128

Jeremy Fairbank

January 12, 2017
Tweet

Transcript

  1. 1.

    TOWARD A BETTER |> FRONT END |> ARCHITECTURE elm Jeremy

    Fairbank blog.jeremyfairbank.com tw: @elpapapollo / gh: jfairbank
  2. 3.
  3. 4.
  4. 5.
  5. 8.
  6. 10.

    let name = 'Jeremy'; export function getName() { return name;

    } export function setName(newName) { name = newName; } Impure and Mutable
  7. 13.

    Error Handling function mayThrow() { throw new Error('Whoops...') } function

    unsafe() { try { mayThrow(); } catch (e) { handleError(e); } } Call Stack ×
  8. 16.

    elm

  9. 17.

    No runtime errors in practice. No null. No undefined is

    not a function. - guide.elm-lang.org
  10. 21.

    greet name = "Hello, " ++ name add x y

    = x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
  11. 22.

    greet name = "Hello, " ++ name add x y

    = x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
  12. 23.

    greet name = "Hello, " ++ name add x y

    = x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
  13. 24.

    greet name = "Hello, " ++ name add x y

    = x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
  14. 25.

    greet name = "Hello, " ++ name add x y

    = x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
  15. 26.

    greet name = "Hello, " ++ name add x y

    = x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
  16. 27.
  17. 28.

    pure add x y = x + y add 2

    3 -- 5 add 2 3 -- 5 add 2 3 -- 5
  18. 29.

    pure add x y = x + y add 2

    3 -- 5 add 2 3 -- 5 add 2 3 -- 5 Referentially Transparent
  19. 30.

    function fetchUser(id) { const url = `/user/${id}`; return axios.get(url); }

    pure ✓ × fetchUser id = let url = "/user/" ++ (toString id) request = Http.get url userDecoder in Http.send LoadUser request
  20. 32.

    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
  21. 33.

    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 ×
  22. 34.

    myList = [1, 2, 3, 4, 5] double n =

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

    myList = [1, 2, 3, 4, 5] double n =

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

    myList = [1, 2, 3, 4, 5] double n =

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

    myList = [1, 2, 3, 4, 5] double n =

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

    currying add x y z = x + y +

    z add 1 2 3 -- 6 ((add 1) 2) 3 -- 6 add1 = add 1 add3 = add1 2 add1 2 3 -- 6 add3 3 -- 6
  27. 40.

    currying add x y z = x + y +

    z add 1 2 3 -- 6 ((add 1) 2) 3 -- 6 add1 = add 1 add3 = add1 2 add1 2 3 -- 6 add3 3 -- 6
  28. 41.

    currying add x y z = x + y +

    z add 1 2 3 -- 6 ((add 1) 2) 3 -- 6 add1 = add 1 add3 = add1 2 add1 2 3 -- 6 add3 3 -- 6
  29. 42.

    currying add x y z = x + y +

    z add 1 2 3 -- 6 ((add 1) 2) 3 -- 6 add1 = add 1 add3 = add1 2 add1 2 3 -- 6 add3 3 -- 6
  30. 48.

    list = List.range 1 10 square n = n *

    n List.map square (List.filter ((<) 6) (List.map ((*) 2) list)) piping
  31. 49.

    list = List.range 1 10 square n = n *

    n List.map square (List.filter ((<) 6) (List.map ((*) 2) list)) piping
  32. 50.

    piping list = List.range 1 10 square n = n

    * n list |> List.map ((*) 2) |> List.filter ((<) 6) |> List.map square
  33. 51.

    piping list = List.range 1 10 square n = n

    * n list |> List.map ((*) 2) |> List.filter ((<) 6) |> List.map square
  34. 53.

    |> List.map ((*) 2) |> List.filter ((<) 6) |> List.map

    square piping list doubled = List.map ((*) 2) list
  35. 55.

    |> List.filter ((<) 6) |> List.map square piping doubled =

    List.map ((*) 2) list doubled filtered = List.filter ((<) 6) mapped
  36. 56.

    piping doubled = List.map ((*) 2) list filtered = List.filter

    ((<) 6) mapped |> List.map square filtered
  37. 57.

    piping doubled = List.map ((*) 2) list filtered = List.filter

    ((<) 6) mapped |> List.map square filtered squared = List.map square filtered
  38. 59.

    life : Int life = 42 greeting : String greeting

    = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3] strong static typing
  39. 60.

    strong static typing greet : String -> String greet name

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

    strong static typing greet : String -> String greet name

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

    strong static typing greet : String -> String greet name

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

    strong static typing greet : String -> String greet name

    = "Hello, " ++ name add : Int -> (Int -> Int) add x y = x + y
  43. 65.

    dog : ( String, Int ) dog = ( "Tucker",

    11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
  44. 66.

    dog : ( String, Int ) dog = ( "Tucker",

    11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
  45. 67.

    dog : ( String, Int ) dog = ( "Tucker",

    11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
  46. 68.

    dog : ( String, Int ) dog = ( "Tucker",

    11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
  47. 69.

    records dog : { name : String, age : Int,

    breed : String } dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } dog.name -- "Tucker" dog.age -- 11 dog.breed -- "Sheltie" .name dog -- "Tucker"
  48. 70.

    records dog : { name : String, age : Int,

    breed : String } dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } dog.name -- "Tucker" dog.age -- 11 dog.breed -- "Sheltie" .name dog -- "Tucker"
  49. 71.

    records dog : { name : String, age : Int,

    breed : String } dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } dog.name -- "Tucker" dog.age -- 11 dog.breed -- "Sheltie" .name dog -- "Tucker"
  50. 72.

    records dog : { name : String, age : Int,

    breed : String } dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } dog.name -- "Tucker" dog.age -- 11 dog.breed -- "Sheltie" .name dog -- "Tucker"
  51. 73.

    records dog : { name : String, age : Int,

    breed : String } dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } dog.name -- "Tucker" dog.age -- 11 dog.breed -- "Sheltie" .name dog -- "Tucker"
  52. 74.

    type alias Dog = { name : String , age

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

    type alias Dog = { name : String , age

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

    type alias Dog = { name : String , age

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

    aliases type alias Dog = { name : String ,

    age : Int , breed : String } dog : Dog dog = Dog "Tucker" 11 "Sheltie"
  56. 79.

    immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  57. 80.

    immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  58. 81.

    immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  59. 82.

    immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  60. 83.

    immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  61. 84.

    union types type alias Dog = { name : String

    , age : Int , breed : String }
  62. 85.

    union types type alias Dog = { name : String

    , age : Int , breed : String }
  63. 86.

    type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed union types type alias Dog = { name : String , age : Int , breed : String }
  64. 87.

    type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed union types type alias Dog = { name : String , age : Int , breed : Breed }
  65. 91.

    type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix
  66. 92.

    type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix
  67. 93.

    type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix
  68. 94.

    type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix ?
  69. 95.

    dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally"

    5 Corgi dog3 = Dog "Rover" 1 (Mix Sheltie Corgi) type Breed = Sheltie | Corgi | GoldenRetriever | Mix Breed Breed
  70. 96.
  71. 99.

    divide : number -> number -> Maybe Float divide x

    y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
  72. 100.

    divide : number -> number -> Maybe Float divide x

    y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
  73. 101.

    divide : number -> number -> Maybe Float divide x

    y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
  74. 102.

    divide : number -> number -> Maybe Float divide x

    y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
  75. 103.

    divide : number -> number -> Maybe Float divide x

    y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
  76. 104.

    case divide 4 2 of Just n -> "Result is

    " ++ (toString n) Nothing -> "No Result"
  77. 105.

    case divide 4 2 of Just n -> "Result is

    " ++ (toString n) Nothing -> "No Result"
  78. 106.

    case divide 4 2 of Just n -> "Result is

    " ++ (toString n) Nothing -> "No Result"
  79. 107.

    case divide 4 2 of Just n -> "Result is

    " ++ (toString n) Nothing -> "No Result"
  80. 117.

    elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets

    Browser Window Mouse Position Events Text Input Mouse Click
  81. 118.

    elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets

    Browser Window Mouse Position Events Text Input Mouse Click Tasks
  82. 119.

    elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets

    Browser Window Mouse Position Events Text Input Mouse Click Tasks
  83. 120.
  84. 134.

    THANKS! Jeremy Fairbank blog.jeremyfairbank.com tw: @elpapapollo / gh: jfairbank |>

    elm-lang.org |> guide.elm-lang.org |> github.com/jfairbank/arch-elm