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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Charles Lowell
May 21, 2016
Programming
110
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
500
Microstates
cowboyd
1
88
Typeclasses in JavaScript
cowboyd
0
260
Big Testing in React
cowboyd
0
120
Wheel of Type
cowboyd
0
82
Immutability is for UI, You and I
cowboyd
3
850
Other Decks in Programming
See All in Programming
net-httpのHTTP/2対応について
naruse
0
470
Old Dog, New Tricks: The Java 25 Reinvention - JNation
bazlur_rahman
0
150
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
250
A2UI という光を覗いてみる
satohjohn
1
120
Dataformのリポジトリを立ち上げるときにまずやること / dataform-day0-2026
snhryt
0
150
Oxlintのカスタムルールの現況
syumai
6
1.1k
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
700
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
3.6k
AutonomyとControlのあいだ:Graflowで記述するAIエージェント協調
myui
0
120
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
2
200
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
560
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
130
Featured
See All Featured
The Language of Interfaces
destraynor
162
27k
Designing for Timeless Needs
cassininazir
1
250
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
360
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
0
1.7k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.7k
The SEO Collaboration Effect
kristinabergwall1
1
480
So, you think you're a good person
axbom
PRO
2
2.1k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.5k
Google's AI Overviews - The New Search
badams
0
1k
Crafting Experiences
bethany
1
170
HDC tutorial
michielstock
2
700
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
330
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