TOWARD A BETTER|> FRONT END|> ARCHITECTUREelmJeremy Fairbankblog.jeremyfairbank.comtw: @elpapapollo / gh: jfairbank
View Slide
sigient.comYour website, SimplyBuilt.simplybuilt.com
×two-waydata bindingmvc
×✓two-waydata bindingunidirectionalmvccomponents
nullundefined is not a function
let name = 'Jeremy';export function getName() {return name;}export function setName(newName) {name = newName;}Impure and Mutable
Unsafe APIsaxios.get(`/user/${id}`).then((user) => {console.log(user.name);}).catch((error) => {console.log(error);});
Error Handlingfunction 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 Handlingcatch?
elm
No runtime errors in practice.No null.No undefined is not a function.- guide.elm-lang.org
confidence
confidenceStatic typingExpressiveTersePureUnidirectionalArchitectureImmutable
functional
greet name = "Hello, " ++ nameadd x y = x + ygreet "Codemash" -- Hello, Codemashadd 2 3 -- 5functional
pure
pureadd x y =x + yadd 2 3 -- 5add 2 3 -- 5add 2 3 -- 5
pureadd x y =x + yadd 2 3 -- 5add 2 3 -- 5add 2 3 -- 5ReferentiallyTransparent
function fetchUser(id) {const url = `/user/${id}`;return axios.get(url);}pure✓×fetchUser id =leturl = "/user/" ++ (toString id)request = Http.get url userDecoderinHttp.send LoadUser request
declarativeDeclare what thedesired 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 * 2doubleNumbers list =List.map double listdoubleNumbers myList -- [2, 4, 6, 8, 10]declarative
curryingCreating buildingblocks
curryingadd x y z = x + y + zadd 1 2 3 -- 6((add 1) 2) 3 -- 6add1 = add 1add3 = add1 2add1 2 3 -- 6add3 3 -- 6
curryingdouble n = n * 2doubleNumbers list =List.map double list
curryingdouble n = n * 2doubleNumbers =List.map double
curryingdouble = ((*) 2)doubleNumbers =List.map double
currying doubleNumbers =List.map ((*) 2)
list = List.range 1 10square n = n * nList.map square (List.filter ((<) 6) (List.map ((*) 2) list))piping
pipinglist = List.range 1 10square n = n * nlist|> List.map ((*) 2)|> List.filter ((<) 6)|> List.map square
|> List.map ((*) 2)|> List.filter ((<) 6)|> List.map squarepipinglist
|> List.map ((*) 2)|> List.filter ((<) 6)|> List.map squarepipinglistdoubled = List.map ((*) 2) list
|> List.filter ((<) 6)|> List.map squarepipingdoubled = List.map ((*) 2) listdoubled
|> List.filter ((<) 6)|> List.map squarepipingdoubled = List.map ((*) 2) listdoubledfiltered = List.filter ((<) 6) mapped
pipingdoubled = List.map ((*) 2) listfiltered = List.filter ((<) 6) mapped|> List.map squarefiltered
pipingdoubled = List.map ((*) 2) listfiltered = List.filter ((<) 6) mapped|> List.map square filteredsquared = List.map square filtered
strong static typingCreating and adheringto contracts
life : Intlife = 42greeting : Stringgreeting = "Hello World"isTrue : BoolisTrue = Truenumbers : List Intnumbers = [1, 2, 3]strongstatictyping
strongstatictypinggreet : String -> Stringgreet name ="Hello, " ++ nameadd : Int -> Int -> Intadd x y =x + y
strongstatictypinggreet : String -> Stringgreet name ="Hello, " ++ nameadd : Int -> (Int -> Int)add x y =x + y
greet Trueadd 2 "5"
dog : ( String, Int )dog = ( "Tucker", 11 )name = Tuple.first dog -- "Tucker"age = Tuple.second dog -- 11tuples
recordsdog : { name : String, age : Int, breed : String }dog ={ name = "Tucker", age = 11, breed = "Sheltie"}dog.name -- "Tucker"dog.age -- 11dog.breed -- "Sheltie".name dog -- "Tucker"
type alias Dog ={ name : String, age : Int, breed : String}dog : Dogdog ={ name = "Tucker", age = 11, breed = "Sheltie"}aliases
aliasestype alias Dog ={ name : String, age : Int, breed : String}dog : Dogdog = Dog "Tucker" 11 "Sheltie"
immutableCreate state, don’tmutate it
immutabledog = Dog "Tucker" 11 "Sheltie"olderDog = { dog | age = dog.age + 1 }dog.age -- 11olderDog.age -- 12
union typestype alias Dog ={ name : String, age : Int, breed : String}
type Breed= Sheltie| Corgi| GoldenRetriever| Mix Breed Breedunion typestype alias Dog ={ name : String, age : Int, breed : String}
type Breed= Sheltie| Corgi| GoldenRetriever| Mix Breed Breedunion typestype alias Dog ={ name : String, age : Int, breed : Breed}
type Breed= Sheltie| Corgi| GoldenRetriever| Mix Breed Breedunion types
type Breed= Sheltie| Corgi| GoldenRetriever| Mix Breed Breeddog1 = Dog "Tucker" 11 Sheltiedog2 = Dog "Sally" 5 Corgidog3 = Dog "Rover" 1 Mix
type Breed= Sheltie| Corgi| GoldenRetriever| Mix Breed Breeddog1 = Dog "Tucker" 11 Sheltiedog2 = Dog "Sally" 5 Corgidog3 = Dog "Rover" 1 Mix?
dog1 = Dog "Tucker" 11 Sheltiedog2 = Dog "Sally" 5 Corgidog3 = Dog "Rover" 1 (Mix Sheltie Corgi)type Breed= Sheltie| Corgi| GoldenRetriever| Mix Breed Breed
null
type Maybe a= Just a| Nothingsafety
divide : number -> number -> Maybe Floatdivide x y =if y == 0 thenNothingelseJust (x / y)divide 4 2 -- Just 2divide 4 0 -- Nothing
case divide 4 2 ofJust n ->"Result is " ++ (toString n)Nothing ->"No Result"
case half 4 ofJust n ->"Result is " ++ (toString n)
CompilerREPLDev Serverbuilt-intoolingPackages
built-inframeworkelm+vs.
architecturemodel-view-updateunidirectionalorganized communication
elmappmodel
elmappmodelCommandsHTTPDatesRandom #’s
elmappmodelCommandsHTTPDatesRandom #’sSubscriptionsWebSocketsBrowser WindowMouse Position
elmappmodelCommandsHTTPDatesRandom #’sSubscriptionsWebSocketsBrowser WindowMouse PositionEventsText InputMouse Click
elmappmodelCommandsHTTPDatesRandom #’sSubscriptionsWebSocketsBrowser WindowMouse PositionEventsText InputMouse Click Tasks
elmapp
elmappmodelUpdate
elmappmodelUpdateView
modelUpdate Viewelm
modelUpdate Viewelm!
github.com/jfairbank/arch-elmDemo
THANKS!Jeremy Fairbankblog.jeremyfairbank.comtw: @elpapapollo / gh: jfairbank|> elm-lang.org|> guide.elm-lang.org|> github.com/jfairbank/arch-elm