Date post: | 13-Apr-2017 |
Category: |
Technology |
Upload: | joe-morgan |
View: | 370 times |
Download: | 1 times |
ES6 Patterns in the Wild
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; }
const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
Code to Run (wild code)
Code to Run (wild code)
Code we write Code we import
Code to Run (wild code)
Code we write Code we import$$
Code to Teach
Code to Teach
Tutorials
Code to Teach
Tutorials
Documentation
Style Guides
Stack Overflow
BooksConferences
Code to Teach
Tutorials
Documentation
Style Guides
Stack Overflow
BooksConferences
Good Stuff
Syntax
SELECT ID, NAME, AGE, AMOUNT FROM CUSTOMERS, ORDERS WHERE CUSTOMERS.ID = ORDERS.CUSTOMER_ID;
Unreadable
Pattern
Complexity
What we expect
What we get
Code to Teach Code to Run
Code to Teach Code to Run
Simple
Complex
Complex
Simple
Joe Morgan
Lawrence, KS
I Write Code
Joe Morgan
Joe Morgan
Read
Joe Morgan
ReadRead
Critically
Reading Code
Redux
{ donuts: [ “chocolate”, ], filter: null }
state.donuts.map(donut => { return ( <h2> {{donut}} </h2> ) })
<h2> Chocolate </h2>
State Component
{ donuts: [ “chocolate”, ], filter: null }
state.donuts.map(donut => { return ( <h2> {{donut}} </h2> ) })
<h2> Chocolate </h2>
State Component
dispatch(addDonut(‘maple’))
{ donuts: [ “chocolate”, “maple”, ], filter: null }
state.donuts.map(donut => { return ( <h2> {{donut}} </h2> ) })
<h2> Chocolate </h2>
State Component
dispatch(addDonut(‘maple’))
updated state
{ donuts: [ “chocolate”, “maple”, ], filter: null }
state.donuts.map(donut => { return ( <h2> {{donut}} </h2> ) })
<h2> Chocolate </h2>
State Component
dispatch(addDonut(‘maple’))
updated state
{ donuts: [ “chocolate”, “maple”, ], filter: null }
state.donuts.map(donut => { return ( <h2> {{donut}} </h2> ) })
<h2> Chocolate </h2> <h2> Maple </h2>
State Component
dispatch(addDonut(‘maple’))
Redux
Functional Array Methods High Order Functions Curry/Partially Applied Functions
Redux
updated state
{ donuts: [ “chocolate”, “maple”, ], filter: null }
state.donuts.map(donut => { return ( <h2> {{donut}} </h2> ) }
<h2> Chocolate </h2> <h2> Maple </h2>
State Component
dispatch(addDonut(‘maple’))
Middleware
Middleware
import compose from './compose'
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, enhancer) var dispatch = store.dispatch var chain = []
var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)
return { ...store, dispatch } } }
import compose from './compose'
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI))
} }
Arrow Functions
import compose from './compose'
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI))
} }
import compose from './compose'
export default function applyMiddleware(...middlewares) { return function(createStore) { return function (reducer, preloadedState, enhancer) { var middlewareAPI = { getState: store.getState, dispatch: function (action) { return dispatch(action); } } chain = middlewares.map(function(middleware) { return middleware(middlewareAPI) }) } } }
import compose from './compose'
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI))
} }
chain = middlewares.map(middleware => middleware(middlewareAPI))
chain = middlewares.map(middleware => middleware(middlewareAPI))
chain = middlewares.map((middleware) => {return middleware(middlewareAPI)})
var that = this;
var namer = { name: 'bill', say: function() { var that = this console.log(this.name); setTimeout(function() { console.log(that.name); },200); } }
var that = this;
const namer = { name: 'bill', say: function() { console.log(this.name); setTimeout(() => { console.log(this.name); },200); } }
Favor Arrow Functions
Why Read Wild Code?
i. Reading Code is a Skill
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; }
const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
i. Reading Code is a Skill: Intuition
i. Reading Code is a Skill: Intuition
i. Reading Code is a Skill: Intuition
Redux Rest/Spread
export default function applyMiddleware(...middlewares) { // Lots of stuff chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) } }
export default function applyMiddleware(...middlewares) { // Lots of stuff chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) } }
(I actually didn’t realize they had different names)
Redux Rest/Spread
Rest: list => array
export default function applyMiddleware(...middlewares) { // Lots of stuff chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) } }
export default function applyMiddleware(...middlewares)
examples/real-world/src/store/configureStore.dev.js
applyMiddleware(thunk, api, createLogger())
examples/real-world/src/store/configureStore.prod.js
applyMiddleware(thunk, api)
Redux Rest/Spread
Spread: array => list
export default function applyMiddleware(...middlewares) { dispatch = compose(...chain)(store.dispatch)
examples/real-world/src/store/configureStore.dev.js compose(thunk, api, createLogger())(store.dispatch)
examples/real-world/src/store/configureStore.prod.js compose(thunk, api)(store.dispatch)
Redux Rest/Spread
Convert items to arrays
export default function applyMiddleware(...middlewares) { // Lots of stuff
chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) } }
export default function applyMiddleware(...middlewares) { // Lots of stuff var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) } }
Redux Rest/Spread
Converting array to a new array without mutations
describe('combineReducers', () => { it('returns a composite reducer that maps the state keys to given reducers', () => { const reducer = combineReducers({ ... action.type === 'push' ? [ ...state, action.value ] : state })
describe('combineReducers', () => { it('returns a composite reducer that maps the state keys to given reducers', () => { const reducer = combineReducers({ ... action.type === 'push' ? [ ...state, action.value ] : state })
const family = [ { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, { name: 'Dyan', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
const family = [ { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, { name: 'Dyan', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
> family.sort(sortAge);
const family = [ { name: 'Theo', age: 1 }, { name: 'Joe', age: 34 }, { name: 'Dyan', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
[ { name: 'Theo', age: 1 }, { name: 'Joe', age: 34 }, { name: 'Dyan', age: 34 }, ]
const family = [ { name: 'Theo', age: 1 }, { name: 'Joe', age: 34 }, { name: 'Dyan', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
const family = [ { name: 'Theo', age: 1 }, { name: 'Joe', age: 34 }, { name: 'Dyan', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
> family.sort(sortName);
const family = [ { name: 'Dyan', age: 34 }, { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
[ { name: 'Dyan', age: 34 }, { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, ]
const family = [ { name: 'Dyan', age: 34 }, { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
const family = [ { name: 'Dyan', age: 34 }, { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
> family.sort(sortAge);
const family = [ { name: 'Theo', age: 1 }, { name: 'Dyan', age: 34 }, { name: 'Joe', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
[ { name: 'Theo', age: 1 }, { name: 'Dyan', age: 34 }, { name: 'Joe', age: 34 }, ]
const family = [ { name: 'Theo', age: 1 }, { name: 'Dyan', age: 34 }, { name: 'Joe', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
const family = [ { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, { name: 'Dyan', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
const family = [ { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, { name: 'Dyan', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
> [...family].sort(sortAge);
const family = [ { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, { name: 'Dyan', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
[ { name: 'Theo', age: 1 }, { name: 'Joe', age: 34 }, { name: 'Dyan', age: 34 }, ]
const family = [ { name: 'Joe', age: 34 }, { name: 'Theo', age: 1 }, { name: 'Dyan', age: 34 }, ]
const sortName = (a,b) => { return a.name > b.name ? 1 : -1 }
const sortAge = (a, b) => { if(a.age === b.age) { return 0; }
return a.age > b.age ? 1 : -1 }
ii. Your code will reflect your reading
ii. Your code will reflect your reading
data structures architecture community standards
ii. Your code will reflect your reading
It’s ok to take ideas from others
ii. Your code will reflect your reading
import compose from './compose'
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, enhancer) var dispatch = store.dispatch var chain = []
var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)
return { ...store, dispatch } } }
import compose from './compose'
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, enhancer) var dispatch = store.dispatch var chain = []
var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)
return { ...store, dispatch } } }
Redux Object Spread
Not part of ES6
//.babelrc { "plugins": [ ... "transform-object-rest-spread", ], ... }
Favor Arrow Functions
Favor Array Methods (map, reduce, find, filter)
Collecting items to arrays +
Arrow Functions =
Happiness
Khan Academy
Khan Academy
Consumer code. Not a library.
Khan Academy
Khan Academy
Object Oriented Complexity hidden behind interface Popular in typescript (angular 2) world
export default class Expression extends Node { constructor(...nodes) { super(); this.type = 'Expression'; this.children = new List(this, ...nodes); }
toString() { return `${this.type}:${this.children.toString()}`; }
toJSON() { return { ...super.toJSON(), children: [...f(this.children).map(child => child.toJSON())], }; }
clone(uniqueId = false) { ...
export default class Expression extends Node { constructor(...nodes) { super(); this.type = 'Expression'; this.children = new List(this, ...nodes); }
toString() { return `${this.type}:${this.children.toString()}`; }
toJSON() { return { ...super.toJSON(), children: [...f(this.children).map(child => child.toJSON())], }; }
clone(uniqueId = false) { ...
export default class Expression extends Node { constructor(...nodes) { super(); this.type = 'Expression'; this.children = new List(this, ...nodes); }
toString() { return `${this.type}:${this.children.toString()}`; }
toJSON() { return { ...super.toJSON(), children: [...f(this.children).map(child => child.toJSON())], }; }
clone(uniqueId = false) { ...
iii. Feature Popularity
iii. Feature Popularity: Frequency
The more useful the feature the more frequent it will pop up.
iii. Feature Popularity: Frequency
In Shakespeare:
The top 10 most frequently occuring words make up 21.4% of all words. The top 100 most frequently occuring words make up 53.9% of all words.
export default class Expression extends Node { constructor(...nodes) { super(); this.type = 'Expression'; this.children = new List(this, ...nodes); }
toString() { return `${this.type}:${this.children.toString()}`; }
toJSON() { return { ...super.toJSON(), children: [...f(this.children).map(child => child.toJSON())], }; }
clone(uniqueId = false) { ...
export default class Expression extends Node { constructor(...nodes) { super(); this.children = new List(this, ...nodes); }
toString() { return `${this.type}:${this.children.toString()}`; }
get last() { return this.children.last; }
set last(value) { this.children.last = value; } }
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 3 } } }
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 3 } } }
Linked List
Khan Academy
export default class Expression extends Node {
get last() { return this.children.last; }
set last(value) { this.children.last = value; }
}
Get/Set treats methods like properties (popular in
typescript)
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 3 } } }
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 3 } } }
e.last;
// { id: 3 }
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 3 } } }
e.last = { id.4 }
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 4 } } }
e.last = { id.4 }
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 4 } } }
e.last = { id.4 }
export default class Expression extends Node {
get last() { return this.children.last; }
set last(value) { this.children.last = value; }
}
export default class Expression extends Node {
get last() { return Object.assign( {}, { name:'last' }, this.children.last ); }
set last(value) { this.children.last = value; }
}
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 3 } } }
e.last
{ name: ‘last’, id: 3, }
export default class Expression extends Node { constructor(...nodes) { super(); this.children = new List(this, ...nodes); }
toString() { return `${this.type}:${this.children.toString()}`; }
get first() { return this.children.first; }
set first(value) { this.children.first = value; } }
export default class Expression extends Node {
toString() { return `${this.type}:${this.children.toString()}`; }
}
export default class Expression extends Node {
toString() { return this.type + ':' + this.children.toString(); }
}
export default class List extends Node { ... toString() { let first = true; for (let node of this) { if (!first) { result += ", "; } else { first = false; } result += node.id; } return result; } }
export default class List extends Node { ... toString() { let first = true; for (let node of this) { // Do Stuff with node.id } } }
export default class List extends Node { ... toString() { let first = true; for (let node of this) { // Do Stuff with node.id } } }
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 3 } } }
const presentation = [ 'ES6 Patterns in the Wild', 'Joe Morgan', ]
for(let metadata of presentation) { console.log(metadata); }
const presentation = [ 'ES6 Patterns in the Wild', 'Joe Morgan', ]
for(let metadata of presentation) { console.log(metadata); }
// ES 6 Patterns in the Wild // Joe Morgan
const presentation = { title: 'ES6 Patterns in the Wild', author: 'Joe Morgan', }
for(let metadata of presentation) { console.log(metadata); }
const presentation = { title: 'ES6 Patterns in the Wild', author: 'Joe Morgan', }
for(let metadata of presentation) { console.log(metadata); }
> TypeError: presentation[Symbol.iterator] is not a function
export default class List { ... *[Symbol.iterator]() { let node = this.first; while (node != this.last) { let current = node; node = node.next; yield current; } if (this.last) { yield this.last; } } }
export default class List { ... *[Symbol.iterator]() { let node = this.first; while (node != this.last) { let current = node; node = node.next; yield current; } if (this.last) { yield this.last; } } }
iii. Feature Popularity: Not all features end up being popular
iii. Feature Popularity: Not all features end up being popular
export default class List { ... *[Symbol.iterator]() { let node = this.first; while (node != this.last) { let current = node; node = node.next; yield current; } if (this.last) { yield this.last; } } }
const e = new Expression({id:1}, {id:2}, {id:3}) e = { children: { first: { id: 1, next: { id: 2, next: { id: 3 } } }, last: { id: 3 } } }
const e = new Expression({id:1}, {id:2}, {id:3})
e = [{id:1}, {id:2}, {id:3}]
Khan Academy
Create Simple Interfaces
React
React
Performance
canUseCollections = ( ... typeof Map === 'function' && isNative(Map) && ... );
if (canUseCollections) { var itemMap = new Map(); var rootIDSet = new Set();
setItem = function(id, item) { itemMap.set(id, item); }; getItem = function(id) { return itemMap.get(id); }; ... }
else { var itemByKey = {}; var rootByKey = {}; var getKeyFromID = () => {} var getIDFromKey = () => {}
setItem = function(id, item) { var key = getKeyFromID(id); itemByKey[key] = item; }; getItem = function(id) { var key = getKeyFromID(id); return itemByKey[key]; }; ... }
const presentation = { title: 'ES6 Patterns in the Wild', author: 'Joe Morgan', }
> presentation.title // 'ES6 Patterns in the Wild'
const presentation = { title: 'ES6 Patterns in the Wild', author: 'Joe Morgan', }
> presentation.title // 'ES6 Patterns in the Wild'
const presentation = new Map();
presentation.set('title', 'ES6 Patterns in the Wild');
presentation.set('author', 'Joe Morgan');
> presentation.get('title'); // 'ES6 Patterns in the Wild'
const presentation = new Map() .set('title', 'ES6 Patterns in the Wild') .set('author', 'Joe Morgan');
> presentation.get('title'); // 'ES6 Patterns in the Wild'
const presentation = new Map([ ['title', 'ES6 Patterns in the Wild'], ['author', 'Joe Morgan'] ]);
> presentation.get('title'); // 'ES6 Patterns in the Wild'
canUseCollections = ( ... typeof Map === 'function' && isNative(Map) && ... );
if (canUseCollections) { var itemMap = new Map(); var rootIDSet = new Set();
setItem = function(id, item) { itemMap.set(id, item); }; getItem = function(id) { return itemMap.get(id); }; ... }
else { var itemByKey = {}; var rootByKey = {}; var getKeyFromID = () => {} var getIDFromKey = () => {}
setItem = function(id, item) { var key = getKeyFromID(id); itemByKey[key] = item; }; getItem = function(id) { var key = getKeyFromID(id); return itemByKey[key]; }; ... }
React
React
React
As ES6 becomes native there are advantages beyond style
Build a Library of Readable Code
Lurk Around Github
Lurk Around Github
Advanced Search
Glance at your dependencies
Have a few authors you like
iv. Code can be beautiful
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; }
const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
var data = [1,2,3,4]; var updated = []; for(var i = 0; i < data.length; i++) { updated.push(i*i); } return updated;
const data = [1,2,3,4]; return data.map(n => n*n);
Perfection is finally attained not when there is no longer anything to add, but when there is no longer anything to take away
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; }
const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
Joe Morgan
Joe Morgan
@joesmorgan
Joe Morgan
@joesmorgan
thejoemorgan.com
Joe Morgan
@joesmorgan
thejoemorgan.com
https://github.com/jsmapr1