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
Codemash 2017: Toward a Better Front-end Archit...
Search
Jeremy Fairbank
January 12, 2017
Programming
1
320
Codemash 2017: Toward a Better Front-end Architecture: Elm
Jeremy Fairbank
January 12, 2017
Tweet
Share
More Decks by Jeremy Fairbank
See All by Jeremy Fairbank
Connect.Tech 2020: Advanced Cypress Testing
jfairbank
1
230
CodeMash 2020: Solving the Boolean Identity Crisis
jfairbank
1
170
CodeMash 2020: Practical Functional Programming
jfairbank
1
340
Connect.Tech 2019: Practical Functional Programming
jfairbank
0
390
Connect.Tech 2019: Solving the Boolean Identity Crisis
jfairbank
0
190
Lambda Squared 2019: Solving the Boolean Identity Crisis
jfairbank
0
150
All Things Open 2018: Practical Functional Programming
jfairbank
2
270
Connect.Tech 2018: Effective React Testing
jfairbank
1
190
Fluent Conf 2018: Building web apps with Elm Tutorial
jfairbank
2
890
Other Decks in Programming
See All in Programming
re:Invent 2025 のイケてるサービスを紹介する
maroon1st
0
170
PC-6001でPSG曲を鳴らすまでを全部NetBSD上の Makefile に押し込んでみた / osc2025hiroshima
tsutsui
0
210
2年のAppleウォレットパス開発の振り返り
muno92
PRO
0
180
PostgreSQLで手軽にDuckDBを使う!DuckDB&pg_duckdb入門/osc25hi-duckdb
takahashiikki
0
240
gunshi
kazupon
1
140
なぜSQLはAIぽく見えるのか/why does SQL look AI like
florets1
0
130
AIエージェントの設計で注意するべきポイント6選
har1101
6
3.1k
これならできる!個人開発のすゝめ
tinykitten
PRO
0
150
AIで開発はどれくらい加速したのか?AIエージェントによるコード生成を、現場の評価と研究開発の評価の両面からdeep diveしてみる
daisuketakeda
1
700
AI Agent Dojo #4: watsonx Orchestrate ADK体験
oniak3ibm
PRO
0
130
はじめてのカスタムエージェント【GitHub Copilot Agent Mode編】
satoshi256kbyte
0
160
生成AIを利用するだけでなく、投資できる組織へ
pospome
2
440
Featured
See All Featured
[SF Ruby Conf 2025] Rails X
palkan
0
710
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
0
180
A Soul's Torment
seathinner
4
2.1k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
We Are The Robots
honzajavorek
0
130
Testing 201, or: Great Expectations
jmmastey
46
7.9k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
A Tale of Four Properties
chriscoyier
162
24k
Balancing Empowerment & Direction
lara
5
840
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
300
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.3k
Transcript
TOWARD A BETTER |> FRONT END |> ARCHITECTURE elm Jeremy
Fairbank blog.jeremyfairbank.com tw: @elpapapollo / gh: jfairbank
sigient.com Your website, SimplyBuilt. simplybuilt.com
None
None
None
× two-way data binding mvc
× ✓ two-way data binding unidirectional mvc components
None
null undefined is not a function
let name = 'Jeremy'; export function getName() { return name;
} export function setName(newName) { name = newName; } Impure and Mutable
Unsafe APIs axios.get(`/user/${id}`) .then((user) => { console.log(user.name); }) .catch((error) =>
{ console.log(error); });
Unsafe APIs axios.get(`/user/${id}`) .then((user) => { console.log(user.name); }) .catch((error) =>
{ console.log(error); });
Error Handling function mayThrow() { throw new Error('Whoops...') } function
unsafe() { try { mayThrow(); } catch (e) { handleError(e); } } Call Stack ×
axios.get(`/user/${id}`) .then((user) => { console.log(user.name); }); Error Handling
axios.get(`/user/${id}`) .then((user) => { console.log(user.name); }); Error Handling catch?
elm
No runtime errors in practice. No null. No undefined is
not a function. - guide.elm-lang.org
confidence
confidence Static typing Expressive Terse Pure Unidirectional Architecture Immutable
functional
greet name = "Hello, " ++ name add x y
= x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
greet name = "Hello, " ++ name add x y
= x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
greet name = "Hello, " ++ name add x y
= x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
greet name = "Hello, " ++ name add x y
= x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
greet name = "Hello, " ++ name add x y
= x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
greet name = "Hello, " ++ name add x y
= x + y greet "Codemash" -- Hello, Codemash add 2 3 -- 5 functional
pure
pure add x y = x + y add 2
3 -- 5 add 2 3 -- 5 add 2 3 -- 5
pure add x y = x + y add 2
3 -- 5 add 2 3 -- 5 add 2 3 -- 5 Referentially Transparent
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
declarative Declare what the desired result is
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] declarative
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10] declarative
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10] declarative
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10] declarative
currying Creating building blocks
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
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
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
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
currying double n = n * 2 doubleNumbers list =
List.map double list
currying double n = n * 2 doubleNumbers = List.map
double
currying double = ((*) 2) doubleNumbers = List.map double
currying double = ((*) 2) doubleNumbers = List.map double
currying doubleNumbers = List.map ((*) 2)
list = List.range 1 10 square n = n *
n List.map square (List.filter ((<) 6) (List.map ((*) 2) list)) piping
list = List.range 1 10 square n = n *
n List.map square (List.filter ((<) 6) (List.map ((*) 2) list)) piping
piping list = List.range 1 10 square n = n
* n list |> List.map ((*) 2) |> List.filter ((<) 6) |> List.map square
piping list = List.range 1 10 square n = n
* n list |> List.map ((*) 2) |> List.filter ((<) 6) |> List.map square
|> List.map ((*) 2) |> List.filter ((<) 6) |> List.map
square piping list
|> List.map ((*) 2) |> List.filter ((<) 6) |> List.map
square piping list doubled = List.map ((*) 2) list
|> List.filter ((<) 6) |> List.map square piping doubled =
List.map ((*) 2) list doubled
|> List.filter ((<) 6) |> List.map square piping doubled =
List.map ((*) 2) list doubled filtered = List.filter ((<) 6) mapped
piping doubled = List.map ((*) 2) list filtered = List.filter
((<) 6) mapped |> List.map square filtered
piping doubled = List.map ((*) 2) list filtered = List.filter
((<) 6) mapped |> List.map square filtered squared = List.map square filtered
strong static typing Creating and adhering to contracts
life : Int life = 42 greeting : String greeting
= "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3] strong static typing
strong static typing greet : String -> String greet name
= "Hello, " ++ name add : Int -> Int -> Int add x y = x + y
strong static typing greet : String -> String greet name
= "Hello, " ++ name add : Int -> Int -> Int add x y = x + y
strong static typing greet : String -> String greet name
= "Hello, " ++ name add : Int -> Int -> Int add x y = x + y
strong static typing greet : String -> String greet name
= "Hello, " ++ name add : Int -> (Int -> Int) add x y = x + y
greet True add 2 "5"
dog : ( String, Int ) dog = ( "Tucker",
11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
dog : ( String, Int ) dog = ( "Tucker",
11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
dog : ( String, Int ) dog = ( "Tucker",
11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
dog : ( String, Int ) dog = ( "Tucker",
11 ) name = Tuple.first dog -- "Tucker" age = Tuple.second dog -- 11 tuples
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"
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"
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"
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"
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"
type alias Dog = { name : String , age
: Int , breed : String } dog : Dog dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } aliases
type alias Dog = { name : String , age
: Int , breed : String } dog : Dog dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } aliases
type alias Dog = { name : String , age
: Int , breed : String } dog : Dog dog = { name = "Tucker" , age = 11 , breed = "Sheltie" } aliases
aliases type alias Dog = { name : String ,
age : Int , breed : String } dog : Dog dog = Dog "Tucker" 11 "Sheltie"
immutable Create state, don’t mutate it
immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {
dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {
dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {
dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {
dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
immutable dog = Dog "Tucker" 11 "Sheltie" olderDog = {
dog | age = dog.age + 1 } dog.age -- 11 olderDog.age -- 12
union types type alias Dog = { name : String
, age : Int , breed : String }
union types type alias Dog = { name : String
, age : Int , breed : String }
type Breed = Sheltie | Corgi | GoldenRetriever | Mix
Breed Breed union types type alias Dog = { name : String , age : Int , breed : String }
type Breed = Sheltie | Corgi | GoldenRetriever | Mix
Breed Breed union types type alias Dog = { name : String , age : Int , breed : Breed }
type Breed = Sheltie | Corgi | GoldenRetriever | Mix
Breed Breed union types
type Breed = Sheltie | Corgi | GoldenRetriever | Mix
Breed Breed union types
type Breed = Sheltie | Corgi | GoldenRetriever | Mix
Breed Breed union types
type Breed = Sheltie | Corgi | GoldenRetriever | Mix
Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix
type Breed = Sheltie | Corgi | GoldenRetriever | Mix
Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix
type Breed = Sheltie | Corgi | GoldenRetriever | Mix
Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix
type Breed = Sheltie | Corgi | GoldenRetriever | Mix
Breed Breed dog1 = Dog "Tucker" 11 Sheltie dog2 = Dog "Sally" 5 Corgi dog3 = Dog "Rover" 1 Mix ?
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
null
type Maybe a = Just a | Nothing safety
type Maybe a = Just a | Nothing safety
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
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
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
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
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
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 half 4 of Just n -> "Result is "
++ (toString n)
Compiler REPL Dev Server built-in tooling Packages
built-in framework elm + vs.
architecture model-view-update unidirectional organized communication
elm app model
elm app model
elm app model
elm app model Commands HTTP Dates Random #’s
elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets
Browser Window Mouse Position
elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets
Browser Window Mouse Position Events Text Input Mouse Click
elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets
Browser Window Mouse Position Events Text Input Mouse Click Tasks
elm app model Commands HTTP Dates Random #’s Subscriptions WebSockets
Browser Window Mouse Position Events Text Input Mouse Click Tasks
elm app
elm app model
elm app model Update
elm app model Update View
model Update View elm
model Update View elm
model Update View elm
model Update View elm !
model Update View elm !
model Update View elm
model Update View elm
model Update View elm
model Update View elm
github.com/jfairbank/arch-elm Demo
THANKS! Jeremy Fairbank blog.jeremyfairbank.com tw: @elpapapollo / gh: jfairbank |>
elm-lang.org |> guide.elm-lang.org |> github.com/jfairbank/arch-elm