+ All Categories
Home > Technology > Nate Abele "Un-Dux Your Front-End"

Nate Abele "Un-Dux Your Front-End"

Date post: 22-Jan-2018
Category:
Upload: fwdays
View: 85 times
Download: 5 times
Share this document with a friend
73
Un-Dux Your Front-End Nate Abele Advisor Innovation Labs
Transcript
Page 1: Nate Abele "Un-Dux Your Front-End"

Un-Dux Your Front-EndNate AbeleAdvisor Innovation Labs

Page 2: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-ENDNATE ABELE

Page 3: Nate Abele "Un-Dux Your Front-End"

THE UNREASONABLE EFFECTIVENESS OF DATA

OR…

Page 4: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

YOUR HOST: NATE ABELE

▸ Some PHP frameworks (Li3, CakePHP)

▸ AngularUI Router

▸ Architect @ AI Labs

▸ @nateabele

[email protected]

Page 5: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

ADVISOR INNOVATION LABS

Page 6: Nate Abele "Un-Dux Your Front-End"

CONCEPTS

Page 7: Nate Abele "Un-Dux Your Front-End"
Page 8: Nate Abele "Un-Dux Your Front-End"

CONCEPTS

Page 9: Nate Abele "Un-Dux Your Front-End"
Page 10: Nate Abele "Un-Dux Your Front-End"
Page 11: Nate Abele "Un-Dux Your Front-End"
Page 12: Nate Abele "Un-Dux Your Front-End"
Page 13: Nate Abele "Un-Dux Your Front-End"
Page 14: Nate Abele "Un-Dux Your Front-End"

STATE

Page 15: Nate Abele "Un-Dux Your Front-End"
Page 16: Nate Abele "Un-Dux Your Front-End"

< Component />

Page 17: Nate Abele "Un-Dux Your Front-End"

< Component />

< Component /> < Component />

Page 18: Nate Abele "Un-Dux Your Front-End"

< Component />

< Component /> < Component />

< Component />

Page 19: Nate Abele "Un-Dux Your Front-End"

< Component />

< Component /> < Component />

< Component /> < Component /> < Component />

Page 20: Nate Abele "Un-Dux Your Front-End"

< Component />

< Component /> < Component />

< Component /> < Component /> < Component />

Page 21: Nate Abele "Un-Dux Your Front-End"

< Component />

< Component /> < Component />

< Component /> < Component /> < Component />

Page 22: Nate Abele "Un-Dux Your Front-End"

< Component />

< Component /> < Component />

< Component /> < Component /> < Component />

Page 23: Nate Abele "Un-Dux Your Front-End"
Page 24: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

REDUX

▸ Single-value store

▸ Changes (actions) are simple values

▸ Few opinions

Page 25: Nate Abele "Un-Dux Your Front-End"

SETTING UP

$ yarn add

Page 26: Nate Abele "Un-Dux Your Front-End"

SETTING UP

$ yarn add reduxreact-reduxreact-router-reduxredux-loggerredux-sagaredux-mock-storeredux-immutableredux-thunkredux-promise-middlewarereact-redux-formredux-actredux-saga-test-planredux-queryredux-saga-async...

Page 27: Nate Abele "Un-Dux Your Front-End"
Page 28: Nate Abele "Un-Dux Your Front-End"

function todoApp(state = initialState, action) {

switch (action.type) {

case SET_VISIBILITY_FILTER:

return Object.assign({}, state, {

visibilityFilter: action.filter

})

default:

return state

}

}

Page 29: Nate Abele "Un-Dux Your Front-End"
Page 30: Nate Abele "Un-Dux Your Front-End"

ELMELM

Page 31: Nate Abele "Un-Dux Your Front-End"
Page 32: Nate Abele "Un-Dux Your Front-End"

CASIUM

Page 33: Nate Abele "Un-Dux Your Front-End"

import React from 'react';

import { container } from 'casium';import Message from 'casium/message';

class Increment extends Message {}class Decrement extends Message {}

export default container({

init: () => ({ count: 0 }),

update: [ [Increment, ({ count }) => ({ count: count + 1 })], [Decrement, ({ count }) => ({ count: count - 1 })] ],

view: ({ emit, count }) => ( <div> <button onClick={emit(Decrement)}> - </button> { count } <button onClick={emit(Increment)}> + </button> </div> )});

Page 34: Nate Abele "Un-Dux Your Front-End"
Page 35: Nate Abele "Un-Dux Your Front-End"

import React from 'react';

import { container } from 'casium';import Message from 'casium/message';

class Increment extends Message {}class Decrement extends Message {}

export default container({

init: () => ({ count: 0 }),

update: [ [Increment, ({ count }) => ({ count: count + 1 })], [Decrement, ({ count }) => ({ count: count - 1 })] ],

view: ({ emit, count }) => ( <div> <button onClick={emit(Decrement)}> - </button> { count } <button onClick={emit(Increment)}> + </button> </div> )});

Page 36: Nate Abele "Un-Dux Your Front-End"

import React from 'react';

import { container } from 'casium';import Message from 'casium/message';

class Increment extends Message {}class Decrement extends Message {}

export default container({

init: () => ({ count: 0 }),

update: [ [Increment, ({ count }) => ({ count: count + 1 })], [Decrement, ({ count }) => ({ count: count - 1 })] ],

view: ({ emit, count }) => ( <div> <button onClick={emit(Decrement)}> - </button> { count } <button onClick={emit(Increment)}> + </button> </div> )});

Page 37: Nate Abele "Un-Dux Your Front-End"

import React from 'react';

import { container } from 'casium';import Message from 'casium/message';

class Increment extends Message {}class Decrement extends Message {}

export default container({

init: () => ({ count: 0 }),

update: [ [Increment, ({ count }) => ({ count: count + 1 })], [Decrement, ({ count }) => ({ count: count - 1 })] ],

view: ({ emit, count }) => ( <div> <button onClick={emit(Decrement)}> - </button> { count } <button onClick={emit(Increment)}> + </button> </div> )});

Page 38: Nate Abele "Un-Dux Your Front-End"

RAMDAJS

Page 39: Nate Abele "Un-Dux Your Front-End"

import React from 'react';import { evolve } from 'ramda';

import { container } from 'casium';import Message from 'casium/message';

class Increment extends Message {}class Decrement extends Message {}

export default container({

init: () => ({ count: 0 }),

update: [ [Increment, evolve({ count: ct => ct + 1 })], [Decrement, evolve({ count: ct => ct - 1 })] ],

view: ({ emit, count }) => ( <div> <button onClick={emit(Decrement)}> - </button> { count } <button onClick={emit(Increment)}> + </button> </div> )});

Page 40: Nate Abele "Un-Dux Your Front-End"

import React from 'react';import { evolve } from 'ramda';

import { container } from 'casium';import Message from 'casium/message';

class Increment extends Message {}class Decrement extends Message {}

export default container({

init: () => ({ count: 0 }),

update: [ [Increment, evolve({ count: ct => ct + 1 })], [Decrement, evolve({ count: ct => ct - 1 })] ],

view: ({ emit, count }) => ( <div> <button onClick={emit(Decrement)}> - </button> { count } <button onClick={emit(Increment)}> + </button> </div> )});

Page 41: Nate Abele "Un-Dux Your Front-End"

import React from 'react';import { evolve, inc, dec } from 'ramda';

import { container } from 'casium';import Message from 'casium/message';

class Increment extends Message {}class Decrement extends Message {}

export default container({

init: () => ({ count: 0 }),

update: [ [Increment, evolve({ count: inc })], [Decrement, evolve({ count: dec })] ],

view: ({ emit, count }) => ( <div> <button onClick={emit(Decrement)}> - </button> { count } <button onClick={emit(Increment)}> + </button> </div> )});

Page 42: Nate Abele "Un-Dux Your Front-End"

import { merge } from 'ramda';/* … */

class UpdateForm extends Message {}class SignIn extends Message {}

export default container({ init: () => ({ email: '', password: '' }),

update: [[UpdateForm,(model, { key, value }) => merge(model, { [key]: value })

]],

view: ({ emit, email, password }) => ( <form> <input type='email' value={email}

onChange={emit([UpdateForm, { key: 'email' }])} /> <input type='password' value={password}

onChange={emit([UpdateForm, { key: 'password' }])} /> </form> )});

Page 43: Nate Abele "Un-Dux Your Front-End"

import { Http } from 'casium/commands';/* … */

class SignIn extends Message {}class SignInSuccess extends Message {}class SignInError extends Message {}

export default container({ init: () => ({ email: '', password: '', loading: false }),

update: [ [UpdateForm, (model, { key, value }) => /* … */],

[SignIn, model => [merge(model, { loading: true }),new Http.Post({url: '/login',data: { email: model.email, password: model.password },result: SignInSuccess,error: SignInError

})]]

],

view: ({ emit, email, password }) => ( <form onSubmit={emit(SignIn)}> /* … */ </form> )});

Page 44: Nate Abele "Un-Dux Your Front-End"

import { Http } from 'casium/commands';/* … */

class SignInSuccess extends Message {}class SignInError extends Message {}

export default container({ init: () => ({ email: '', password: '', loading: false }),

update: [ /* … */

[SignInSuccess, (model, { data }) => /* Handle the response… */][SignInError, (model, { status }) => /* Handle error… */]

],

view: ({ emit, email, password }) => ( <form onSubmit={emit(SignIn)}> /* … */ </form> )});

Page 45: Nate Abele "Un-Dux Your Front-End"

import { Post, formData } from 'casium/commands/http';

export default class SignIn extends Post {

constructor({ email, password, ...params }) { const id = 'my-app', secret = 'woo-sekrit';

super({ url: '/oauth/token', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' + btoa(id + ':' + secret) }, data: formData({ username: email, password, grant_type: 'password', scope: 'read write', client_secret: secret, client_id: id }), ...params }); }}

Page 46: Nate Abele "Un-Dux Your Front-End"

import { Post, formData } from 'casium/commands/http';import { SignInSuccess, SignInError } from './sign_in_container';

export default class SignIn extends Post {

constructor({ email, password, ...params }) { const id = 'my-app', secret = 'woo-sekrit';

super({ url: '/oauth/token', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' + btoa(id + ':' + secret) }, data: formData({ username: email, password, grant_type: 'password', scope: 'read write', client_secret: secret, client_id: id }),

result: SignInSuccess,error: SignInError

...params }); }}

Page 47: Nate Abele "Un-Dux Your Front-End"

import { Http } from 'casium/commands';/* … */

export default container({ init: () => ({ email: '', password: '', loading: false }),

update: [ /* … */

[SignInSubmit, model => [merge(model, { loading: true }),new Http.Post({url: '/login',data: { email: model.email, password: model.password },result: SignInSuccess,error: SignInError

})]]

],

view: ({ emit, email, password }) => ( <form onSubmit={emit(SignInSubmit)}> /* … */ </form> )});

Page 48: Nate Abele "Un-Dux Your Front-End"

import { SignIn } from ‘./messages/sign_in’;/* … */

export default container({ init: () => ({ email: '', password: '', loading: false }),

update: [ /* … */

[SignInSubmit, model => [merge(model, { loading: true }),new SignIn({ email: model.email, password: model.password })

]] ],

view: ({ emit, email, password }) => ( <form onSubmit={emit(SignInSubmit)}> /* … */ </form> )});

Page 49: Nate Abele "Un-Dux Your Front-End"

import { SignIn } from ‘./messages/sign_in’;import { container, seq } from 'casium';/* … */

export default container({ init: () => ({ email: '', password: '', loading: false }),

update: [ /* … */

[SignInSubmit, seq(model => merge(model, { loading: true }),model => [model, new SignIn({ email: model.email, password: model.password})]

)] ],

view: ({ emit, email, password }) => ( <form onSubmit={emit(SignInSubmit)}> /* … */ </form> )});

Page 50: Nate Abele "Un-Dux Your Front-End"

import { merge, pick } from 'ramda';import { SignIn } from ‘./messages/sign_in’;import { container, seq, replace, commands } from 'casium';/* … */

export default container({ init: () => ({ email: '', password: '', loading: false }),

update: [ /* … */

[SignInSubmit, seq(replace({ loading: true }),commands(SignIn, pick(['email', 'password']))

)] ],

view: ({ emit, email, password }) => ( <form onSubmit={emit(SignInSubmit)}> /* … */ </form> )});

Page 51: Nate Abele "Un-Dux Your Front-End"

WHY?

Page 52: Nate Abele "Un-Dux Your Front-End"

GUARANTEES

Page 53: Nate Abele "Un-Dux Your Front-End"

EXAMPLE: PROMISES

Page 54: Nate Abele "Un-Dux Your Front-End"

GUARANTEES

Page 55: Nate Abele "Un-Dux Your Front-End"

‘PROBABLY’

Page 56: Nate Abele "Un-Dux Your Front-End"

$ git checkout b69c907

Page 57: Nate Abele "Un-Dux Your Front-End"

$ yarn test

Page 58: Nate Abele "Un-Dux Your Front-End"
Page 59: Nate Abele "Un-Dux Your Front-End"

[DEMO]

Page 60: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

REVIEW

▸ Diff view of changes

▸ Generated unit tests

▸ Time travel

▸ Message log export

▸ Websockets magic

Page 61: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

IMPLICATIONS

▸ Crossing boundaries

▸ Device farm

▸ Reproduce production errors

▸ Watch / replay user sessions

▸ Isolation

▸ Browser testing

▸ API testing

Page 62: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

IMPLICATIONS

▸ Diff analysis

Page 63: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

Sign Up.json

Log In.json

Set Prefs.json

Page 64: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

Sign Up.json

Log In.json

Set Prefs.json

Page 65: Nate Abele "Un-Dux Your Front-End"

$ webpack my-app.js

Page 66: Nate Abele "Un-Dux Your Front-End"

$ webpack my-app.js> my-app-df3db62731a0a32ef0c6.js

Page 67: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

df3db6273+

Page 68: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

Sign Up.json

Log In.json

+

+

df3db6273

df3db6273

Page 69: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

TRY CASIUM

▸ /ai-labs-team/casium

▸ /ai-labs-team/casium-devtools

▸ casium.io

Page 70: Nate Abele "Un-Dux Your Front-End"

THANKS!

Page 71: Nate Abele "Un-Dux Your Front-End"

QUESTIONS?

Page 72: Nate Abele "Un-Dux Your Front-End"

UN-DUX YOUR FRONT-END

CONTACT

▸ /nateabele

▸ @nateabele

[email protected]

Page 73: Nate Abele "Un-Dux Your Front-End"

PHOTO CREDITS

▸ ‘This is not a pipe’: https://www.threadless.com/product/543/this_is_not_a_pipe

▸ ‘Cow’: https://www.emaze.com/@AWCTOFZ

▸ ‘Steak’: http://www.chicagomeat.com/products/t-bone-steak/

▸ ‘McDonald’s Hamburger’: https://www.businessinsider.com.au/man-saves-mcdonalds-burger-for-5-years-2014-7

▸ ‘Texas’: http://yalsa.ala.org/blog/2014/02/25/virtual-road-trip-texas-part-2/

▸ ‘DeLorean’: https://www.pinterest.com/pin/114419646753355072/

▸ ‘Redux Architecture’: https://medium.com/mofed/react-redux-architecture-overview-7b3e52004b6e


Recommended