Композиции для функций

JavascriptФункцииКомпозиция

Итак. Сегодня, так получается, очень много разговоров, что, композиции должны всё "упростить". Особенно в JavaScript. Потому что нельзя просто так взять и сделать правильный подход к коду - нужно накинуть туда кучу функционала, чтобы его потом отменить. Но, не про то.

Что такое композиции в функциях

Как это выглядит в нашей "легаси" жизни? Был некоторый разработчик Вася, у которого была задача. Он получал со стороннего API список потенциальных клиентов. После ему нужно выбрать только платежеспособных. После, только мужчин в возрасте до 30. Дальше из имени и фамилии нужно составить целое. А, после, посчитать и сравнить шанс на успех в заключении контракта по чудесной чудо-формуле придуманной бизнес-аналитиками и добавить результат в объект клиента. Например. И он начинает и получает что-то такое:

const clients = await externalApiCall();

const result = clients
  .filter(client => выбирает платежеспособных)
  .filter(client => выбирает мужчин младше 30)
  .map(client => прибавляет имя к фамилии)
  .map(client => высчитывает всё по чудо формуле)
  .filter(client => отбрасывает всех, кто не прошёл по чудо-формуле);

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

function filterClients(val) {
  // только платежеспособные мужчины до 30
}

function fullName(val) {
  // прибавляем имя к фамилии
}

function chudoFormula(val) {
  // считаем по чудо формуле и отбрасываем что не нужно
}

const clients = await externalApiCall();

const getAllValidClientsComposition =
  (client) => chudoFormula(
      fullName(
        filterClients(client);
      );
  );

const result = clients
  .map(getAllValidClientsComposition)
  .filter(client => !!client); //  фильтр на несуществующее        

Такой код сработает быстро. Васю это устраивает и он переходит к следующей задаче. Это не плохо. Но можно лучше!

Пайплайны из stage 1

Вряд ли они увидят свет. Но сейчас немного их хайпуют, поэтому покажу. Смотрите, какой наглядной станет наша композиция:

const getAllValidClientsComposition =
  filterClients(client)
  |> fullName
  |> chudoFormula;

Теперь всё читается сверху-вниз, как и должно. Только когда это будет - наверное - никогда.

Композиция промисами

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

const getAllValidClientsComposition = Promise.resolve(clients)
  .then(filterClients)
  .then(fullName)
  .then(chudoFormula);

const compositionArray = clients.map(client => getAllValidClientsComposition(client));
const result = await Promise.all(compositionArray);

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

Зачем вообще эти композиции функций

Сама суть композиции какая? Несколько чего-то используется вместе. Так и с функциями - несколько функций используются вместе. Вы можете просто заранее сделать композицию и использовать её в разных частях кода в разных файлах. Это крайне удобно.