Я всегда был нацелен на результат. Меня не привлекают псевдоинтеллектуальные концепции, причудливая терминология и пиар. Вместо этого, я всегда стремлюсь к тем инструментам и технологиям, которые помогают развернуть исходный код как можно быстрее. Такой подход был изначально продуктивным, особенно когда я создавал меньшие по объему приложения по (‘proof of concept’) «проверке концепции».
К сожалению, такой подход не был эффективным. Совершенствуясь как разработчик, я начал ощущать закон убывающей доходности на моей производительности. Запуск проекта и достижение базовой функциональности произошли быстро. Но реальные проблемы начали возникать, когда мои приложения начали усложняться. Я обнаружил, что, когда цикл жизни проекта совершенствуется, я пишу сложный код. Код, который я написал, стал сложнее, что требовало осмысления. Для того, чтобы его понять, мне пришлось предельно сконцентрироваться.
У меня было не дающее покоя чувство, что должен существовать лучший, более чистый подход к разработке программного обеспечения. Я краем уха слышал о ФП (функциональном программировании) и о том, как оно позволяет разработчикам прописывать более сжатый и элегантный код. Сам того не зная, я впервые столкнулся с парадигмами и моделями ФП при работе с инструментами React и Redux. Оба эти инструмента объединяют в себе некоторые из принципов ФП, и мне они понравились. Я раньше читал о ФП — к своему ужасу, который я вначале испытал, я понял, что эти парадигмы основываются на абстрактных математических концепциях, и что такое видение преобладает в академических кругах. Так как моей целью является максимально быстрое разворачивание продукции, было похоже, что то, чего я пытаюсь достичь, противоречит здравому смыслу. Отучившись 4 года на инженерном факультете, я утвердился во мнении, что в научной среде решались проблемы исключительно теоретического характера, и что вряд ли такая среда когда-либо поможет мне в моих ежедневных разработках.
?????????????????????????????????
Но ФП не давало мне покоя. Элегантные решения и парадигмы периодически появлялись во всех моих любимых проектах с открытым исходным кодом, публикациях в блогах и учебных материалах. Я отложил свой скептицизм в сторону и углубился в изучение ФП.
Хотя такие концепции содержат новый специальный язык и подразумевают быстрое обучение, я был поражен и по-настоящему взволнован этим «новым подходом». В настоящей серии статей я делюсь своим опытом изучения ФП; моей целью является извлечение и обобщение лучших концепций ФП, что обеспечивает получение опыта более чистых и сжатых разработок. Я постараюсь выстроить интуитивное понимание моделей, которые я обсуждаю, и представить проблемы и предлагаемые решения в максимально простой форме, пропуская излишне сложную терминологию. Для многих изучение ФП представляется несколько пугающим, но, разбивая концепции на маленькие порции, мы сможем легче усвоить эти понятия.
Основным отличием ФП, в сравнении с другими парадигмами программирования, является декларативный подход (ФП) в отличие от императивного подхода. Прежде чем мы углубимся в формальные определения, давайте рассмотрим их различия на примере.
Императивный подход
// triple the value of every element in a given array const triple = (arr) => { let results = [] for (let i = 0; i < arr.length; i++){ results.push(arr[i] * 3) } return results } // sum all the elements in a given array const sum = (arr) => { let result = 0 for (let i = 0; i < arr.length; i++){ result += arr[i] } return result }
Посмотреть код вы можете тут
Данный код кажется непригодным? А должен быть! Что схожего между указанными выше методами?
- Главная сложность фрагмента исходного кода происходит от того, что, вместо того, чтобы давать команду компьютеру о том, что мы хотим, чтобы он сделал, мы даем ему инструкции, как это сделать. Код, который дает команду компьютеру, как действовать — т.е. обращение к массиву данных с помощью индекса i и (видоизменение) изменение или замена значения называются императивным исходным кодом.
- Такой код не является надежным (?゚リᄆ?). Это очень простой пример, но по мере роста Вашей программы и повышения уровня функциональности, использование данных замкнутых систем создает код, который не является тривиальным и который требует, чтобы наш мозг анализировал внутреннюю работу системы, одновременно следя за индексами, переменными величинами и многим другим. Императивный код повышает когнитивную нагрузку при чтении, и со временем усложняет понимание и логическое осмысление.
Декларативный подход
Давайте перепишем этот фрагмент исходного кода, но в соответствии с декларативным подходом.
// triple the value of every item in a given array
const triple = (arr) => arr.map((currentItem) => currentItem * 3)
// sum all the elements in a given array
const sum = (arr) => arr.reduce((prev, current) => prev + current, 0)
Посмотреть код вы можете тут
.map? .reduce? Что за черная магия?
Прежде всего, я обещаю, что, если вы введете ту же исходную информацию, эти два метода будут производить одинаковую информацию на выходе каждый раз.
Короткое примечание в отношении фрагмента декларативного кода —
.map() является методом, доступным из каждого массива в JavaScript. Метод .map() создает новый массив, что приводит к вызову предоставленной функции на каждом элементе запрашиваемого массива.
.reduce() является методом, который применяет функцию в отношении аккумулятора и каждого элемента массива (слева направо) для того, чтобы свести его к единому значению.
Не испытывайте страха перед этим. Мы детально изучим данные удобные встроенные методы в отношении массивов в следующих постах. Но сейчас уже очевидно, что фрагмент декларативного исходного кода является более сжатым, чем фрагмент императивного кода. Он также более легко прочитывается. Вместо того, чтобы давать инструкции программе о том, к каким индексам она должна получить доступ и т.д., я просто выдаю выражение на .map() и .reduce() (в нашем случае это анонимная функция), которое говорит программе, что я хочу, чтобы она сделала в отношении каждого элемента массива.
Декларативный подход будет служить нам согласно полному спектру функциональных возможностей:
- Изучая и используя шаблоны в Вашем коде, которые являются хорошо известными, понятными и надежными в отношении недопущения ошибок, которые делают код трудным для понимания.
2. Составляя более короткий, выразительный и сжатый код. В конечном итоге, чем короче код мы пропишем, тем меньше нам придется отыскивать и устранять дефекты.
Самое важное заключается в том, что эти инструменты и парадигмы помогут нам достичь нашу (мою) конечную цель, состоящую в более быстром разворачивании продукции.
Перевод статьи Omer Goldberg: Javascript and Functional Programming: An Introduction