Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Modern functional concepts and JavaScript (RUS)

Modern functional concepts and JavaScript (RUS)

Modern concept of using Functional Programming paradigm, Immutable data types and CRDT in JavaScript. LvivJS 2016

Max Klymyshyn

August 27, 2016
Tweet

More Decks by Max Klymyshyn

Other Decks in Programming

Transcript

  1. Обо мне ‣ 13+ лет опыта веб разработки, 7 лет

    JavaScript, 8 лет Python ‣ Работал в Upwork (oDesk), Helios Tech., 42cc. ‣ Со-организатор конференций PyCon Ukraine, KyivJS ‣ с 20012 года работаю техническим директором в CartFresh (ZAKAZ.UA)
  2. О разговоре ‣ Некоторые проблемы JS ‣ Функциональный подход ‣

    Неизменяемые структуры данных ‣ Conflict-free replicated data type
  3. Зачем это надо? if (a = true) console.log("Condition fucked"); var

    b = [], a = ""; if (a == b) console.log("Condition fucked"); var a = null; if (typeof a === "object") console.log("you got it..."); var a = NaN; if (typeof a === "number") console.log("holy molly"); if (0.1 + 0.2 !== 0.3) console.log("Math fucked"); ([] === []) // you know ({} === {}) // you know…
  4. Зачем это надо? ‣ 25.3% времени в баг репортах тратится

    на обсуждение фикса, включая советы, понимание и т.п. ‣ баг фиксы сами по себе являются источником 9% багов
  5. Композиция ∘ Функция, построена из двух функций таким образом, что

    результат выполнения первой является аргументом второй (f ∘ g)(x) = f(g(x))
  6. Композиция let double = number => number * 2; let

    triple = number => number * 3; let quadruple = number => number * 4; let compose = (...funcs) => (value) => { return funcs.reduce((v,fn) => fn(v), value); }; // Arguments are read right to left // double -> triple -> quadruple let crunchNumber = compose( double, triple, quadruple ); let number = crunchNumber(5); console.log(number); // 120
  7. \

  8. Reduce var total = 0; var numbers = [1, 2,

    3]; for ( var i = 0; i < numbers.length; i++ ){ total += numbers[i]; } [1, 2, 3].reduce( (total, num) => total + num , 0))
  9. Map and filter [1, 2, 3].map( (num) => num *

    2 ) // -> [2, 4, 6] [1, 2, 3].filter( (num) => num > 1 ) // -> [2, 3]
  10. Chaining var wu = require("wu"); const pairs = [[2, 1],

    [2, 2], [2, 3], [2, 4]]; const log = msg => console.log.bind(console, msg); const iter = wu(pairs) .tap(log("initial: ")) .spreadMap(Math.pow) .tap(log("after spreadMap: ")) .map(n => n + 1) .tap(log("after + 1: ")) .reject(n => n < 7) .tap(log("after reject: ")); iter.next().value;
  11. Chaining after spreadMap: 2 after + 1: 3 initial: [

    2, 2 ] after spreadMap: 4 after + 1: 5 initial: [ 2, 3 ] after spreadMap: 8 after + 1: 9 after reject: 9
  12. var t = require("transducers-js"); let {map, filter, comp, into} =

    t; let inc = (n) => n + 1; let isEven = (n) => n % 2 == 0; let xf = comp(map(inc), filter(isEven)); console.log(into([], xf, [0,1,2,3,4])); // [2,4]
  13. Fizz buzz ‣ x % 15 == 0 - FizzBuzz

    ‣ x % 3 == 0 - Fizz ‣ x % 5 == 0 - Buzz
  14. from operator import itemgetter from transducer.eager import transduce from transducer.transducers

    import grouping, mapping, batching from transducer.functional import compose from transducer.reducers import Appending normprice = lambda i: int(float(i.replace(",", ".")) * 100) COLUMNS = ( ("int_id", str), ("num", str), ("id", str), ("sku", int), ("qty", float), ("ppi_price", normprice), ("price", normprice), ("discount_price", normprice), ("created_at", str), ("location", str)) class AppendToDatabase(Appending): def step(self, result, item): print ("Here we going to save into database: {}".format(len(item))) pprint.pprint(transduce( transducer=compose( mapping(lambda l: l.split(";")), mapping(lambda c: [f(v) for f, v in zip(map(itemgetter(1), COLUMNS), c)]) , mapping(lambda c: dict(zip(map(itemgetter(0), COLUMNS), c))), grouping(itemgetter("id")), batching(100) ), reducer=AppendToDatabase(), iterable=gather_data()))
  15. React.js import React, { PropTypes, Component, createElement } from 'react';

    import highOrderProvider from 'react-high-order-provider'; @highOrderProvider class Example extends Component { render() { const { originalProps, component } = this.props; return createElement( component, { ...originalProps, myAditionalProp: 123, }); } } @exampleProvider function MyComponent(props) { return ( <input type="text" placeholder={props.myAditionalProp} /> ); }
  16. Нечитабельный код ‣ “читабельность” кода крайне субъективное понятие ‣ зачастую

    функциональный код читать несколько сложнее, но объем кода меньше
  17. Что это такое? Структуры, предоставляющие мутационный API, который не изменят

    данные на месте, а возвращает всегда новые обновленные данные
  18. var person = Immutable.Map({ name: 'John', birth: 594687600000, phone: '12345678'

    }); var changePhone = function( person, newPhone ) { return person.set( 'phone', newPhone ); }; var person2 = changePhone( person, '87654321' ); console.log( person2 == person, person2 === person ); // false false console.log( person.get('phone'), person2.get( 'phone' ) ); // 12345678 87654321 console.log( person.phone, per
  19. ‣ Immutable.js – by facebook ‣ Mori – port from

    Clojure with Vanilla JS API ‣ seamless-immutable – backwards-compatible with normal Arrays and Objects ‣ Object.freeze – pure JS ‣ persistence-js Что на рынке?
  20. Общий замысел CRDT — в использовании частичного порядка вместо линеаризации.

    Операции могут происходить параллельно на многих репликах, и некоторые операции конкурентны — т.е. произошли на разных репликах, не зная друг о друге, ни одна из них не «первая», и на разных репликах они прикладываются в разном порядке. Что такое CRDT?
  21. ‣ G-Set – только добавление ‣ 2P-Set – однократное добавление

    и удаление ‣ LWW-Element-Set – многократное добавление и удаление ‣ OR-Set – добавление и удаление на узле ‣ Max-Change-Set – Set, оптимизирующий объединение по большому числу элементов, нельзя удалить несуществующий элемент и добавить существующий ‣ G-Counter — Counter, только возрастает ‣ PN-Counter — Counter, можно увеличивать и уменьшать
  22. Минусы: 1. ограниченный «урезанный» функционал 2. при длительном использовании эффективность

    падает, и надо делать распределенную сборку мусора на всех узлах (что требует 2-х фазный коммит) 3. больше расход памяти