+ All Categories
Home > Software > Func up your code

Func up your code

Date post: 08-Feb-2017
Category:
Upload: maciej-komorowski
View: 204 times
Download: 0 times
Share this document with a friend
55
Func up your code Maciej Komorowski
Transcript
Page 1: Func up your code

Func up your codeMaciej Komorowski

Page 2: Func up your code

What is func%onal programming?

Page 3: Func up your code

Func%onal programming is programming paradigm [...] that

treats computa%on as the evalua%on of mathema&cal func&ons and

avoids changing-state and mutable data.

— Wikipedia

Page 4: Func up your code

Pillars of FP

• Higher-order func0ons (e.g. map)

• Immutable data

• Lazy evalua0on

• Pure func0ons

• Recursion

Page 5: Func up your code

Pure func)on! Always evaluates the same result value given the same arguments! Does not cause any seman5cally observable side effect, such as muta5on of mutable objects

Page 6: Func up your code

Pure func)on examples// Purefunction add(a, b) { return a + b;}

// ImpureMath.random();

// Impureconst items = []

function addItem(item) { return items.push(item);}

Page 7: Func up your code

State muta(on

Page 8: Func up your code

State muta(on in OOP

! Relies heavily on encapsula)on! Has hidden nature! Brings nondeterminism! Root cause of doom

Page 9: Func up your code

Brogrammer1

State muta)on example

A brogrammer is [...] a slang term for a macho, male programmer. A brogrammer

might self-describe as a sociable programmer.

— Wikipedia

1 Frans Hals, Oil on canvas, 1630. Source: classicprogrammerpain;ngs

Page 10: Func up your code

What brogrammer does?

• drinkBeer

• talk

Page 11: Func up your code

Stateful implementa*on

class Brogrammer { constructor() { this.beers = 0; }

drinkBeer() { /* ... */ } talk() { /* ... */ }}

Page 12: Func up your code

Stateful – drinkBeer

it('increment number of drunk beers', () => { expect(brogrammer.drinkBeer()).toEqual(1); expect(brogrammer.drinkBeer()).toEqual(2);});

// Inside Brogrammer classdrinkBeer() { return this.beers += 1; // encapsulates 'beers'}

Page 13: Func up your code

Stateful – talk testsit('says "Beer me up!" before drinking', () => { expect(brogrammer.talk()).toEqual("Beer me up!");});

it('says "Yummy" after 1st beer', () => { brogrammer.drinkBeer(); expect(brogrammer.talk()).toEqual("Yummy");});

it('says "I a<M dRuNk" after 10th beer', () => { brogrammer.drinkBeer(); // 8 x brogrammer.drinkBeer(); brogrammer.drinkBeer(); expect(brogrammer.talk()).toEqual("I a<M dRuNk");});

Page 14: Func up your code

Stateful – talk implementa+on

// Inside Brogrammer classtalk() { return ({ 0: 'Beer me up!', 1: 'Yummy', // ... 10: 'I a<M dRuNk', })[this.beers] || '';}

Page 15: Func up your code

How to remove state?Single source of truth

Page 16: Func up your code

Naïve stateless – implementa+on

class Brogrammer { constructor(store) { this.store = store; }

// ...}

Page 17: Func up your code

Naïve stateless – drinkBeer tests

it('increment number of drunk beers', () => { const store = { beers: 0 }; const brogrammer = new Brogrammer(store);

brogrammer.drinkBeer();

expect(store.beers).toEqual(1);});

Page 18: Func up your code

Naïve stateless – drinkBeer implementa+on

// Inside Brogrammer classdrinkBeer() { return this.store.beers += 1;}

Page 19: Func up your code

Naïve stateless – talk tests

it('says "I a<M dRuNk" after 10th beer', () => { const store = { beers: 10 }; const brogrammer = new Brogrammer(store);

expect(brogrammer.talk()).toEqual("I a<M dRuNk");});

Page 20: Func up your code

Naïve stateless – talk implementa+on

// Inside Brogrammer classtalk() { return ({ 0: 'Beer me up!', 1: 'Yummy', // ... 10: 'I a<M dRuNk', })[this.store.beers] || '';}

Page 21: Func up your code

Solu%on review! Removed state from the Brogrammer! Easier tes2ng" Lost encapsula-on

Page 22: Func up your code

How to improve?The Redux way

Page 23: Func up your code

Redux workflow2

2 Source: CSS-Tricks

Page 24: Func up your code

Three Principles of Redux3

! Single source of truth! State is read-only! Changes are made with pure func)ons

3 Source: Redux

Page 25: Func up your code

Three Principles of ReduxSingle source of truth

console.log(store.getState());

// {// brogrammer: {// beers: 0// }// }

Page 26: Func up your code

Three Principles of ReduxState is read-only

store.dispatch({ type: 'INCREMENT_BEERS',});

Page 27: Func up your code

Three Principles of ReduxChanges are made with pure func3ons

function brogrammer(state = {}, action) { switch (action.type) { case 'SET_BEERS': return { ...state, beers: 5, }; // case ... }}

Page 28: Func up your code

Redux – incrementBeers ac%on

it('returns action with type INCREMENT_BEERS', () => { const action = incrementBeers();

expect(action).toEqual({ type: 'INCREMENT_BEERS' });});

Page 29: Func up your code

Redux – incrementBeers ac%on

const incrementBeers = () => ({ type: 'INCREMENT_BEERS',});

Page 30: Func up your code

Redux – brogrammer reducer

it('returns state with incremented beers', () => { const state = { beers: 0 }; const action = incrementBeers();

const nextState = brogrammer(state, action);

expect(nextState).toEqual({ beers: 1 });});

Page 31: Func up your code

Redux – brogrammer reducerimplementa)on

const brogrammer = (state = {}, action) => { switch (action.type) { case 'INCREMENT_BEERS': return { ...state, beers: state.beers + 1 }; default: return state }}

Page 32: Func up your code

Redux – drinkBeer tests

it('increment number of drunk beers', () => { const store = createStore({ beers: 0 }); const brogrammer = new Brogrammer(store);

brogrammer.drinkBeer();

expect(store.dispatch) .toHaveBeenCalledWith(incrementBeers());});

Page 33: Func up your code

Redux – drinkBeer implementa+on

// Inside Brogrammer classdrinkBeer() { return this.store.dispatch(incrementBeers());}

Page 34: Func up your code

Redux – talk tests

it('says "I a<M dRuNk" after 10th beer', () => { const store = createStore({ beers: 10 }); const brogrammer = new Brogrammer(store);

expect(brogrammer.talk()).toEqual("I a<M dRuNk");});

Page 35: Func up your code

Redux – talk implementa+on

// Inside Brogrammer classtalk() { return ({ 0: 'Beer me up!', 1: 'Yummy', // ... 10: 'I a<M dRuNk', })[this.store.get('beers')] || '';}

Page 36: Func up your code

Solu%on review! Easy tes(ng! Be,er separa(on! Explicit state changes! Full control over state

Page 37: Func up your code

A few thoughts on Redux

Page 38: Func up your code

Immutable data

Page 39: Func up your code

Mutable vs immutable// Mutableconst items = ['foo'];

items.push('bar');items.push('baz');

console.log(items); // ["foo", "bar", "baz"]

Page 40: Func up your code

Mutable vs immutable// Immutable via immutable-jsconst items = Immutable.List.of('foo');

items.push('bar');items.push('baz');

console.log(items.toArray());// ["foo"]

console.log(items.push('bar').push('baz').toArray());// ["foo", "bar", "baz"]

Page 41: Func up your code

What about performance?5

5 Source: React.js Conf 2015 - Immutable Data and React

Page 42: Func up your code

Performance benchmarkArray push 1,000,000 items:

var list = [];for (var i = 0; i < 1000000; i++) { list.push(i);}

83 ms

Page 43: Func up your code

Performance benchmarkMori immutable vector conj 1,000,000 items:

var list = mori.vector();for (var i = 0; i < 1000000; i++) { mori.conj(list, i);}

288 ms

Page 44: Func up your code

Should update problemconst form = { /* ... */ };

function submit(form) { if (hasChanged(form)) { doSomethingExpensive(form); }}

Page 45: Func up your code

Should update problemversioning

let currentFormVersion;

function hasChanged(form) { const formVersion = md5(JSON.stringify(form));

return formVersion !== currentFormVersion;}

Page 46: Func up your code

Should update problemdirty bits

function hasChanged(form) { for (var field in form) { if (field.meta.dirty === true) { return true; } }

return false;}

Page 47: Func up your code

Should update problemobservable pa+ern

const form = { /* ... */ };

Object.observe(form, changes => { doSomethingExpensive(form);});

form.firstName = 'Maciej';form.lastName = 'Komorowski';form.profession = 'Brogrammer'; // Not true :)

Page 48: Func up your code

Should update problemimmutable

let currentForm = { /* ... */ };

function hasChanged(form) { return currentForm !== form;}

Page 49: Func up your code

Memoiza(on examplefunction memoize(fn) { var cache = {}; return function (arg) { var hash = arg === Object(arg) ? JSON.stringify(arg) // Wat? : arg; return hash in cache ? cache[hash] : (cache[hash] = fn.call(this, arg)); }}

Page 50: Func up your code

Memoiza(on examplefunction rawSum(list) { return list.reduce((a, b) => a + b)}

const sum = memoize(rawSum);const array = [0, 1, ...1000000];

sum(array); // 89 ms

rawSum(array); // 51 mssum(array); // 42 ms

Page 51: Func up your code

Advantages of immutability! No defensive copies! Can be faster! Be3er for concurrency (no deadlocks)

Page 52: Func up your code

Explore func-onal programing❗It's worth it

Page 53: Func up your code

ContactMaciej Komorowski

@komomc

Page 54: Func up your code

QuizWhat f does?

f = 0 : 1 : zipWith (+) f (tail f)

Page 55: Func up your code

AnswerGenerates Fibonacci sequence

> let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

> take 11 fibs[0,1,1,2,3,5,8,13,21,34,55]


Recommended