Slide 1

Slide 1 text

@maxmaxmaxmax МАКСИМ КЛИМИШИН CTO CARTFRESH GVMachines Inc. Modern functional concepts and JavaScript

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

О разговоре ‣ Некоторые проблемы JS ‣ Функциональный подход ‣ Неизменяемые структуры данных ‣ Conflict-free replicated data type

Slide 4

Slide 4 text

Зачем это надо?

Slide 5

Slide 5 text

Зачем это надо? 1. Решать некоторые бока JS

Slide 6

Slide 6 text

Зачем это надо? 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…

Slide 7

Slide 7 text

Brendan Eich Creator of JavaScript

Slide 8

Slide 8 text

Зачем это надо? 2. Писать код лучше

Slide 9

Slide 9 text

Зачем это надо? 2. Callback hell

Slide 10

Slide 10 text

Зачем это надо?

Slide 11

Slide 11 text

Зачем это надо? 3. Допускать меньше ошибок

Slide 12

Slide 12 text

Так сложилось…

Slide 13

Slide 13 text

Зачем это надо? ‣ 25.3% времени в баг репортах тратится на обсуждение фикса, включая советы, понимание и т.п. ‣ баг фиксы сами по себе являются источником 9% багов

Slide 14

Slide 14 text

Зачем это надо?

Slide 15

Slide 15 text

Зачем это надо?

Slide 16

Slide 16 text

Функциональное программирование

Slide 17

Slide 17 text

Способ организации вычислений без состояния. f(x)

Slide 18

Slide 18 text

Ключевое ‣ Чистые функции: ‣ детерминированные ‣ без побочных эффектов

Slide 19

Slide 19 text

Чистые функции ‣ Легко тестировать ‣ Легко делать композицию ‣ Легко дебажить

Slide 20

Slide 20 text

Композиция ∘ Функция, построена из двух функций таким образом, что результат выполнения первой является аргументом второй (f ∘ g)(x) = f(g(x))

Slide 21

Slide 21 text

Композиция 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

Slide 22

Slide 22 text

\

Slide 23

Slide 23 text

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))

Slide 24

Slide 24 text

Map and filter [1, 2, 3].map( (num) => num * 2 ) // -> [2, 4, 6] [1, 2, 3].filter( (num) => num > 1 ) // -> [2, 3]

Slide 25

Slide 25 text

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;

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

iterable map(f1) map(f2) filter(f3) reducer sequence Трансдюсер

Slide 28

Slide 28 text

Выносим за пределы обработки ‣ функцию-трансформер или предикат ‣ функцию-накопитель результата обработки Простейший трансдюсер готов!

Slide 29

Slide 29 text

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]

Slide 30

Slide 30 text

Fizz buzz ‣ x % 15 == 0 - FizzBuzz ‣ x % 3 == 0 - Fizz ‣ x % 5 == 0 - Buzz

Slide 31

Slide 31 text

Fizz buzz

Slide 32

Slide 32 text

Fizz buzz

Slide 33

Slide 33 text

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()))

Slide 34

Slide 34 text

‣ react pure render ‣ stateless components React.js

Slide 35

Slide 35 text

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 ( ); }

Slide 36

Slide 36 text

‣ Underscore ‣ Lodash ‣ Ramda ‣ functional.js ‣ wu.js Что на рынке?

Slide 37

Slide 37 text

Нечитабельный код ‣ “читабельность” кода крайне субъективное понятие ‣ зачастую функциональный код читать несколько сложнее, но объем кода меньше

Slide 38

Slide 38 text

Неизменяемые структуры данных

Slide 39

Slide 39 text

Что это такое? Структуры, предоставляющие мутационный API, который не изменят данные на месте, а возвращает всегда новые обновленные данные

Slide 40

Slide 40 text

Преимущества ‣ Производительность ‣ Простота: map1.equals(map2) ‣ Time travel

Slide 41

Slide 41 text

O(1)

Slide 42

Slide 42 text

Persistent data structures

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

‣ 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 Что на рынке?

Slide 45

Slide 45 text

CRDT Convergent/Commutative Replicated Data Types

Slide 46

Slide 46 text

Общий замысел CRDT — в использовании частичного порядка вместо линеаризации. Операции могут происходить параллельно на многих репликах, и некоторые операции конкурентны — т.е. произошли на разных репликах, не зная друг о друге, ни одна из них не «первая», и на разных репликах они прикладываются в разном порядке. Что такое CRDT?

Slide 47

Slide 47 text

Зачем это надо?

Slide 48

Slide 48 text

‣ G-Set – только добавление ‣ 2P-Set – однократное добавление и удаление ‣ LWW-Element-Set – многократное добавление и удаление ‣ OR-Set – добавление и удаление на узле ‣ Max-Change-Set – Set, оптимизирующий объединение по большому числу элементов, нельзя удалить несуществующий элемент и добавить существующий ‣ G-Counter — Counter, только возрастает ‣ PN-Counter — Counter, можно увеличивать и уменьшать

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

‣ Swarm ‣ CRDT (npm) ‣ Logoot Что на рынке?

Slide 51

Slide 51 text

‣ FRP ‣ ClojureScript ‣ react-haskell О чем я не говорил

Slide 52

Slide 52 text

@maxmaxmaxmax