1. Первые шаги
2. Сочетаем функции
3. Частичное применение (каррирование)
4. Декларативное программирование
5. Бесточечная нотация
6. Неизменяемость и объекты
7. Неизменяемость и массивы
8. Линзы
9. Заключение

Данный пост является четвёртой частью серии о функциональном програмировании под названием «Мышление в стиле Ramda».

В третьей части мы говорили об объединении функций, которые могут принимать больше одного аргумента, используя техники частичного применения и каррирования.

Когда мы начинаем писать маленькие функциональные строительные блоки и объединять их, мы обнаруживаем, что нам необходимо написать множество функций, которые будут оборачивать операторы JavaScript, такие как арифметика, сравнение, логика и управление потоком. Это может показаться утомительным, но мы находимся за спиной Ramda.

Но сначала, небольшое введение.

Императивность vs Декларативность


Есть множество различных путей для разделения языков программирования и стилей написания. Это статическая типизация против динамической типизаци, интерпретируемые языки и компилируемые языки, высокоуровневые и низкоуровные, и так далее.

Другое подобное разделение заключается в императивном програмировании против декларативного.

Без погружения вглубь этого, императивное программирование — это стиль программирования, в котором программисты говорят компьютеру, что нужно сделать, объясняя ему, как это нужно сделать. Императивное программирование даёт множество конструкций, которые мы используем каждый день: управление потоком (if-then-else синтаксис и циклы), арифметические операторы (+, -, *, /), операторы сравнения (===, >, <, и т.д.), и логические операторы (&&, ||, !).

Декларативное программирование — это стиль програмирования, в котором програмисты говорят компьютеру, что нужно сделать, объясняя ему, что они хотят. Компьютер далее должен определить, как получить необходимый результат.

Один из классических декларативных языков — это Prolog. В Prolog програма состоит из набора фактов и набора правил вывода. Вы начинаете программу, задавая вопрос, и набор правил вывода Prolog'а использует факты и правила для ответа на ваш вопрос.

Функциональное программирование рассматривается как подмножество декларативного програмирования. В функциональной программе, мы объявляем функции и далее объясняем компьютеру что мы хотим сделать, совмещая данные функции.

Даже в декларативных программах необходимо выполнять подобные задачи, которые мы выполняем в императивных программах. Управление потоком, арифметика, сравнения и логика всё ещё являются базовыми строительными блоками, с которыми мы должны работать. Но нам необходимо найти способы для выражения этих конструкций в декларативном стиле.

Декларативные заменители


Поскольку мы программируем на JavaScript, императивном языке, это нормально — использовать стандартные императивные конструкции при написании «нормального» JavaScript кода.

Но когда мы пишем функциональные трансформации, используя конвееры и подобные им конструкции, императивные конструкции перестают вписываться с создаваемую структуру кода.

Посмотрим на некоторые базовые строительные блоки, которые предоставляет Ramda для того чтобы помочь нам выйти из этой неприятной ситуации.

Арифметика


Во второй части мы реализовали серию арифметических трансформаций для демонстрации конвеера:

const multiply = (a, b) => a * b
const addOne = x => x + 1
const square = x => x * x
 
const operate = pipe(
  multiply,
  addOne,
  square
)
 
operate(3, 4) // => ((3 * 4) + 1)^2 => (12 + 1)^2 => 13^2 => 169

Обратите внимание, как мы пишем функции для всех базовых строительных блоков, которые мы желаем использовать.

Рамда предоставляет функции add, subtract, multiply и divide для использования в местах стандартных арифметических операций. Так что мы можем использовать рамдовскую multiply там, где мы использовали самописную функцию, мы можем взять преимущество каррированной функции add для замены нашей addOne, и мы также можем написать square с помощью multiply.

const square = x => multiply(x, x)
 
const operate = pipe(
  multiply,
  add(1),
  square
)

add(1) очень похожа на оператор инкрементирования (++), но оператор инкрементирования изменяет переменную, так что он вызывает мутацию. Как мы узнали из первой части, иммутабельность — это основной принцип функционального программирования, так что мы не хотим использовать ++ или его кузена --.

Мы можем использовать add(1) и subtract(1) для увеличения и уменьшения, но так как эти две операции такие распространённые, Ramda предоставляет inc и dec вместо них.

Так что мы можем ещё немного упростить наш конвеер:

const square = x => multiply(x, x)
 
const operate = pipe(
  multiply,
  inc,
  square
)

subtract является заменой бинарного оператора -, но у нас ещё имеется унарный оператор - для отрицания значения. Мы также можем использовать multiply(-1), но Ramda предоставляет функцию negate для выполнения этой задачи.

Сравнение


Также во второй части мы написали несколько функций для определения, является ли персона имеющей право на голосование. Конечная версия того кода выглядела следующим образом:

const wasBornInCountry = person => person.birthCountry === OUR_COUNTRY
const wasNaturalized = person => Boolean(person.naturalizationDate)
const isOver18 = person => person.age >= 18
 
const isCitizen = either(wasBornInCountry, wasNaturalized)
 
const isEligibleToVote = both(isOver18, isCitizen)

Обратите внимание, что некоторые из наших функций использут стандартные операторы сравнения (=== и >= в данном случае). Как вы можете предположить сейчас, Ramda также предоставляет заменители для всего этого.

Давайте преобразуем наш код на использование equals вместо === и gte вместо >=.

const wasBornInCountry = person => equals(person.birthCountry, OUR_COUNTRY)
const wasNaturalized = person => Boolean(person.naturalizationDate)
const isOver18 = person => gte(person.age, 18)
 
const isCitizen = either(wasBornInCountry, wasNaturalized)
 
const isEligibleToVote = both(isOver18, isCitizen)

Ramda также предоставляет gt для >, lt для < и lte для <=

Обратите внимание, что эти функции, как кажется, принимают свои аргументы в нормальном порядке (первый аргумент больше второго?). Это имеет смысл, когда мы используем их в изоляции, но может сбивать с толку при объединении функций. Эти функции нарушают принцип «данные идут последними», так что нам нужно быть осторожными, когда мы используем иих в наших конвеерах и подобных им ситуациях. И это место, когда flip и заполнитель (__) становятся полезными.

В дополнение к equals есть ещё identical для определения, являются ли два значения ссылками на то же пространство в памяти.

Существует набор случаев основных применений для ===: проверка, что строка или массив являются пустыми (str === '' или arr.length === 0) и проверка, является ли переменная равной null или undefined. Ramda предоставляет удобные функции для обоих случаев: isEmpty и isNil.

Логика


Во второй части (и чуть выше), мы использовали функции both и either в местах операторов && и ||. Мы также говорили о complement для мест с !.

Эти комбинированные функции работают прекрасно, когда функции объединяют операцию над тем же значением. Написанные выше wasBornInCountry, wasNaturalized и isOver18 все применялись к объекту персоны.

Но иногда нам нужно применить &&, || и ! к различным значениям. Для подбоных случаев Ramda предоставляет нам функции and, or и not. Я думаю следующим образом: and, or и not работают со значениями, в то время как both, either и complement работают с функциями.

В основном, || используется для получения значений по умолчанию. К примеру, мы можем написать что-нибудь вроде этого:

const lineWidth = settings.lineWidth || 80

Это распространённая идиома, и чаще всего работающая, но полагающаяся на JavaScript логику определения «ложности». Что если 0 является валидным параметром? Так как 0 является ложным значением, мы получим значение линии равное 80.

Мы можем использовать функцию isNil, о которой мы только что узнали выше, но Ramda снова имеет более логичный вариант для нас: defaultTo.

const lineWidth = defaultTo(80, settings.lineWidth)

defaultTo проверяет второй аргумент на isNil. Если проверка провалилась он вернёт полученное значение, в ином случае вернёт первый аргумент, переданный ей.

Условия


Управление потоком выполнения менее важно в функциональном программировании, но иногда оказывается нужным. Коллекция итерирующих функций, о которых мы говорили в первой части, заботиться о большинстве ситуаций с циклами, но условия всё ещё довольно важны.

ifElse


Давайте напишем функцию, forever21, которая получает год и возвращает следующий. Но, как нам указывает её имя, начиная с 21 года, он будет оставаться в этом значении.

const forever21 = age => age >= 21 ? 21 : age + 1

Обратите внимание, что наше условие (age >= 21) и вторая ветвь (age + 1) могут быть обе написаны как функции age. Мы можем переписать первую ветвь (21) как функцию-константу (() => 21). Теперь у нас будет три функции, которые принимают (или игнорируют) age.

Теперь мы на позиции, когда мы можем использовать функцию ifElse из Ramda, которая является эквивалентом структуры if...then..else или её более короткого кузена, тернарного оператора (?:).

const forever21 = age => ifElse(gte(__, 21), () => 21, inc)(age)

Как мы упомянули выше, функции сравнения не работают подобно функциям объединения, так что здесь нам нужно начать использовать заполнитель (__). Мы также можем применить lte вместо этого:

const forever21 = age => ifElse(lte(21), () => 21, inc)(age)

В данном случае, мы должны читать это как «21 меньше или равно age». Я собираюсь придерживаться версии с заменителем в оставшейся части поста, так как я нахожу это более читабельным и менее запутывающим.

Константы


Функции-константы весьма полезны в ситуациях, подобных этой. Как вы можете предположить, Ramda предоставляет нам сокращение. В данном случае, сокращение называется always.

const forever21 = age => ifElse(gte(__, 21), always(21), inc)(age)

Ramda также предоставляет T и F в качестве дальнейших сокращений для always(true) и always(false)

Тождественность


Давайте попробуем написать другую функцию, alwaysDrivingAge. Эта функция принимает age и возвращает его, если его значение gte 16. Если же оно меньше 16, то она вернёт 16. Это позволяет любому притвориться, что он управляет возрастом, даже если это не так:

const alwaysDrivingAge = age => ifElse(lt(__, 16), always(16), a => a)(age)

Вторая ветвь сравнения (a => a) — это другой типичный паттерн в функциональном программировании. Это известно как «тождественность» (не знаю точного перевода термина «identity function», просто выберу этот — прим. пер.). То есть, это функция, которая просто возвращает тот аргумент, который она получила.

Как вы уже можете ожидать, Ramda предоставляет нам функцию identity:

const alwaysDrivingAge = age => ifElse(lt(__, 16), always(16), identity)(age)

identity может принять больше одного аргумента, но всегда вернёт только первый. Если мы хотим вернуть что-то другое, отличное от первого аргумента, для этого существует более общая функция nthArg. Это гораздо менее распространённая ситуация, чем использование identity.

«when» и «unless»


Выражение ifElse, в котором одна из логических ветвей является тождественностью, также является типичным патеррном, так что Ramda предоставляет нам больше сокращающих методов.

Если, как в нашем случае, вторая ветвь является тождественностью, мы можем использовать when вместо ifElse:

const alwaysDrivingAge = age => when(lt(__, 16), always(16))(age)

Если первая ветвь условия является тождественностью, мы можем использовать unless. Если мы перевернём наше условие на использование gte(__, 16), мы можем использовать unless.

const alwaysDrivingAge = age => unless(gte(__, 16), always(16))(age)

Cond


Ramda также предоставляет функцию cond, которая может заменить выражение switch или цепочку выражений if...then...else.

const water = temperature => cond([
  [equals(0),   always('water freezes at 0°C')],
  [equals(100), always('water boils at 100°C')],
  [T,           temp => `nothing special happens at ${temp}°C`]
])(temperature)

Мне не понадобилось использовать cond в моём коде с Ramda, но я писал подобный код на Lisp много лет назад, так что cond чувствуется старым другом.

Заключение


Мы рассмотрели набор функций, которые Ramda предоставляет нам для превращения нашего императивного кода в декларативный функциональный код.

Далее


Вы могли заметить, что последние несколько функций, которые мы написали (forever21, drivingAge и water) все принимают параметры, создают новую функцию и далее применяют эту функцию к параметру.

Это распространённый паттерн, и вновь Ramda предоставляем нам инструменты для того чтобы привести всё это к более чистому виду. Следующий пост, «Бесточечная нотация» рассматривает способы, позволяющие упростить функции, следующие подобному паттерну.

Комментарии (33)


  1. AngReload
    14.04.2018 14:59
    +1

    Честно говоря, условия и сравнения в Ramda выглядят настолько запутывающими, что хочется использовать простые стрелочные функции вместо них.


    1. saggid Автор
      14.04.2018 15:17

      Мне кажется, что вы просто привыкли к императивной логике, и поэтому она кажется сейчас вам более простой, чем декларативная)


      Сравните два этих примера:


      const alwaysDrivingAge = age => age <= 16 ? 16 : age;
      
      const alwaysDrivingAge = when(lt(__, 16), always(16));

      Первый императивный, второй декларативный. Я чуток упростил второй пример, применив в нём "бесточечную нотацию", о которой рассказывается в следующей части серии, это не мешает ему оставаться рабочим.


      Вот для простого человека, который программирование знает совсем мало, какой из вариантов выглядит более очевидным сейчас?) Думаю, это дело привычки в большей степени. Не стоит торопиться с выводами, наверное надо немного поработать с написанием подобного кода, чтобы начать воспринимать его как нечто привычное.


      1. Zenitchik
        14.04.2018 15:52

        Первый императивный, второй декларативный

        Оба настолько просты, что могут считаться хоть декларативными, хоть императивными.
        Но стрелочная функция не содержит внешних зависимостей.


        1. saggid Автор
          14.04.2018 16:20

          Я рад за неё. Сжатый код всей рамды весит 12 килобайт. Примерно в 2.5 раза меньше текущего jquery и в 2 раза меньше лодаша. Код современных проектов обычно в сотни раз объемнее. При этом, с использованием рамды, есть определенная вероятность, что по конечному объему размер кода проекта выйдет даже меньшим, в силу большого количества переиспользования одних и тех же строительных блоков-функций, так что это спорное утверждение изначально.


      1. Riim
        14.04.2018 16:09
        +2

        Мне стало интересно сравнить производительность приведённых примеров. Вариант на Ramda оказался примерно в 200 раз медленнее. Код:


        const Benchmark = require('benchmark');
        const { always, lt, when, __ } = require('ramda');
        
        const alwaysDrivingAge1 = age => (age <= 16 ? 16 : age);
        const alwaysDrivingAge2 = when(lt(__, 16), always(16));
        
        const suite = new Benchmark.Suite();
        
        suite
            .add('ternal 32', () => {
                alwaysDrivingAge1(32);
            })
            .add('ramda 32', () => {
                alwaysDrivingAge2(32);
            })
            .add('ternal 5', () => {
                alwaysDrivingAge1(5);
            })
            .add('ramda 5', () => {
                alwaysDrivingAge2(5);
            })
            .on('cycle', evt => {
                console.log(String(evt.target));
            })
            .run({ async: true });

        Результат:


        ternal 32 x 399,197,552 ops/sec ±1.03% (80 runs sampled)
        ramda 32 x 1,906,899 ops/sec ±1.00% (87 runs sampled)
        ternal 5 x 422,652,247 ops/sec ±1.18% (82 runs sampled)
        ramda 5 x 1,914,890 ops/sec ±1.01% (87 runs sampled)


        1. saggid Автор
          14.04.2018 16:23

          Кто сомневался, что ванила быстрее библиотеки? Поэтому реакт и вью и проводят столько работ по оптимизации своего кода. Конечно на ваниле все в тысячи раз быстрее. Кроме скорости разработки конкретных фич в проектах)


          1. TheShock
            14.04.2018 16:44

            Кроме скорости разработки конкретных фич в проектах)

            Ирония в том, что на Ramda очень весело писать — чувствуешь себя таким умным, модным, функциональным, твой код столько краток и декларативен!

            А когда дело доходит до поддержки — даже фанаты Рамда боятся лезть в код, тем более чужой. Я уже два года даю ссылку на один пример:
            habrahabr.ru/post/279715/#comment_8812695

            Человек написал рамда-код и очень расхваливал фреймворк, но в коде закрался баг и, хотя я уже десять раз давал в разных спорах ссылку на этот комментарий — никто не смог его починить. Потому что код на Рамда совершенно неподдерживаемый. Он write-only


            1. saggid Автор
              14.04.2018 18:04

              Почитал, изучил тему, разобрался с кодом. Вообще, проблема конкретно в этом примере не связана с Ramda, она была связана с Rx.js. Пришлось немного изучить, как он работает и понять суть проблемы.


              Вот исправленный вариант, работает так, как вы хотели, без "бага": https://jsfiddle.net/a9m50xev/29/


              Мне хватило примерно получаса чтобы разобраться с проблемой. Естественно, функциональщина — это такая штука, с которой, наверное, сможет разобраться тот, у кого есть более-менее основательный опыт в программировании. Для меня лично логика вполне стала уловимой и ясной из вышенаписанного кода спустя где-то 20 минут изучения логики работы используемых функций, благо документация к ним имеется в открытых источниках.


              1. TheShock
                14.04.2018 18:43
                -1

                Для меня лично логика вполне стала уловимой и ясной из вышенаписанного кода спустя где-то 20 минут изучения логики работы используемых функций

                Скажите, вы правда считаете, что нормально то, что код в 20 строчек требует 20 минут на изучение, чтобы стать понятным человеку, который имеет, как вы сказали, более-менее основательный опыт в программировании? А что делать с кодом на 100 строк? С кодом на 1000 строк?

                Признайтесь честно, сколько времени у вас заняло понять логику работы моего императивного кода?


                1. saggid Автор
                  14.04.2018 18:57

                  Да это же чисто вопрос того, насколько ты привык шпилить проекты на Rx.js и Ramda. Если бы я пилил на них уже пару лет — я бы понял там всё намного быстрее.


                  Я согласен, что в данном случае императивный вариант оказался вполне хорош.


                  Вышеуказанный пример функциональщины я лично не могу никак посчитать идеальным. В нём много чего путает, в силу того, как его написал сам автор: десяток анонимных функций уже сам по себе сбивает с толку. Был бы я тимлидом в проекте, увидел бы такую портянку — раскритиковал бы автора за это и заставил переписывать на нормальные именованные функции-блоки, имеющие ясную логику работы. Вы в своём примере примерно это же и сделали ведь. С этим кодом надо бы сделать то же самое, а сейчас он действительно выглядит и страшным, и запутанным, я с этим не спорю. Но запутан он не потому что там используется функциональщина, а потому что автор не стремился к ясности, видимо очень ему хотелось именно "понтануться" различными вывертами функциональными, что я лично никогда не ценил в людях.


                  Однако, даже несмотря на все эти недостатки, в нём можно разобраться, можно его отрефакторить, сделать более чистым и ясным. Ещё хорошо бы знать Rx.js на нормальном уровне, чтобы сделать это ещё более качественным образом. У меня возникает ощущение, что этот код писал не совсем опытный программист, хотя-бы та же связка с жиквери немного обескураживает.


                  И вообще в этом случае, по-моему, не надо было совсем использовать Rx.js, ибо он не для подобных вещей, он скорее для реакции на множественные потоки событий предназначем, как я знаю. Он здесь просто излишен, ни к чему. Переусложнение без необходимости.


                  Можно написать намного более простую реализацию с использованием только рамды и нативной подписки на DOM-события, этого было бы более чем достаточно.


                  А говнокод может быть и в императивном коде ведь. Я очень не уверен в данный момент, что всякую функциональщину можно назвать "говнокодом" априори, как вы это пытаетесь сделать.


                  1. TheShock
                    14.04.2018 23:58

                    Я не говорю, что всякая функциональщина — говнокод. Я говорю, что:
                    1. В целом функциональщину в JS сложнее поддерживать
                    2. Большинство функциональщиков в JS считают себя офигенными экспертами, что пишут хороший и поддерживаемый код, а в итоге другие функциональщики должны потратить 20 минут на разбор 20 строк кода.
                    3. Практически любой неначинающий JS программист смог бы работать с моим кодом. Очень мало JS программистов смогли бы работать с кодом, на который я дал ссылку. Да и, уверен, с вашим кодом.

                    Так скажите — какие преимущества у использовании Ramda, если можно писать код, как у меня (вообще без библиотек), с теми же усилиями и получить значительно более легкую поддержку?


                    1. saggid Автор
                      15.04.2018 06:21

                      Вы наверное и редукс в проектах не используете, потому что слишком сложно? Знаете, на проект, использующий редукс, новичок без опыта точно также будет смотреть как баран на новые ворота. Только вот большинство людей этого мира все-таки понимают бенефиты от редакса (но не все старпёры хабра, надо заметить). Реакт тоже может быть довольно сложной асинхронной хернёй в некоторых случаях в силу своего управления стейта, однако мир современный он завоевал. И проекты, которые пишут на реакте и редаксе — они в реальности намного более более простые для понимания, я лично по своему опыту вижу, чем те проекты, в которых применяется некая самописная логика, подобная вашей. Но для человека, который в реакте и редаксе не разбирается — это будет адом в каком-то смысле. Ибо ему совершенно будет непонятно, что и как устроено. До того момента пока он не почитает вдумчиво официальную документацию к инструментам. Точно также с рамдой. Я честно вообще не вижу здесь пространства для споров, хотя посетители хабра иногда меня конечно удивляют подобными вышеуказанными статьями. Уже половина мира использует редакс — но на хабре есть масса людей, которые считают, что редакс это вообще плохо… Как-бы нам в своём мирке таким макаром не остаться совсем, даже железного занавеса никакого не нужно, достаточно подобного вашему стремления подтасовать факты в своих измышлениях и успокоиться на этом, как на высокообъективных доказательствах.


                      Я наверное дальше не буду обсуждать это, извините. Для меня лично просто всё понятно в этом плане. Я не знаю что тут дальше привести, зачем тратить время на обсуждение этого. Если у вас другое мнение — я рад за то, что вы способны его иметь и высказывать. А спорить я не люблю.


                      1. TheShock
                        15.04.2018 15:41
                        +1

                        Вы наверное и редукс в проектах не используете, потому что слишком сложно?
                        Нет, потому что слишком быдлокодерски. И я его использовал и понял, насколько он делает код хуже. Так зачем его использовать, если есть прекрасная альтернатива в виде MobX?

                        Только вот большинство людей этого мира все-таки понимают бенефиты от редакса
                        Вы ведь понимаете, что это тоже логическая ошибка, по аналогии с вашей ссылкой.

                        Я вот считаю, что Редакс стал таким популярным за счет пиара его автора, что можно быдлокодить не задумываясь и при этом подавать себя как крутого прогрессивного разработчика

                        А в подтверждение моих слов выходят статьи с таким бредом:
                        Async/await это шаг назад для JavaScript'a?… Мы начинаем обучение некоторым из его принципов. Изучаем новые слова, такие как функторы, монады, моноиды — и вдруг наши dev-друзья начинают считать нас крутыми, потому что мы используем эти странные слова довольно часто!
                        И потому Async/await — это плохо.

                        А еще подтверждение тот код, который я дал. Его автор искренне считал, что он — очень крутой, потому что функциональный. Он не думал о легкости поддержке, он думал он функциональности.

                        Реакт тоже может быть довольно сложной асинхронной хернёй в некоторых случаях в силу своего управления стейта, однако мир современный он завоевал
                        А теперь вы используете вторую логическую ошибку — подмену понятий. Я нигде не говорил, что реакт — плох. Наоборот, я считаю его — прекрасным инструментом, заслужено получившим свою славу.

                        Уже половина мира использует редакс — но на хабре есть масса людей, которые считают, что редакс это вообще плохо
                        Второй раз ту же логическую ошибку. Конечно плохо, а то, что есть люди, которые клюнули на этот маркетинг — далеко не показатель.


                        1. saggid Автор
                          16.04.2018 11:46

                          Давайте я напишу вам один раз одно большое сообщение, подробно разъясняющее пару некоторых важных моментов, на которое впоследствии буду просто отправлять вас и подобных вам людей, чтобы не повторяться.


                          В ваших словах как всегда светится желание возвысить один инструмент до небес и доказать, что другой — это результат "быдлокодерства", то есть там вообще всё изначально неправильно, как я понимаю. С вашей точки зрения. Потому что функциональщина, и так далее.


                          Альтернативой redux вы назвали mobx. Хорошо хоть не ту mvc-приколюху из соседней статьи от ненавистника редакса, в которой вызывается forceUpdate на каждое изменение. Я посмотрел на mobx, вижу, что в основе идея практически та же самая: inject + observer вместо connect у редакса, классы-сторы, вместо экшенов и единого хранилища у редакса. Вижу что он более простой и изначально решает меньше проблем и предоставляет меньше возможностей, при этом работает он на основе внутренней магии, т.е. мы доверяемся заклинаниям разрабов mobx и должны молиться, что всё просто будет хорошо. Мне уже на этом моменте не слишком всё нравится, особенно после распиаренного "убийцы пыхи" Ruby, авторы которого столько сил потратили на пропаганду монки патчинга, из-за чего потом стали терять даже core-контрибьютеров больших проектов. Спасибо, я лично лучше на пхп останусь: явное лучше неявного.


                          Ну да вернёмся к mobx. Что мы теряем сразу, отбрасывая "быдлокодерский редакс"?


                          • возможность осмотреть историю изменения состояния всего хранилища, в том числе путешествовать по ней
                            и возможность быстрой реализации отмены изменений в приложении
                          • более ясную структуру, в которой есть конкретные чистые функции, изменяющие хранилище (редюсеры), и функции, которые занимаются сайд эффектами (экшены и мидлверы), вместо этого будем писать… ну наверное какие-то приколюхи, кто во что горазд, как я понимаю. В итоге будем иметь 100500 вариаций каждого компонента проекта, ибо никто нас не ограничивает в этом. С каждой из них, конечно же, разбираться надо будет отдельно, в отличии от "быдлокодерского" редакса, в котором каждый проект практически однотипен и сразу понятен любому, кто изучил док-цию к редаксу
                          • возможность писать мидлверы, которые могли бы реагировать на изменение хранилища и делать что-то полезное, вроде вызовов api или логирования, или ещё чего угодно

                          И это как минимум. Я просто глубоко не вдавался в различия. Ну да, зато "быдлокодерской функциональщины" у нас в проекте больше не будет. Да, можно ещё закинуть в mobx-проект плагин mobx-state-tree и получить в итоге практически тот же redux, но на заклинаниях, и после этого молиться, чтобы вся эта смесь не заглючила в один прекрасный день, когда нам неожиданно придётся разбираться в магии mobx'а. Но вообще, зачем было изначально уходить от редакса, если к нему всё равно в итоге приходим?


                          Давайте почитаем цитаты людей, сравнивающих mobx и redux. Я почитал три статьи (1,2,3) на эту тему. Я надеюсь, вы способны воспринимать другие мнения людей из этого мира, не может же быть, наверное, что вы на этом земном шаре — самый умный и знаете 100% больше других? Давайте приведём некоторые цитаты из вышеуказанных статей:


                          И вот, что я думаю в вопросе выбора между, MobX и Redux. Если вы в процессе изучения React и его экосистемы, если вы только планируете начать свой путь во front-end и ищете работу над проектом на React, изучайте Redux, практикуйте Redux, он повсюду, он везде.

                          На практике, мы имеем успешные проекты всех типов. Маленькие и большие. И на Redux и на MobX.

                          Redux сегодня, это как азбука для React разработчика. А Mobx, опциональное знание для интересующихся.

                          3 Reasons Not to Use MobX:
                          1. Too much freedom
                          2. Hard to debug
                          3. There could be a better alternative to MobX

                          Для начала mobx, несмотря на то что его сравнивают с другими библиотеками как библиотека для управления состоянием, не предоставляет практически никаких удобств для работы с состоянием за исключением вызова обновления компонентов реакта

                          Я понял, что mobx — это интересная штука, спасибо за это. Но говорить, что redux — это говно, а mobx — это идеал — тоже неправильно как-бы. Как минимум, мы видим, что проблемы имеются в том числе и у mobx, а вероятность написать кучу говнокода, особенно если ты только начинаешь фронтенд-карьеру — намного выше. Соответственно, мы тут изначально обсуждали, где будет больше говнокода — получается, что говнокода всё-таки будет больше именно вместе с mobx, а не с redux'ом.


                          Я вот считаю, что Редакс стал таким популярным за счет пиара его автора

                          Забавно кстати, тот же автор редакса хвалит в том числе и mobx в своём же твиттере. Опять наглый пиар!.. Суда на них нет, одни пропагандисты-обманщики..


                          Как мы видим, как всегда нет в реальном мире "говёного редакса" и "идеального mobx'а". Всё гораздо более сглаженно, и хорошие стороны есть и у первого, и у второго решения. И в реальности почти всегда бывает именно так.


                          Что очень важно для меня лично, и надеюсь, что когда-нибудь станет важным и для вас в том числе: подобное поведение встречается в СНГ слишком часто. Мне трудно жить в таком обществе. В большинстве своём, люди не способны оценивать всё умеренно, спокойно и с уважением. Они постоянно перелетают из одной крайности в другую. От любви до ненависти один шаг, как говорится. Сегодня вы топите за mobx и императивный код, завтра "прозреете" и начнёте топить за какой-нибудь HypeX, а всё остальное называть "говнокодерством".


                          У вас может уже и было подобное ранее, а? Наверное PHP поунижать успели за "говнокодинг", наверное тоже уверены, что он никому нинужен. Правда Laravel вот нынче имеет больше звёзд на гитхабе, чем Rails и Django (42 146 vs 39 345 vs 33 221). Да и Facebook, Vk, Wikipedia, Badoo, и прочие спокойно применяют PHP в своих проектах уже многие годы, никуда не собираясь мигрировать, а разрабы Slack вообще пишут в своём блоге о том, что PHP сейчас — это в целом лучший вариант для написания нового веб-проекта. Опять, наверное, наглый пиар разрабов PHP.


                          Я в своё время писал о Riot.js на хабре — меня точно также закидывали говном в комментариях. Это правда не помешало мне применить его в разработке двух больших международных проектов и одном своём личном. Да и сейчас он остаётся моим личным любимчиком для написания небольших решений в силу своей простоты.


                          Это я всё пишу к тому, что такой "экстермизм" в своих убеждениях, подобным вашим, когда один инструмент возвышается до небес, а другой втаптывается всеми правдами и неправдами на уровень "говёного поделия" — это больше от невежества и страстей, чем от нормального знания.


                          Вы же сейчас пытаетесь топить вообще против всякой функциональщины, притягивая за уши "доказательства" оттудова и отсюдова — откуда угодно, лишь бы доказать свою точку зрения. Неужели вы действительно уверены в том, что любой код, написанный в функциональном стиле — априори говёный? Вам самому не кажется это утверждение глупым? Неужели нельзя написать говнокод в императивном стиле? Вы что, не видели на своём веку такого? Так чего удивительного в том, что на функциональной логике тоже можно написать говнокод?


                          Вас бесит функциональщина за то, что она не решает все проблемы мира и даже не объясняет смысл жизни? Я с вами вообще не спорю на эту тему. Программирование — это всегда поиск компромиссов. Я не фанат функциональщины, не фанат редакса, не фанат реакта, не фанат ООП, императивщины и любого другого X. Я стараюсь изучать этот мир и применять то, что наиболее рационально в конкретной ситуации.


                          Я пишу статьи о Ramda для общего образования, чтобы знать, как она работает. Чтобы поэкспериментировать с нею в будущем. И если она докажет свою эффективность и полезность — то я скорее всего буду применять её в своих проектах. Даже если на хабре найдётся тысяча людей, которые из-за страстей своих назовут её говёным поделием, как назвали ранее массу других инструментов, признанных, при этом, всем остальным миром как доказавшие свою эффективность.


                          Моя к вам просьба: больше умеренности и мягкости. Это просто культура. Это уважение к людям, к моему труду в том числе. Я постараюсь просто отправлять ссылку на это сообщение, если в очередной раз буду видеть подобную тенденцию в общении. Я не желаю общаться на таком уровне, мне не интересно унижать одно и возвышать другое. Мне интересно принести людям пользу, дать им знания, и самому узнать что-то ещё, и умеренность и осторожность в своих выводах никогда не была плохой вещью в таких делах.


                          1. TheShock
                            16.04.2018 13:12
                            +2

                            В ваших словах как всегда светится желание возвысить один инструмент до небес и доказать, что другой — это результат «быдлокодерства», то есть там вообще всё изначально неправильно, как я понимаю. С вашей точки зрения. Потому что функциональщина, и так далее.
                            Э нет, опять вы подменяете мои слова.
                            1. Я предположил, что ФП вцелом сложнее поддерживается, а не сказал, что весь ФП — говнокод.
                            2. Да, я считаю, что Редакс поощряет говнокод, но, в первую очередь потому что у него такая архитектура, а не из-за ФП
                            3. Я считаю, что Редакс больше процедурный, чем функциональный. В нем есть функциональные элементы, но это не делает его полностью ФП

                            изначально решает меньше проблем и предоставляет меньше возможностей
                            Аргументируйте

                            доверяемся заклинаниям разрабов mobx и должны молиться, что всё просто будет хорошо
                            Всмысле «молиться»? Я никогда не молился, оно просто работает.

                            пропаганду монки патчинга
                            Подмена понятий. MobX не использует манки-патчинг.

                            явное лучше неявного.
                            А абстракции — зло? Вы из этих?

                            более ясную структуру, в которой есть конкретные чистые функции, изменяющие хранилище

                            Или менее ясную структуру

                            вместо этого будем писать… ну наверное какие-то приколюхи, кто во что горазд, как я понимаю

                            То есть это про MobX выходят десятки статтей «как я сделал МобХ совсем другим»? Это в МобХ существуют mobx-thunk, mobx-saga, которые полностью меняют идеологию использования?

                            С каждой из них, конечно же, разбираться надо будет отдельно, в отличии от «быдлокодерского» редакса, в котором каждый проект практически однотипен и сразу понятен любому, кто изучил док-цию к редаксу

                            Скажите, вы пользовались MobX? Видимо, нет.
                            Потому что я Редаксом пользовался. И прекрасно знаю, что каждый пишет кто во что гаразд. Названия действий в константы выносятся или нет? Или может генерируются? Чистый или танки или саги? Или какая-то другая улучшалка? Композиция функций или миддливейр? Какой-то процент логики в Миддлвейре, какой-то во Вьшке, какой-то в АкшнКриэйторе. В итоге логика размазана фиг знает где.
                            Хреновая архитектура Редакса создает проблемы, которые решаются костылями. В МобХ этих проблем просто нет. Ты просто пишешь хороший, понятный код.

                            Но вообще, зачем было изначально уходить от редакса, если к нему всё равно в итоге приходим?
                            Опять же, очевидно, вы МобХ не пользовались.

                            Как минимум, мы видим, что проблемы имеются в том числе и у mobx, а вероятность написать кучу говнокода [...] — намного выше
                            Где вы успели сделать такой вывод?

                            Соответственно, мы тут изначально обсуждали, где будет больше говнокода — получается, что говнокода всё-таки будет больше именно вместе с mobx, а не с redux'ом.
                            Снова. Я что-то не увидел, как вы смогли прийти к этому.

                            Забавно кстати, тот же автор редакса хвалит в том числе и mobx в своём же твиттере
                            Он не хвалит архитектуру или подход МобХ. Он признает, что по цифрам он быстрее его поделки. И что?

                            Как мы видим, как всегда нет в реальном мире «говёного редакса» и «идеального mobx'а»


                            Сегодня вы топите за mobx и императивный код

                            Не, погодите. Давайте еще раз определимся:
                            1. Я искренне считаю, что редакс — найбольший провал фронтенда за последнее время, это да. И понимаю, что он в этом похож на первые версии php — поощряющие быдлокодинг и потому столь популярные.
                            2. Я не вижу преимущест ФП, но правда хочу их увидеть. Пока я вижу, что на ФП удобно писать локальную обработку данных, а архитектуру вцелом писать императивно. Тут я подозреваю, что могу ошибиться, потому и холиварю, чтобы в споре прийти к истине.
                            3. Не смешивайте редакс и фп. Редакс функциональный больше в рекламных материалах, чем в реальной жизни.

                            Наверное PHP поунижать успели за «говнокодинг», наверное тоже уверены, что он никому нинужен

                            Но ведь первые версии и правда были не очень. Вспомните «Волшебные кавычки», впомните Register_Globals, вспомните поглощение ошибок, впомните все документации, где примеры запросов делались с SQL-инъекциями. Я хорошо помню, что было безумно сложно найти тексты, где описаны хорошие, годные практики, а не всякое говнокодище.

                            И, возможно, такие комментарии как мои про редакс и привели к тому, что всего этого больше нет и phpшники поняли, что лучше пользоваться Laravel, а не быдлокодить, как это делали 80% пхп-программистов того времени. Или вы считаете, что они тоже обладали тайным знанием и все делали правильно, как сейчас пользователи редакс?

                            это больше от невежества и страстей, чем от нормального знания.
                            Обратите внимание, я пользовался в практической разработке обоими инструментами. И я к редаксу пришел открытый и без предрассудков. Вот правда. Я честно думал, что это — хороший инструмент. Пока не начал его использовать, пока не начал читать статьи о нем. Видите ли, я не успел поверить в то, что Редакс — идеален до того, как попользовался, меня не успела накрыть волна маркетинга и в итоге я просто сложил про него независимое мнение в поле.

                            Вы же сейчас пытаетесь топить вообще против всякой функциональщины
                            Неправда.

                            Неужели вы действительно уверены в том, что любой код, написанный в функциональном стиле — априори говёный?
                            Ни в коем случае. Потому я и прошу — покажите мне хороший, поддерживаемый код. Я хочу тоже научиться такой писать.
                            Потому что когда я прошу об этом, то мне, обычно показывают код совсем не поддерживаемый, а представляют как вершину мысли.
                            Я искренне верю, что его можно писать. Может, просто, JS не подходящий язык для этого?
                            Но я уверен, что код на Редаксе — априори говёный. Обратите внимание, не функциональный, а код на Редаксе. Меня, правда, некоторые люди убеждали, что пишут не говенный код, но так и не показали его. Пока весь код на редаксе, который я видел — или говенный или тудушка на 2 страницы.

                            Вас бесит функциональщина
                            Ни в коем случае. Я ею сам пользуюсь. Кое-где. Я даже хотел написать движок своей игры в функциональном стиле, ибо он идеально подходит под мою игру (значительно больше, чем ООП, правда), но не решился переходить на F#, а на C# иммутабельные объекты изменять слишком неудобно.


                            1. Zenitchik
                              16.04.2018 14:12

                              Может, просто, JS не подходящий язык для этого?

                              Можно поинтересоваться, в целях повышения образованности, а чего конкретно не хватает JS чтобы быть подходящим для ФП?


                              1. TheShock
                                16.04.2018 14:24

                                Я не утверждаю, что это так и есть, там стоял знак вопроса и я правда спрашиваю. Просто предположил на основе общения с людьми, которые пользовались другими ФП языками. Они утверждают, что на других языках и правда в ФП стиле код получается намного лучше, но мопед не мой.
                                Вот например, насколько я знаю, в них есть мощная система типов с автоматическим выведением, которая работает в Compile-time.


                            1. saggid Автор
                              17.04.2018 07:51

                              изначально решает меньше проблем и предоставляет меньше возможностей
                              Аргументируйте

                              Что аргументировать после того что было уже написано? Я уже объяснил всё наверху, как вы читали? Давайте я процитирую сам себя:


                              Что мы теряем сразу, отбрасывая "быдлокодерский редакс"?
                              • возможность осмотреть историю изменения состояния всего хранилища, в том числе путешествовать по ней и возможность быстрой реализации отмены изменений в приложении
                              • более ясную структуру, в которой есть конкретные чистые функции, изменяющие хранилище (редюсеры), и функции, которые занимаются сайд эффектами (экшены и мидлверы), вместо этого будем писать… ну наверное какие-то приколюхи, кто во что горазд, как я понимаю. В итоге будем иметь 100500 вариаций каждого компонента проекта, ибо никто нас не ограничивает в этом. С каждой из них, конечно же, разбираться надо будет отдельно, в отличии от "быдлокодерского" редакса, в котором каждый проект практически однотипен и сразу понятен любому, кто изучил док-цию к редаксу
                              • возможность писать мидлверы, которые могли бы реагировать на изменение хранилища и делать что-то полезное, вроде вызовов api или логирования, или ещё чего угодно




                              На тему магии.


                              Давайте я более подробно разверну вышенаписанную цитату того человека, который пишет на mobx и в том числе имеет свой небольшой бойлерплейт для него. Вы скорее всего статьи mobx не пишете и бойлерплейт для него не имеете, по крайней мере его слова будут более объективны в какой-то степени.


                              Он пишет в своей статье в одном из разделов под названием 3 Reasons Not to Use MobX:


                              Too much freedom
                              Redux is a framework that provides strict guidelines on how you write state code. This means you can easily write tests and develop maintainable code. MobX is a library and has no rules on how to implement it. The danger with this is that it’s very easy to take shortcuts and apply quick fixes that can lead to unmaintainable code.

                              Hard to debug
                              MobX’s internal code “magically” handles a lot of logic to make your application reactive. There’s an invisible area where your data passes between the store and your component, which makes it difficult to debug when you have a problem. If you change state directly in components, without using @actions, you’ll have a hard time pinpointing the source of a bug.

                              There could be a better alternative to MobX
                              In software development, new emerging trends appear all the time. Within a few short years, current software techniques can quickly loose momentum. At the moment, there are several solutions competing with both Redux and Mobx. A few examples are Relay/Apollo & GraphQL, Alt.js and Jumpsuit. Any of these technologies has the potential to become the most popular. If you really want to know which one is best for you, you’ll have to try them all.

                              Слишком много свободы для написания говнокода. Трудно отлаживать, если вылезут проблемы из-за магии и отсутствия нормальной истории изменений хранилища. И тут может быть более подходящая альтернатива.


                              Всмысле «молиться»? Я никогда не молился, оно просто работает.

                              Это как в Руби тоже всё "просто работает"? А потом оттуда уходят разрабы со словами о сообществе: I’m pretty damn sure that my proposals would end up being drastically downvoted. Monkey-patches? C’mon, not a problem, we love our 10.years.ago! New abstractions? Who needs that, Rails is SIMPLE!. Суть в том, что сейчас оно, возможно, работает, но в один прекрасный момент начнутся проблемы из-за магии, из-за которых вы проведёте 5 часов в дебаге и, надеюсь, сможете найти корень проблемы. А может и не сможете, прям как те авторы "говяной функциональщины", о которой вы ранее писали.


                              Подмена понятий. MobX не использует манки-патчинг.

                              Я где-то писал что он его использует? Помимо монки патчинга в мире есть другие заклинания, и он использует их. Мне это не нравится, я не склонен доверять магии просто изначально, и для меня такая методика работы — это и есть говнокод. Видимо, мы сейчас приходим к тому, что для каждого из нас понятие "говнокода" — это уже субьективная вещь, вам нравится магический mobx, мне нравится более явно работающий redux.


                              То есть это про MobX выходят десятки статтей «как я сделал МобХ совсем другим»?

                              Господи, да просто потому что mobx в сотни раз менее популярен чем redux, всё. Был бы популярнее — имел бы точно такое же кол-во статей про варианты организации кода. Конечно в мелочах можно писать по-разному, но вы же понимаете, что основа остаётся той же самой: редюсеры, хранилище и экшены. Основа не меняется и легко улавливается.


                              Скажите, вы пользовались MobX? Видимо, нет. Потому что я Редаксом пользовался. И прекрасно знаю, что каждый пишет кто во что гаразд.

                              Я-то не пользовался, но авторы вышепроцитированных статей его использовали, да и мой опыт говорит о моей нелюбви к магии.


                              Он не хвалит архитектуру или подход МобХ. Он признает, что по цифрам он быстрее его поделки. И что?

                              Опять спорите. Это указание на его в целом желание добра и mobx в том числе. Если бы он занимался "наглым пиаром" своего говяного поделия, он наверное написал бы что-то мерзкое про mobx, вместо чего-то хорошего? Он таким не занимается, потому что, скорее всего, целей таких и не имел, а вам просто кажется.


                              Наверное PHP поунижать успели за «говнокодинг», наверное тоже уверены, что он никому нинужен
                              Но ведь первые версии и правда были не очень.

                              Ну блин, и первые версии mobx тоже были не очень, я вполне уверен. Сейчас уже 4-я мажорная ветка развивается. Однако дело в том, что на PHP уже начиная с ерсии 5.3, которая вышла в 2009, можно было писать нормальные качественные проекты, чем люди и занимались. Но множество других продолжают называть PHP "говёным поделием" даже сегодня, в 2018-м году.


                              Я искренне считаю, что редакс — найбольший провал фронтенда

                              Ну я за вас рад, а я считаю это прорывом после нескольких лет эры бекбона. Я лично намного более счастлив с одним глобальным хранилищем, с ясной логикой проекта, когда я могу за пару недель войти в реально большой проект и понять всю его логику, просто потому что она везде однотипная. Вы считаете это говнокодом, я считаю это прекрасной в целом вещью. Опять видимо тут субьективщина пошла. Я не могу с этим ничего сделать, могу лишь сказать, что я с вами не согласен. Всё.


                              Я честно думал, что это — хороший инструмент. Пока не начал его использовать, пока не начал читать статьи о нем

                              Да я вот тоже его использую и читаю статьи о нём в последний год примерно. Всё очень хорошо у меня лично. Вот честно не знаю, от чего у людей к нему прямо такое отторжение идёт. Удобный, понятный инструмент. Идея редюсеров мне очень нравится в целом.


                              Но я уверен, что код на Редаксе — априори говёный.

                              Снова начинается желание доказать, что одно говно, другое не говно. Да и это чистая субьективщина. Я уже достаточно написал про редкас, мне опять самого себя цитировать и здесь? Вот в этом проблема. Я почти уверен, что если я приведу вам любой код, который не будет в вашем стиле — вы назовёте его "априори говёным". Ну и какой смысл тут общаться? Почему я вообще должен вам что-то доказывать в такой манере общения, когда вы называете всё, чего я придерживаюсь — "говёным поделием"? Вы понимаете, что культуры напиания кода могут быть разными? И каждая культура эффективна в той или иной мере. Мы с вами никогда не договоримся, если не будет этого понимания.


                              Возвращаясь к функциональщине. Я сам вообще далеко не спец в ФП. Я эти статьи перевожу для себя в том числе, чтобы лучше их понять, как я уже писал ранее. У меня даже проектов на ФП сейчас нет. Поэтому пока что и показывать в том числе нечего. И вообще ФП сейчас слишком неразвито, особенно в СНГ. Поэтому и примеров нормальных не имеется практически. Поэтому я и перевожу статью об основах работы с рамдой.


                              Каждый раз хочется закончить обсуждение, но каждый раз вы заставляете лезть объяснять вам всё, иногда цитируя себя же самого, что я писал ранее. Извините, наверное это всё-таки последний мой ответ вам. Время ценная штука, я уже потратил целый час на написание этого текста. Мог бы заняться чем-то более полезным. Цените время людей и цените своё время в том числе. До свидания.


                            1. saggid Автор
                              17.04.2018 09:30

                              Потому я и прошу — покажите мне хороший, поддерживаемый код. Я хочу тоже научиться такой писать.

                              Да, вот кстати, на эту тему забыл ещё кинуть пару примеров, правда на англицком.


                              Обрабатываем логи вместе с Ramda и трансдюсерами
                              Используем Ramda вместе с Redux


                              Возможно я переведу эти статьи тоже после завершения перевода данного цикла статей о рамде, мне кажется, что они занимательные.


                          1. faiwer
                            16.04.2018 16:39
                            +2

                            в котором каждый проект практически однотипен и сразу понятен любому, кто изучил док-цию к редаксу

                            Вы очень-очень ошибаетесь ;) Если не придерживаться вот этой мантры, то вы можете вкусить все 50 оттенков redux+react-а. А если вспомнить то, как готовят redux некоторые товарищи (например пишут почти всю логику в "экшонах"), то смею вас заверить, от некоторых проектов у вас… вам поплохеет.


                    1. saggid Автор
                      15.04.2018 06:33
                      +2

                      Вообще, говоря честно, наверное надо было серию статей писать где-то на другом ресурсе. Теперь я это понимаю. Наверное я их все удалю и перенесу в какое-то другое место позже. Главное чтобы в поисковых системах светились. Честно говоря я просто устал, что вместо хоть сколько нибудь нормальной реакции получаешь как обычно копну зачастую нерациональной критики, на которую потом ещё тратится моё личное время и нервы. И почти ни одного поста, который дал бы мне нечто полезное. Зачем я вообще закидывал сюда посты о рамде? Чтобы какие-то старпёры хабра, простите, доказывали мне, что я идиот, который вообще не понимает зачем это нужно? Я не ради этого переводил статьи.


                      1. AngReload
                        15.04.2018 14:46

                        Стыдно мне. Когда писал первый комментарий, не думал что этого дойдёт.


                        1. TheShock
                          15.04.2018 15:33
                          +1

                          Стыдно должно быть автору. Такие комментарии — это вполне нормально и устраивать из-за них истерику — это совершенно странно. Тем более на такую узкую тему.

                          Вы высказали свое мнение, высказали его корректно, а значит стыдаться тут нечего


            1. saggid Автор
              14.04.2018 18:28

              Вообще, там надо банально хранить где-то историю выбранных значений, наверное, чего в коде с использованием rxjs и рамдой не делается в данной реализации. Но это можно исправить, переписав немного код по другому. Примерно как в том примере с императивной реализацией, которую вы написали. Для человека достаточно развитого это вряд ли станет проблемой. Вся суть лишь в том, что надо индекс последнего активного элемента где-то хранить и вытаскивать при клике с зажатым шифтом. Вроде для меня всё стало ясно и понятно. Вопрос с "непонятностью" функциональщины на этом, надеюсь, в какой-то степени снимается с повестки)


          1. Riim
            14.04.2018 17:07
            +1

            > Кроме скорости разработки конкретных фич в проектах

            сильно зависит от размера проекта. Небольшие проекты действительно очень интересно делать на ФП. Небольшие до того момента пока весь проект способен уместиться в голове одного человека. Когда проект выходит за эти рамки многие восхваляемые плюсы ФП показывают свою обратную сторону. Скорость добавления новых фич остаётся примерно на том же уровне, но вот добавляется их очень мало, тк. основное время уходит на латание багов, скорость добавления которых тоже бьёт все рекорды.


      1. zvulon
        14.04.2018 17:20
        +3

        очевидно это просто написать

        const alwaysDrivingAge2 = age => Math.max(age, 16)
        

        тк понятно что происходит. А все эти lt, gt пусть в баше остаются
        вобщем я тоже когда то кипятком писал о функциональщины и усложнения
        потом все же образумился и теперь стараюсь писать как можно более тупой код.
        императивный в основном. тк быстрее и проще.


        1. saggid Автор
          14.04.2018 20:26

          Ну окей, тогда код на рамде можно упростить ещё сильнее, на основе вашего подхода:


          const alwaysDrivingAge = max(16)

          Я абсолютно серьёзно, оно работает, именно так, как надо.


          Вы уже второй, кто меня пытается уличить в "усложнении", хотя я вообще в конкретно этой сериии статей вижу наоборот такие подходы, которые код как раз упрощают и сокращают, а не наоборот.


      1. DarthVictor
        15.04.2018 02:17

        Замена инфиксных и тернарных операторов на префиксные функции делает код декларативным?


  1. zim32
    15.04.2018 22:40
    +3

    Еще один инструмент который делает тоже самое но необходимо его учить. В чем профит не пойму


  1. Neiromaster
    16.04.2018 14:13

    Много ошибок по тексту. Материал полезен, но перед публикацией хорошо бы вычитку проводить.


    1. saggid Автор
      16.04.2018 14:15

      Я честно его прошерстил пару раз и исправил всё, что заметил, но я такой же простой смертный, как и многие другие. Можете написать сюда или в личку свои замечания, два простых смертных всегда лучше одного. Воспринимайте это как помощь друг другу в полезном деле.


    1. TheShock
      16.04.2018 14:25
      +1

      Много ошибок по тексту

      Такие вещи принято писать в личку. Хотите помочь — напишите туда ошибки, которые заметили. А просто замечание в воздух не имеет никакого смысла.


  1. andreylartsev
    17.04.2018 10:31

    Почему в качестве примера декларативных языков программирования всегда приводят Prolog? Хотя к нашим современным реалиям более близки HTML / CSS или SQL которые являются классическим декларативными языками программирования.