Comments 46
Я разуму уму заря,
Я иду с мечем судия;
С начала та ж я и с конца
И всеми чтуся за Отца.
Державин, 1805г
Что вас смущает?
Какая разница, какой сейчас год если фраза написана 200 лет назад? А данная фраза широко известна и знаменита тем, что это первый достоверно известный авторский палиндром на русском. Потому и является отличным примером.
Любопытно, что у Державина была-то в оригинале «ё»
Вы в курсе, что в русском допустимо вместо "ё" писать "е"? У Державина там еще и "ъ" были.
Если вы считаете иначе, то поясните пожалуйста.
const allNotWordSymbolsRegexpGlobal = () => /[\.,\/#!$%\^&\*;:{}=\-_~()?\s]/g;
const replace = (regexp, replacement, str) => str.replace(regexp, replacement);
const toLowerCase = str => str.toLowerCase();
const stringReverse = str => str.split('').reverse().join('');
const isStringsEqual = (strA, strB) => strA === strB;
Это пример хелпера для каких либо целей.
Далее мы используя ФП инкапсулируем определённую бизнес логику в продуктовые функции.
Опять же, данный код не более чем обучающий пример на темы композиция, каррирование, частичное применение. В качестве допущения для данной задачи было выбрано: необходимость достижения функциональной чистоты. Кстати, вполне вероятная задача на собеседованиях.
Вот почитайте.
Такой подход очень часто применяется в совокупности с теми концепциями, которые я описал в статье.
В статье я реализовал всё нативно для того чтобы показать как эти вещи устроены под капотом.
Цитата из статьи:
Заключение
В рамках данной статьи мы разобрали такие техники функционального программирования как композиция, каррирование и частичное применение. Разумеется, на реальных проектах вы будете использовать готовые библиотеки с этими инструментами, но в рамках статьи я реализовывал всё на нативном JS, чтобы читатели с возможно не очень большим опытом в ФП могли понять как эти техники работают под капотом.
Также я сознательно избрал метод повествования — псевдо кодревью, для того, чтобы проиллюстрировать свою логику достижения функциональной чистоты в коде.
К слову, вы можете продолжить развитие этого модуля работы с палиндромами и развить его идеи, например загружать строки по апи, преобразовывать в наборы букв и отправлять на сервер, где будет генерироваться строка палиндром и многое другое… На ваше усмотрение.
Также неплохо было бы избавится от дублирования в процессах этих строк:
replaceAllNotWordSymbolsToEmpltyGlobal,
toLowerCase,
В общем, совершенствовать код можно и нужно постоянно!
т.е. к бесточечному коду на верхнем уровне
Насколько я понимаю это наименее принципиальный момент. Есть у вас бесточечная нотация или нет её, плевать. На суть это не влияет никак. Это вопрос организации кода больше.
Во-вторых, функция getPalindrom обращается к базе.
И как же использование чистых функций избавит нас от обращения к базе? Если уж нужно к ней обращаться для получения данных, то в какой бы парадигме вы не писали код, такая потребность останется. Если можно убрать обращение к базе без потери функциональности, то это можно будет сделать и в императивной версии. А если следовать тру функциональной парадигме, нужно будет для обращения к базе и другим действиям с побочными эффектами использовать монады.
К слову, аналог getPalindrom в функциональном стиле вы так и не написали.
В-третьих, функции модифицируют свои аргументы. Итого, наши функции не чисты.
Это потому что вы так написали. Можно просто создать временную переменную, и все надуманные проблемы уйдут, а читаемость останется.
Выбор способа использования целиком на совести разработчика, ответственность за результат тоже.
В реальных проектах обращения к баз выносят отдельно, а логику отдельно. ФП это лишь инструмент.
Вот именно. А вы почему-то пишите, что текущая реализация плоха с точки зрения ФП, потому что там идёт обращение к базе. Но если логика обращения к базе в этой самой функции, то она плоха в принципе, не взирая ни на какую парадигму.
И вообще, о чём эта статья? Показать плюсы ФП? Ну что ж, вместо функции на 3-5 строк у вас вышло кода в 3-4 раза больше, он читается труднее. Не понятно, зачем всё переписывать в функциональном стиле.
Вот тут, например, очень хорошо показаны минусы императивного подхода и плюсы функциональщины на примере. А у вас какая-то антиреклама ФП.
На проекте всё слишком специфично и зависит от архитектуры. Для каких — то проектов организация кода в статье — антиреклами ФП, а для каких-то очень даже уместно.
Задача в статье поставлена так: создайте набор инструментов! Не было сказано «напишите две функции». Набор инструментов подразумевает, что мы должны получить на выходе апи, с помощью которого сможем организовать любой тех процесс работы с палиндромами. Собственно поэтому я и показал примерное разбиение на бандлы. В сравнении с начальным вариантом код результата более переиспользуемый и чистый. С точки зрения поставленной задачи код вполне хорош.
Как мне кажется, преимущества ФП надо показывать на тех примерах, где ФП действительно помогает. А сейчас, получается, натянули сову на глобус.
Видел я один проект, который полностью написанн в функциональном стиле функциональной версии lodash. Прямо Lodash Головного Мозга. И, честно говоря, от проекта остались ровно такие же ощущения, как от этой статьи: вместо простых и понятных функций получаем ворох функций, функций-аргументов, функций-связок, функций-функций. Да, все чисто, по канону, но не удобно для чтения, а порой и поддержки.
На реальных проектах другие законы. Люди опытные в функциональном программировании не будут читать такие простые статьи, они им не нужны, а для постигающих эти концепции будет простой и понятный пример, который, кстати, может встретится на собеседовании.
Очень-очень редко приходилось применять каррирование, лишь буквально в единицах случаев оно мне неплохо облегчало жизнь.
Мысль писать весь код в функциональном стиле вызывает… сильное отторжение. Подозреваю, что это результат воспитания и образования, когда серьёзно погружаться в программирование начинаешь с pascal/c++. Возможно, поколение, которое только-только начинает изучать программирование, при наличии всех современных языков, будет иначе воспринимать ФП.
После императивных языков функциональный подход воспринимается в большинстве случаев как разминка для ума — чистый ФП код выглядит иногда круто, но сам на практике так делать ни за что не будешь.
Раз ФП так и не завоевало мир, то значит в большинстве случаев оно не так уж и хорошо/удобно/просто/понятно/универсально. И было бы интересно почитать как раз о том, когда чистый ФП подход таки стоит применять в тех языках, где поддерживаются оба подхода к программированию.
P.S. Совсем иначе эту статью можно воспринимать, если в примерах кода начать применять pipeline оператор из ES2019 proposal github.com/tc39/proposal-pipeline-operator
С ним чистое ФП или его отдельные элементы выглядят совсем иначе, гораздо понятнее и лаконичнее.
P.P.S В подобных статьях имхо стоит через строчку писать, что это упрощенный учебный пример.
Разумеется бизнес логику на ФП не нужно организовывать
Да ладно? ) Вполне себе пишут люди большие и сложные проекты на ФП и в ус не дуют. Обычно проблема, насколько я понял, найти достаточно квалифицированных разработчиков, нежели с самим подходом. Порог входа выше, а это сильно сужает воронку доступных кандидатов. А они все вумные, и хотят высокую з\п.
Ну в нашем случае это backend для соц. сети. А вообще не принципиально.
Ну это не меня надо спрашивать, на самом деле. Я ФП использую лишь отчасти. Я полагаю что киллер фича — декларативность. Есть строгая чёткая схема того как и почему что происходит. А те места где творится магия вынесены в свои собственные загончики, которые явным образом помечены. Это как unsafe в Rust. Проще дебажить, больше гарантий уже на уровне компиляции, понимание что сюрпризов будет куда меньше, и, как часто говоря ФП разработчики, больше дисциплины, т.к. эти искусственные ограничения принуждают разделять мух от котлет.
На на самом деле вам лучше спросить тех кто на ФП языках пишет. Я "не настоящий сварщик" :)
Думаю, что писать код в функциональном стиле ради простоты — это несколько попахивает перфекционизмом, что для одного человека вполне себе допустимо и даже полезно, а для командной разработки, скорей всего, не оправдано.
Статью пропустил, надо почитать…
Свойства PF:… Не используют глобальные значения
Pure function может использовать глобалки. Никаких проблем с этим пока они иммутабельны. Откуда вы это взяли?
В-третьих, функции модифицируют свои аргументы
function isPalindrom (str) {
const regexp = /[\.,\/#!$%\^&\*;:{}=\-_`~()?\s]/g;
str = str.replace(regexp, '').toLowerCase();
return str === str.split('').reverse().join('');
}
Где вы тут модифицируете аргументы? str = str.replace
не модифицирует аргумент. Ваш аргумент остался нетронутым, вы просто потеряли с ним связь. Некрасиво с точки зрения ФП и чистоты кода, но не более того. И .reverse()
тоже ничего не нарушает, ибо мутирует созданную в пределах вашей функции сущность (.split()
). Эта функция не нарушает правил pure functions. Хотя конечно же лучше было присвоить это значение другому наименованию.
const allNotWordSymbolsRegexpGlobal = () => /[\.,\/#!$%\^&\*;:{}=\-_~()?\s]/g;//(1)
Что это? Зачем вы статику засунули в метод? Что мешало сделать стандартно: const BLABLA = /blabla/
?
const replace = (regexp, replacement, str) => str.replace(regexp, replacement);//(2)
const toLowerCase = str => str.toLowerCase();//(3)
Этим вы только хуже сделали. До — было просто и понятно, после — требуется лезть в код и смотреть что же все эти методы делают. Смысл избавляться от точечной нотации в мультипарадигменном языке? да ещё и в стандартной библиотеке...
const isStringsEqual = (strA, strB) => strA === strB;//(5)
Синтаксический сахар в виде операндов придуман как раз для того, чтобы не писать такой код. Тем более когда у нас есть |>
оператор.
ФП оно не про то как создать 100500 однострочных методов делающих очевидные вещи. ФП призван упростить сложное за счёт более понятной схемы взаимодействия и трансформации данных. В вашем примере вы взяли простое решение (причём isPalindrom
уже был PF) и раздули его до груды кода, которая не должна пройти code review.
Поэтому в вас столько негативных комментариев.
Применительно к программированию любой код служит определённым целям. Данный код и данный пример преследует учебные цели: проиллюстрировать определённые техники и практики.
На реальных проектах другие законы. Люди опытные в функциональном программировании не будут читать такие простые статьи, они им не нужны, а для постигающих эти концепции будет простой и понятный пример, который, кстати, может встретится на собеседовании.
Функциональное программирование с точки зрения EcmaScript. Композиция, каррирование, частичное применение