вступление

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

Смелая новая Рамда

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

Когда я начал использовать Ramda, я испытал эффект «WOW». Мне понравилось, насколько элегантно стал мой код декларативным, а все полезные функции его инструментария позволили мне выразить сложную логику в одном операторе. Каждый раз, когда мне удавалось решить с ним задачу, я ощущал чувство вознаграждения в своем мозгу. Чем больше логики мне удавалось включить, тем большее удовлетворение я получал. Помимо этого мнения, Ramda действительно улучшила код во многих отношениях, таких как сохранение неизменности данных, расширение возможностей декларативных выражений и решение многочисленных рутинных задач с помощью удобного набора помощников, среди прочих преимуществ.

Упадок Ramda и возрождение JavaScript

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

Вы когда-нибудь сталкивались с приятным чувством написания простого кода без суеты, используя только встроенные функции языка? Бьюсь об заклад, у всех нас есть. Как разработчики, мы часто тяготеем к тому, что знаем лучше всего, и в данном случае это старый добрый нативный JavaScript.

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

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

Давайте начнем с функций более высокого порядка, таких как map(), reduce() и filter(), работающих с массивами, которые превратились в легкий ветерок. Это было так же просто, как пирог.

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

Затем появились шаблонные литералы — они изменили способ обработки строк. Больше никакой беспорядочной конкатенации, только гладкое и надежное создание строк.

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

Использование нативных функций JavaScript дает ощущение комфорта и простоты, знакомство, которое позволяет разработчикам творить без дополнительных уровней обучения. Многих из нас привлекает ядро ​​языка, сама ткань, из которой он соткан. И почему бы нет? Эти нативные функции являются не только сердцем JavaScript, они также разработаны с учетом производительности, такие же легкие и гибкие, как газель.

По сравнению с такими библиотеками, как Ramda, которые оборачивают ваш код дополнительным уровнем абстракции, нативный JavaScript работает так же быстро, как бурлящая река.

Эти функции выигрывают от оптимизации в движках JavaScript, таких как V8. Создатели V8, движка Google Chrome и Node.js, постоянно оптимизируют эти нативные функции. Это обеспечивает еще более плавное и быстрое выполнение, заставляя ваш код JavaScript работать как хорошо смазанная машина.

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

Еще одна замечательная особенность нативного JavaScript — его совместимость с различными версиями ECMAScript и тот факт, что он имеет минимальные зависимости. Это язык, который постоянно совершенствуется благодаря постоянным обновлениям ECMAScript. Этот постоянный рост и адаптация делают нативный JavaScript лучшим выбором для многих разработчиков. Зачем искать что-то новое, когда оригинал так хорошо справляется со своей задачей?

Бьетесь головой о рамдамизированный TypeScript

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

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

Еще одна проблема заключается в функциональном стиле программирования Ramda с его причудливым каррированием и композицией функций. Вывод типов TypeScript может с трудом успевать за всеми поворотами, поэтому вы можете добавить явные аннотации типов или дополнительные утверждения, чтобы держать все под контролем. Это может стать немного запутанным и может сделать ваш код менее читабельным и ремонтопригодным.

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

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

Хватит болтать, покажи мне код

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

const result = R.pipe(
  R.filter(R.both(
    R.propSatisfies(R.gt(R.__, 25), 'age'),
    R.pathEq(['address', 'country'], 'USA')
  )),
  R.map(R.prop('name'))
)(users)

// 🤔 🤔 🤔

Код фильтрует список пользователей в зависимости от их возраста и страны проживания, в частности, ищет пользователей старше 25 лет, проживающих в США. В приведенном выше примере Ramda применяются принципы функционального программирования с использованием R.pipe() для объединения нескольких операций. Хотя логика не самая запутанная, которую я когда-либо видел, многоуровневая композиция функций требует минуты (или двух) паузы, чтобы понять.

Мы можем переписать это с помощью Lodash и сделать его немного лучше.

const resultL2 = _.map(
  _.filter(
    users,
    user => user.age > 25 && user.address.country === 'USA'
  ),
  'name'
)

// 👌👌👌

Сразу же версия Lodash кажется более доступной. Это упрощает нашу жизнь, напрямую выражая условия фильтрации в функции обратного вызова, используя filter() и map(). Тем не менее, хотя это улучшение, все еще есть место для упрощения.

Пойдем дальше и перепишем это, используя только нативный JS:

const result = users
  .filter(
    user => user.age > 25 && user.address.country === 'USA'
  )
  .map(user => user.name)

// 🥹🥹🥹

Красивый!

Синтаксис прост, интуитивно понятен и не содержит никаких абстракций, отвлекающих нас от основной логики. Мы видим список операций, которые легко читать и понимать. Мы используем методы массива filter() и map() для достижения одинаковых операций фильтрации и сопоставления. Условия фильтрации записываются непосредственно в функциях обратного вызова, в результате чего фрагмент кода становится более читаемым. Действительно, даже моя бабушка может прочитать это.

Для тех, кто привык к традиционным стилям кодирования, интенсивное использование Ramda функционального программирования и каррирования в сочетании с необычными соглашениями об именах может затруднить понимание кода. Особенно, когда вам нужно переключаться между разными стилями кода в рамках проекта, это может быть еще более сложным. По сути, если вы не привыкли к этим конкретным практикам, чтение кода Ramda может быть похоже на попытку решить головоломку. Эта незнакомость затрудняет чтение и отслеживание, особенно при жонглировании несколькими парадигмами кодирования.

Несколько слов в защиту

Не поймите меня неправильно. Ramda, несмотря на опасения, о которых я говорил ранее, несомненно, является мощным инструментом при правильном применении.

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

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

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

Заключение

Хотя у Ramda определенно есть свои сильные стороны и она занимает важное место в сфере функционального программирования, она не всегда подходит лучше всего, особенно если в вашем проекте используются разные стили кодирования. В таких ситуациях вы можете обнаружить, что использование современного нативного JavaScript и Lodash послужит вам лучше. В конечном счете, наша цель — писать эффективный и понятный код, а не просто использовать сложные инструменты ради них самих.