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

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

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

Jeremy Fairbank

January 12, 2017
Tweet

More Decks by Jeremy Fairbank

Other Decks in Programming

Transcript

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

    Fairbank blog.jeremyfairbank.com tw: @elpapapollo / gh: jfairbank
  2. let name = 'Jeremy'; export function getName() { return name;

    } export function setName(newName) { name = newName; } Impure and Mutable
  3. Error Handling function mayThrow() { throw new Error('Whoops...') } function

    unsafe() { try { mayThrow(); } catch (e) { handleError(e); } } Call Stack ×
  4. elm

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

    not a function. - guide.elm-lang.org
  6. greet name = "Hello, " ++ name add x y

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

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

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

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

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

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

    3 -- 5 add 2 3 -- 5 add 2 3 -- 5
  13. pure add x y = x + y add 2

    3 -- 5 add 2 3 -- 5 add 2 3 -- 5 Referentially Transparent
  14. 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
  15. 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
  16. 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 ×
  17. myList = [1, 2, 3, 4, 5] double n =

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

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

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

    n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10] declarative
  21. 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
  22. 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
  23. 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
  24. 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
  25. list = List.range 1 10 square n = n *

    n List.map square (List.filter ((<) 6) (List.map ((*) 2) list)) piping
  26. list = List.range 1 10 square n = n *

    n List.map square (List.filter ((<) 6) (List.map ((*) 2) list)) piping
  27. piping list = List.range 1 10 square n = n

    * n list |> List.map ((*) 2) |> List.filter ((<) 6) |> List.map square
  28. piping list = List.range 1 10 square n = n

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

    square piping list doubled = List.map ((*) 2) list
  30. |> List.filter ((<) 6) |> List.map square piping doubled =

    List.map ((*) 2) list doubled filtered = List.filter ((<) 6) mapped
  31. piping doubled = List.map ((*) 2) list filtered = List.filter

    ((<) 6) mapped |> List.map square filtered
  32. piping doubled = List.map ((*) 2) list filtered = List.filter

    ((<) 6) mapped |> List.map square filtered squared = List.map square filtered
  33. life : Int life = 42 greeting : String greeting

    = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3] strong static typing
  34. strong static typing greet : String -> String greet name

    = "Hello, " ++ name add : Int -> Int -> Int add x y = x + y
  35. strong static typing greet : String -> String greet name

    = "Hello, " ++ name add : Int -> Int -> Int add x y = x + y
  36. strong static typing greet : String -> String greet name

    = "Hello, " ++ name add : Int -> Int -> Int add x y = x + y
  37. strong static typing greet : String -> String greet name

    = "Hello, " ++ name add : Int -> (Int -> Int) add x y = x + y
  38. dog : ( String, Int ) dog = ( "Tucker",

    11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
  39. dog : ( String, Int ) dog = ( "Tucker",

    11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
  40. dog : ( String, Int ) dog = ( "Tucker",

    11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
  41. dog : ( String, Int ) dog = ( "Tucker",

    11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
  42. 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"
  43. 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"
  44. 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"
  45. 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"
  46. 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"
  47. type alias Dog = { name : String , age

    : Int , breed : String } dog : Dog dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } aliases
  48. type alias Dog = { name : String , age

    : Int , breed : String } dog : Dog dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } aliases
  49. type alias Dog = { name : String , age

    : Int , breed : String } dog : Dog dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } aliases
  50. aliases type alias Dog = { name : String ,

    age : Int , breed : String } dog : Dog dog = Dog "Tucker" 11 "Sheltie"
  51. immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  52. immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  53. immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  54. immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  55. immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {

    dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
  56. union types type alias Dog = { name : String

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

    , age : Int , breed : String }
  58. type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed union types type alias Dog = { name : String , age : Int , breed : String }
  59. type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed union types type alias Dog = { name : String , age : Int , breed : Breed }
  60. type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix
  61. type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix
  62. type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix
  63. type Breed = Sheltie | Corgi | GoldenRetriever | Mix

    Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix ?
  64. 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
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. case divide 4 2 of Just n -> "Result is

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

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

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

    " ++ (toString n) Nothing -> "No Result"
  74. elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets

    Browser Window Mouse Position Events Text Input Mouse Click
  75. elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets

    Browser Window Mouse Position Events Text Input Mouse Click Tasks
  76. elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets

    Browser Window Mouse Position Events Text Input Mouse Click Tasks
  77. THANKS! Jeremy Fairbank blog.jeremyfairbank.com tw: @elpapapollo / gh: jfairbank |>

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