Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Scenic City Summit 2017: Tame the frontend with...
Search
Jeremy Fairbank
July 28, 2017
Programming
0
170
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
200
CodeMash 2020: Solving the Boolean Identity Crisis
jfairbank
1
150
CodeMash 2020: Practical Functional Programming
jfairbank
1
320
Connect.Tech 2019: Practical Functional Programming
jfairbank
0
350
Connect.Tech 2019: Solving the Boolean Identity Crisis
jfairbank
0
180
Lambda Squared 2019: Solving the Boolean Identity Crisis
jfairbank
0
120
All Things Open 2018: Practical Functional Programming
jfairbank
2
260
Connect.Tech 2018: Effective React Testing
jfairbank
1
160
Fluent Conf 2018: Building web apps with Elm Tutorial
jfairbank
2
850
Other Decks in Programming
See All in Programming
Quand Symfony, ApiPlatform, OpenAI et LangChain s'allient pour exploiter vos PDF : de la théorie à la production…
ahmedbhs123
0
210
AI コーディングエージェントの時代へ:JetBrains が描く開発の未来
masaruhr
1
190
ソフトウェア品質を数字で捉える技術。事業成長を支えるシステム品質の マネジメント
takuya542
2
14k
Railsアプリケーションと パフォーマンスチューニング ー 秒間5万リクエストの モバイルオーダーシステムを支える事例 ー Rubyセミナー 大阪
falcon8823
5
1.1k
レベル1の開発生産性向上に取り組む − 日々の作業の効率化・自動化を通じた改善活動
kesoji
0
240
Team operations that are not burdened by SRE
kazatohiei
1
320
PicoRuby on Rails
makicamel
2
130
新メンバーも今日から大活躍!SREが支えるスケールし続ける組織のオンボーディング
honmarkhunt
5
7.7k
PHP 8.4の新機能「プロパティフック」から学ぶオブジェクト指向設計とリスコフの置換原則
kentaroutakeda
2
950
すべてのコンテキストを、 ユーザー価値に変える
applism118
3
1.4k
なぜ適用するか、移行して理解するClean Architecture 〜構造を超えて設計を継承する〜 / Why Apply, Migrate and Understand Clean Architecture - Inherit Design Beyond Structure
seike460
PRO
3
780
AIと”コードの評価関数”を共有する / Share the "code evaluation function" with AI
euglena1215
1
170
Featured
See All Featured
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
The Invisible Side of Design
smashingmag
301
51k
Docker and Python
trallard
44
3.5k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
126
53k
Done Done
chrislema
184
16k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
130
19k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.9k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.5k
Code Review Best Practice
trishagee
69
19k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
48
2.9k
Visualization
eitanlees
146
16k
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
[email protected]
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