Abstracting
Just
Enough
James Long, @jlongster
ReactiveConf 2015
Refactoring
SUCKS
Inherent
Incidental
vs
Benefits > Cost
Start Simple
Relearn Requirements
Build Up Slowly
Core Principals
• Must be composable
• Must be testable
• Must be debuggable
• Must be live-reloadable
Is it stateful?
function User(name, numEyes) {
this.name = name;
this.numEyes = numEyes;
}
User.prototype.isScary = function() {
return this.numEyes !== 2;
}
new User("James", 2).isScary()
ENCOURAGES
mutation
function isScary(user) {
return user.numEyes !== 2;
}
isScary({ name: "James", numEyes: 2 });
isScary(
immutable({ name: "James", numEyes: 2 })
);
function isScary(user) {
return user.numEyes !== 2;
}
What We Need
• Render the UI
• Manage State
• Asynchronous Work
• Testing
Where We Are
• DOM mutations
• State in DOM, custom JS classes, etc
• Promises and events everywhere
• Very few unit tests
Where We Want to Go
• Declarative UI
• Central App State
• Async work with atomic UI updates
• Unit tests
React Declarative UI
Components
No DOM Needed
ReduxFlux-style Actions
Central App State
Action Creators
UIDATA EVENTS
function App({ items }) {
return (
<ul>
{items.map(item => <li>{item}</li>)}
</ul>
);
}
UI
EVENTS
STATE
{ items: ["James", "Sarah", "Evelina"] }
UISTATE
ACTION
CREATOR
ACTION
function addItem(name) {
return {
type: ADD_ITEM,
name: name
}
}
{ type: ADD_ITEM,
name: name }
State Snapshotting
Log & Replay Actions
Asynchronous Work?
UISTATE
ACTION
CREATOR
ACTION
ACTION
CREATOR
STATE UI
ACTION
STATE UI
ACTION
Action Creators
Time
0ms
100ms
ACTION
CREATOR
STATE UI
STATE UI
ACTION
ACTION
Action Creators
Time
0ms
100ms
Time
0ms
1000ms
STATE UI
STATE UI
Action Creators
ACTION
CREATOR
ACTION
CREATOR
ACTION
CREATOR
STATE UI
STATE UI
STATE UI
STATE UI
“UIs are inherently
asynchronous”
-Everybody
Nope
Time
0ms
100ms
STATE UI
STATE UI
ACTION
CREATOR
ACTION
CREATOR
ACTION
CREATOR
STATE UI
STATE UI
STATE UI
STATE UI
Sync
How we interact with
UIs is asynchronous
Time
0ms
100ms
STATE UI
STATE UI
ACTION
CREATOR
ACTION
CREATOR
ACTION
CREATOR
STATE UI
STATE UI
STATE UI
STATE UI
SyncAsync
Time
0ms
100ms
STATE UI
STATE UI
STATE UI
STATE UI
STATE UI
STATE UI
SyncAsync
PROMISE
OBSERVABLE
CHANNEL
Time
0ms
100ms
STATE UI
STATE UI
STATE UI
STATE UI
STATE UI
STATE UI
SyncAsync
Relay/Falcor
dispatch({
type: ADD_ITEM,
status: "start",
name: "James"
})
// UI Rendered!!
function addItem(name) {
return dispatch => {
dispatch({
type: ADD_ITEM,
status: "start",
name: name
});
setTimeout(() => {
dispatch({
type: ADD_ITEM,
status: "finish",
name: name
})
}, 100);
}
}
const { PROMISE } = require('<promise-middleware>');
function addItem(name) {
return {
type: ADD_ITEM,
name: name,
[PROMISE]: api.addItem(name)
};
}
You might not need
promises
observables
etc
Testing
• State updates: simple functions
• React components: basically simple

functions
• Action creators: simple async functions
Testing Ideas
• Recording workflows
• Generative & property-based testing
Core Principals
• Must be composable
• Must be testable
• Must be debuggable
• Must be live-reloadable
Solved!
• Use simple functions as much as possible
• Single, central state
Thanks!@jlongster

Abstracting Just Enough