Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
Scenic City Summit 2017: Tame the frontend with Elm
Jeremy Fairbank
July 28, 2017
Programming
0
120
Scenic City Summit 2017: Tame the frontend with Elm
Jeremy Fairbank
July 28, 2017
Tweet
Share
More Decks by Jeremy Fairbank
See All by Jeremy Fairbank
Connect.Tech 2020: Advanced Cypress Testing
jfairbank
1
110
CodeMash 2020: Solving the Boolean Identity Crisis
jfairbank
1
110
CodeMash 2020: Practical Functional Programming
jfairbank
1
270
Connect.Tech 2019: Practical Functional Programming
jfairbank
0
190
Connect.Tech 2019: Solving the Boolean Identity Crisis
jfairbank
0
130
Lambda Squared 2019: Solving the Boolean Identity Crisis
jfairbank
0
40
All Things Open 2018: Practical Functional Programming
jfairbank
2
210
Connect.Tech 2018: Effective React Testing
jfairbank
1
100
Fluent Conf 2018: Building web apps with Elm Tutorial
jfairbank
2
680
Other Decks in Programming
See All in Programming
プロダクトのタイプ別 GraphQL クライアントの選び方
shozawa
0
5.7k
【Scrum Fest Osaka 2022】スクラムチームに放り込まれた若手エンジニアの皆さん、どのように技術のキャッチアップをしていくかイメージはついていますか?
miiiki
0
120
Let's keep Commodore 64 alive for the next 40 years
mehowte
1
110
設計ナイト2022 トランザクションスクリプト
shinpeim
11
2.1k
Angular-basierte Micro Frontends mit Module Federation @API Summit
manfredsteyer
PRO
0
120
Get Ready for Jakarta EE 10
ivargrimstad
0
2.9k
Swift Regex
usamik26
0
210
BASE BANKチームの技術選定と歴史 / how to decide technology selection for startup
budougumi0617
0
1.4k
CSE360 Tutorial 07
javiergs
PRO
0
100
Angular‘s Future without NgModules: Architectures with Standalone Components @enterJS
manfredsteyer
PRO
0
250
パターンマッチングを学んで新しいJavaの世界へ!Java 18までの目玉機能をおさらいしよう / Java 18 pattern matching
ihcomega56
3
430
シェーダー氷山発掘記
logilabo
0
150
Featured
See All Featured
Docker and Python
trallard
27
1.6k
Become a Pro
speakerdeck
PRO
3
850
In The Pink: A Labor of Love
frogandcode
131
21k
Rails Girls Zürich Keynote
gr2m
86
12k
Product Roadmaps are Hard
iamctodd
34
6.6k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
212
20k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
349
27k
Large-scale JavaScript Application Architecture
addyosmani
499
110k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
269
11k
Stop Working from a Prison Cell
hatefulcrawdad
261
17k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
655
120k
The Mythical Team-Month
searls
209
39k
Transcript
Tame the frontend with Elm Jeremy Fairbank @elpapapollo / jfairbank
Tame the frontend with Elm Jeremy Fairbank @elpapapollo / jfairbank
Software is broken. We are here to fix it. Say
hi@testdouble.com
Happiness
None
✓ Easier to write code ✓ Easier to write tests
✓ Easier to refactor
elm
No runtime exceptions in practice.
No undefined is not a function
Fast
One framework. No fatigue. Update View Model Messages
elm
Functional
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit Single Expression
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
Pure Data in Data out
Pure No side effects
Pure Predictable and Testable!
add x y = x + y add 2 3
== 5 add 2 3 == 5 add 2 3 == 5
add x y = x + y add 2 3
== 5 add 2 3 == 5 add 2 3 == 5
add x y = x + y add 2 3
== 5 add 2 3 == 5 add 2 3 == 5
Expressive Terse and declarative code
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
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 ×
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
Curried Functions Building blocks
add x y = x + y add 1 2
-- 3 (add 1) 2 -- 3
add x y = x + y add 1 2
-- 3 (add 1) 2 -- 3
add x y = x + y add 1 2
-- 3 (add 1) 2 -- 3
add x y = x + y add 1 2
-- 3 (add 1) 2 -- 3 New function created
increment = add 1 increment 2 -- 3 increment 41
-- 42
increment = add 1 increment 2 -- 3 increment 41
-- 42
increment = add 1 increment 2 -- 3 increment 41
-- 42
Pipes Compose functions with expressive chaining
greet name = "Hello, " ++ name exclaim phrase =
phrase ++ "!" excitedGreeting name = exclaim (greet (String.toUpper name))
greet name = "Hello, " ++ name exclaim phrase =
phrase ++ "!" excitedGreeting name = exclaim (greet (String.toUpper name))
excitedGreeting name = name |> String.toUpper |> greet |> exclaim
excitedGreeting "Tucker"
excitedGreeting name = name |> String.toUpper |> greet |> exclaim
excitedGreeting "Tucker"
"Tucker" |> String.toUpper |> greet |> exclaim
|> String.toUpper "Tucker" |> greet |> exclaim
"TUCKER" |> greet |> exclaim
|> greet "TUCKER" |> exclaim
"Hello, TUCKER" |> exclaim
|> exclaim "Hello, TUCKER"
"Hello, TUCKER!"
No Runtime Exceptions
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
greet : String -> String greet name = "Hello, "
++ name add : Int -> Int -> Int add x y = x + y
greet : String -> String greet name = "Hello, "
++ name add : Int -> Int -> Int add x y = x + y
greet : String -> String greet name = "Hello, "
++ name add : Int -> Int -> Int add x y = x + y
greet : String -> String greet name = "Hello, "
++ name add : Int -> (Int -> Int) add x y = x + y
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
Immutable Data Safe and Consistent
dog : { name : String, age : Int }
dog = { name = "Tucker" , age = 11 } dog.name -- "Tucker" dog.age -- 11 Records
dog : { name : String, age : Int }
dog = { name = "Tucker" , age = 11 } dog.name -- "Tucker" dog.age -- 11 Records
dog : { name : String, age : Int }
dog = { name = "Tucker" , age = 11 } dog.name -- "Tucker" dog.age -- 11 Records
dog : { name : String, age : Int }
dog = { name = "Tucker" , age = 11 } dog.name -- "Tucker" dog.age -- 11 Records
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
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
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
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
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
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
Custom Types Domain-specific code
type alias Dog = { name : String , age
: Int , breed : Breed } type Breed = Sheltie | Poodle
type alias Dog = { name : String , age
: Int , breed : Breed } type Breed = Sheltie | Poodle
type alias Dog = { name : String , age
: Int , breed : Breed } type Breed = Sheltie | Poodle Union Type
dog : Dog dog = { name = "Tucker" ,
age = 11 , breed = Sheltie }
dog : Dog dog = { name = "Tucker" ,
age = 11 , breed = Sheltie }
dog : Dog dog = { name = "Tucker" ,
age = 11 , breed = Sheltie }
dog : Dog dog = { name = "Tucker" ,
age = 11 , breed = Shelty } Misspelled. Won’t compile!
No null or undefined
type Maybe a = Just a | Nothing
type Maybe a = Just a | Nothing Wraps the
successful value
type Maybe a = Just a | Nothing Wraps the
successful value Type Variable
type Maybe a = Just a | Nothing Represents no
result or missing value
type Maybe a = Just a | Nothing Either I
have Just the value a, or I have Nothing.
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
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
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
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
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
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
case divide 4 2 of Just n -> "Result is
" ++ (toString n) Nothing -> "No Result"
case divide 4 2 of Just n -> "Result is
" ++ (toString n) Nothing -> "No Result"
case divide 4 2 of Just n -> "Result is
" ++ (toString n) Nothing -> "No Result"
case divide 4 2 of Just n -> "Result is
" ++ (toString n) Nothing -> "No Result"
case divide 4 2 of Just n -> "Result is
" ++ (toString n) -- Nothing -> -- "No Result"
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!
Update View Model Messages The Elm Architecture
model Update View
model Update View VDOM
model Update View
model Update View
model Update View
model Update View
model Update View
model Update View VDOM
Demos The Elm Architecture in Action
Getting Started • elm-lang.org • elm-lang.org/examples • guide.elm-lang.org • www.elm-tutorial.org
• builtwithelm.co • Slack • elmlang.herokuapp.com
Thanks! Jeremy Fairbank @elpapapollo / jfairbank Slides: bit.ly/scs-elm