Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Living Immutably with Ember
Search
Charles Lowell
May 21, 2016
Programming
120
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Living Immutably with Ember
From idea to action, using immutability in Ember applications.
Charles Lowell
May 21, 2016
More Decks by Charles Lowell
See All by Charles Lowell
State Of Enjoyment
cowboyd
1
520
Microstates
cowboyd
1
90
Typeclasses in JavaScript
cowboyd
0
260
Big Testing in React
cowboyd
0
120
Wheel of Type
cowboyd
0
86
Immutability is for UI, You and I
cowboyd
3
850
Other Decks in Programming
See All in Programming
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
7
2.3k
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
130
iOSDC2026登壇資料.pdf
riofujimon
0
200
Security issues being discussed on Web Platforms
petamoriken
0
1.4k
Workers Cache を知る
syumai
0
320
SREの越境 / SRE Collaboration
y0hgi
2
290
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
520
Embedded Swiftで作る自作USBデバイス によるiOSデバイスの自動テスト / iOSDC Japan 2026 glassfiber
glassfiber
0
260
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
370
App Intentsのビルドプロセスを支える技術
kntkymt
0
490
setup-vp GitLab対応の裏側
naokihaba
0
150
Featured
See All Featured
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.5k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
900
How GitHub (no longer) Works
holman
316
150k
SEO for Brand Visibility & Recognition
aleyda
0
4.8k
Designing Experiences People Love
moore
143
24k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
560
Game over? The fight for quality and originality in the time of robots
wayneb77
1
290
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
Facilitating Awesome Meetings
lara
57
7.2k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
620
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
Transcript
None
Code
Handwaving
Codewaving
I Said • Don’t use a component’s properties in its
template • Don’t use computed properties • Don’t use Ember.Object at all
But the Devil is in the Details Code
Living Immutably @cowboyd GEMConf SF 2016
Why vs How
So What’s the Big Idea?
Content First
Content as Stream
Model Content as Stream
Independent Frames
One Experience
Going Practical Implementing a File Upload
UX the movie
UX the movie
UX the content
An Upload at Rest
Start State isStarted: false isEnded: false file: null progress: 0
UX the state { isStarted: false, isEnded: false, file: null,
progress: 0 } ??? Start
A Wild File Object Appears { isStarted: false, isEnded: false,
file: null, progress: 0 } selectFile(File) Start
New Target Acquired
Uploading State isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0
UX the state { isStarted: false, isEnded: false, file: null,
progress: 0 } selectFile(File) Start { isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0 } Uploading ???
Progress is Made isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress:
0 Uploading progress(Event)
Uploading Pt 2 isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress:
0.75
UX the state { isStarted: false, isEnded: false, file: null,
progress: 0 } selectFile(File) Start { isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0 } Uploading { isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0.75 } Uploading ??? progress(Event)
Final Count Down isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress:
0.75 Uploading loadend()
Success isStarted: true, isEnded: true, file: File(‘puppies.gif’), progress: 1
UX the state { isStarted: false, isEnded: false, file: null,
progress: 0 } selectFile(File) Start { isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0 } Uploading { isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0.75 } Uploading progress(Event) { isStarted: true, isEnded: true, file: File(), progress: 1 } loadend() Success
Code Timeout (a moment for us)
Content First
UX the state { isStarted: false, isEnded: false, file: null,
progress: 0 } selectFile(File) Start { isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0 } Uploading { isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0.75 } Uploading progress(Event) { isStarted: true, isEnded: true, file: File(), progress: 1 } loadend() Success
Start Uploading Success selectFile(File) progress(Event) loadend() UX the state machine
A Radical New Framework for describing immutable states
Ecma Script 6
Start Uploading Success selectFile(File) progress(Event) loadend() Turn this into ES6
Start Start at the beginning
Start the JavaScripts! class Start { constructor() { this.isStarted =
false; this.isEnded = false; this.file = null; this.progress = 0; } }
Start State isStarted: false isEnded: false file: null progress: 0
JavaScript representation class Start { constructor() { this.isStarted = false;
this.isEnded = false; this.file = null; this.progress = 0; } }
Start Uploading selectFile(File) Where do we go from here?
Transition method class Start { constructor() { this.isStarted = false;
this.isEnded = false; this.file = null; this.progress = 0; } selectFile(file) { return new Uploading(file); } }
Transition method • Never updates existing state • Always returns
a new state
Start Uploading selectFile(File) Transition to Uploading
Transition method class Start { constructor() { this.isStarted = false;
this.isEnded = false; this.file = null; this.progress = 0; } selectFile(file) { return new Uploading(file); } }
Uploading representation class Uploading { constructor(file, progress = 0) {
this.isStarted = true; this.isEnded = false; this.file = file; this.progress = progress; } }
Uploading State isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0
Uploading Success progress(Event) loadend() Uploading two ways out
Uploading representation class Uploading { constructor(file, progress = 0) {
this.isStarted = true; this.isEnded = false; this.file = file; this.progress = progress; } loaded() { return new Success(this.file); } progress(event) { let ratio = event.loaded / event.total) return new Uploading(this.file, ratio); } }
That’s some Code
Start Uploading Success selectFile(File) progress(Event) loadend() Your JavaScript
Building a Player
A Player • tracks the current frame of content •
maps events from the user into state transitions • maps events from external sources like the network
Playing with Ember
There are a lot of options right now
export default Ember.Component.extend({ url: 'https://posttestserver.com', model: new Start(), actions: {
fileChosen(file) { this.set('model', this.get('model').selectFile(file)); let xhr = this.xhr = new XMLHttpRequest(); xhr.upload.onprogress = (event)=> { this.set('model', this.get('model').progress(event)); }; xhr.onload = ()=> { this.set('model', this.get('model').sucess()); }; xhr.open('POST', this.get('url'), true); xhr.send(file); } } }); A Player Component
export default Ember.Component.extend({ url: 'https://posttestserver.com', model: new Start(), actions: {
fileChosen(file) { this.set('model', this.get('model').selectFile(file)); let xhr = this.xhr = new XMLHttpRequest(); xhr.upload.onprogress = (event)=> { this.set('model', this.get('model').progress(event)); }; xhr.onload = ()=> { this.set('model', this.get('model').sucess()); }; xhr.open('POST', this.get('url'), true); xhr.send(file); } } }); A Player Component
Explore Techniques
Content is King — Bill Gates
UX the movie
UX the movie
UX the state { isStarted: false, isEnded: false, file: null,
progress: 0 } selectFile(File) Start { isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0 } Uploading { isStarted: true, isEnded: false, file: File(‘puppies.gif’), progress: 0.75 } Uploading progress(Event) { isStarted: true, isEnded: true, file: File(), progress: 1 } loadend() Success
Start Uploading Success selectFile(File) progress(Event) loadend() UX the state machine
ES6 Classes class Uploading { constructor(file, progress = 0) {
this.isStarted = true; this.isEnded = false; this.file = file; this.progress = progress; } loaded() { return new Success(this.file); } progress(event) { let ratio = event.loaded / event.total) return new Uploading(this.file, ratio); } }
Content is King — Bill Gates
Thanks