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
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
510
Microstates
cowboyd
1
89
Typeclasses in JavaScript
cowboyd
0
260
Big Testing in React
cowboyd
0
120
Wheel of Type
cowboyd
0
84
Immutability is for UI, You and I
cowboyd
3
850
Other Decks in Programming
See All in Programming
20260722_microCMSで考える、AI時代のコンテンツ運用設計
yosh1
0
190
Lean は証明の正しさを確認するためだけのツールって思ってませんか?
inoueasei
1
130
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
180
AI時代の仕事技芸論〜ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ(スクフェス仙台 2026バージョン)
kuranuki
0
790
Build-to-own AI: Agentic Development for Humans
inesmontani
PRO
0
160
全PRの83%がAIレビューだけでマージできるようになった開発組織はその後どうなったか
athug
0
1k
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
140
ここ半年くらいでAIに作らせたR用ツール
eitsupi
0
360
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
3.3k
今さら聞けない .NET CLI
htkym
0
170
Embedded SREと共に達成した会員管理システムのAWS移行 - SRE NEXT 2026 ランチスポンサーセッション
niftycorp
PRO
1
3.3k
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
9
5.9k
Featured
See All Featured
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
560
From π to Pie charts
rasagy
0
240
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
240
Evolving SEO for Evolving Search Engines
ryanjones
0
250
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
680
A Soul's Torment
seathinner
6
3.1k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
The untapped power of vector embeddings
frankvandijk
2
1.8k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
Context Engineering - Making Every Token Count
addyosmani
9
1k
What's in a price? How to price your products and services
michaelherold
247
13k
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