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
1
110
Living Immutably with Ember
From idea to action, using immutability in Ember applications.
Charles Lowell
May 21, 2016
Tweet
Share
More Decks by Charles Lowell
See All by Charles Lowell
State Of Enjoyment
cowboyd
1
460
Microstates
cowboyd
1
86
Typeclasses in JavaScript
cowboyd
0
250
Big Testing in React
cowboyd
0
110
Wheel of Type
cowboyd
0
79
Immutability is for UI, You and I
cowboyd
3
830
Other Decks in Programming
See All in Programming
GISエンジニアから見たLINKSデータ
nokonoko1203
0
190
Canon EOS R50 V と R5 Mark II 購入でみえてきた最近のデジイチ VR180 事情、そして VR180 静止画に活路を見出すまで
karad
0
140
LLMで複雑な検索条件アセットから脱却する!! 生成的検索インタフェースの設計論
po3rin
4
980
生成AIを利用するだけでなく、投資できる組織へ
pospome
2
410
GoLab2025 Recap
kuro_kurorrr
0
780
マスタデータ問題、マイクロサービスでどう解くか
kts
0
140
tparseでgo testの出力を見やすくする
utgwkk
2
290
認証・認可の基本を学ぼう後編
kouyuume
0
250
Vibe codingでおすすめの言語と開発手法
uyuki234
0
130
[AtCoder Conference 2025] LLMを使った業務AHCの上⼿な解き⽅
terryu16
6
810
Implementation Patterns
denyspoltorak
0
130
脳の「省エネモード」をデバッグする ~System 1(直感)と System 2(論理)の切り替え~
panda728
PRO
0
120
Featured
See All Featured
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Code Review Best Practice
trishagee
74
19k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.3k
How Software Deployment tools have changed in the past 20 years
geshan
0
30k
ラッコキーワード サービス紹介資料
rakko
0
1.8M
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
130
Ethics towards AI in product and experience design
skipperchong
1
140
Documentation Writing (for coders)
carmenintech
77
5.2k
Everyday Curiosity
cassininazir
0
110
Reality Check: Gamification 10 Years Later
codingconduct
0
1.9k
New Earth Scene 8
popppiees
0
1.2k
The SEO identity crisis: Don't let AI make you average
varn
0
39
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