Комментарии 45
Когда я и многие другие разработчики в 2010-2014 топили за функциональное программирование, мы имели ввиду не Erlang, Haskell и монады. Просто тогда во фронтенд пришло огромное количество ребят из C++, Java и других ООП языков и они пытались внедрить свои подходы в JS, который мультипарадигменный. Вместо них пришли функциональщики, которые начали внедрять свои подходы, которые тоже не подходят фронтенду, но их приняли просто на инерции от сопротивления ООП. Оказалось ФП ещё более уродская идея, но мы слишком поздно это поняли. Реально, если бы мы в 2010 знали что такое ФП и во что эти идеи превратят фронтенд, мы бы никогда за это не топили.
Напишу как я это понял, вдруг кому интересно.
Является ли вид страницы в браузере функцией от данных? Очевидно да.
Значит ли это что можно написать фронтенд средствами функционального программирования? Разумеется.
Как будет себя вести такой фронтенд? Перерисовываться при малейшем изменении данных.
Это что/как? Задница/внезапно.
спасибо за интерпретацию, очень кратко и по делу :)
Как обычно, идея сама по себе не плоха, но вопрос в том насколько аккуратно она адаптируется под реальный веб
А разве плеер на странице - это функция от данных? Кажется нет.
Ну, он не перерисовывается на каждый чих потому что это предусмотрели - хранят Стейт до и после, потом сравнивают и перерисовывают измененные годы. Грубо говоря.
Мне вот одно не понятно. Если вы возьмёте любой десктоп фреймворк для написания UI, то это ООП в 100% случаев. То есть, уже есть проверенная парадигма для этой задачи. Но нет, веб пошел своим путём в сторону функций. Но по факту состояние переменеой то внутри функции сохраняется (useState). И получается, что это состояние выглядит как приватная переменная в классе. Так зачем тогда это все городить?? Не проще ли тогда использовать классы и ООП? Чем он так не угодил?
Потому что Дэнчик [Абрамов] так приказал. Заткнись и верстай!
Статья максимально конструктивно это объясняет https://habr.com/ru/articles/885980/
Насчет максимально конструктивно - это вы себе льстите.
На самом деле - нет, начиная с того, что вы почему-то процедурное программирование записываете в функциональное.
Далее: "даже этот код недостаточно ООП-шный — там нет ни одной фабрики и ни одного контейнера зависимостей." Ни фабрики, ни контейнеры зависимостей частью ООП не являются. Я, например, легко могу себе представить фабрику или контейнер зависимостей, возвращающий чистую функцию для ФП.
И далее там такого много, то, что выше написано - это только с первой страницы взято.
Короче, не пишите больше "максиально конструктивно это объясняет", пишите что-нибудь типа "изложил свой взгдяд на ООП", будьте скромнее.
Процедурному программированию не свойственны замыкания, функций первого порядка и иммутабельность, это во-первых. Тут прокол.
Фабрика это по определению класс, а в ФП их нет. Еще прокол.
В конструктив вы не могете, советы попридержите 👍
Процедурному программированию не свойственны замыкания, функций первого порядка и иммутабельность, это во-первых. Тут прокол.
Чей прокол, ваш? В таком случае согласен. Если нет поясните: сначала за замыкания, потом за всё остальное.
Фабрика это по определению класс, а в ФП их нет. Еще прокол
Ну, не знаю, гже вы такое определение откпали. Наверное Вы просто мало знаете. Например, даже в шаблонах GoF есть тако шаблон - factory method. Подчеркиваю: метод, не класс. Ну, а в общем случае роль фабрики может выполнять и функция (а если в C# - делегат): присваиваете его переменной - и вытаскиваете из него нужную функцию единообразно. Да, это не совсем ФП, но ничто не мешает извлеакать из такой фабрики функцию для ФП.
В конструктив вы не могете, советы попридержите
В то, что вы называете "конструктивом" - да, не могу, критическое мышление вкупе со знанием многих фактов мешает: не могу спокойно пойти мимо предрассудков, сказанных с апломбом, и ни на чем не основанных.
Является ли вид страницы в браузере функцией от данных? Очевидно да.
Это совсем не очевидно. Контент - это не всегда данные. Страница может отображать произвольный контент, который практически не поддаётся типизации, и при этом является статичным, уникальным и не переиспользуемым. При этом вид страницы может меняться от действий пользователя: всплывашки, выпадайки, зум и т.д., а данные при этом никак не меняются. Значит ли это, что ФП тут не нужно? Очевидно да.
Контент - это не всегда данные.
Да, содержимое - не всегда документ :статический, все взаимодействие пользователя с которым - посмотреть содержимое с той ли другой стороны - запустить видео, открыть/закрыть скрытй текст и т.д. - или перейти к другому документу по гиперссылке.
Есть другой тип содержимого - интерактивное приложение, которое может взаимодействовать с пользователем и клиентским окружением произвольным образом и, более того, отсылать результат этого взаимодействия обратно на сервер. И всякие интернет-магазины или, там, соцсети требуют использвания именно такого типа содержимого.
Более того, с точки зрения экономической моддели современного массового веба - среды для размещения рекламы - документ не является желательным типом содержимого: он дает мало средств для размещения притягательной рекламы, сбора информации для таргетирования рекламы и т.д.
Потому даже там, где полезное для пользователя содержимое по существу является документом, разработчики стремятся заменить его интерактивным приложением, несмотря на все недостатки такого типа содержимого: увеличение нагрузки на каналы связи (приложение кэшируется сильно хуже) и на клиентские устройства, увеличение поверхности атаки в связи с необходимостью использовать более-менее унивесальный язык программирования и вызванная этим необходимость защиты канала связи и т.д. Потому что смысл существования современного веба - размещение рекламы.
Для того, чтобы трекать пользовательскую активность и размещать рекламу, вовсе не обязательно засовывать в Virtual DOM всю страницу вплоть до копирайта в футере. Равно как это не обязательно для того, чтобы листать фотографии, переключать табы. И даже гонять инфу запросами можно без всякой реактивности.
Кстати, о DOM - это же document object model. И сам по себе HTML так устроен, что каждый элемент в браузере становится объектом, который к тому же хранит своё собственное состояние. Но в какой-то момент почему-то мы решили, что этого недостаточно. Апогеем всего стало хранение всего на свете в redux. Особенно, когда делают слайсы под каждый тип страниц, чтобы пока юзер смотрит товар, его браузер знал, что на сайте есть страница с обратной связью, на которой есть форма, в которой есть элемент "Дополнительные параметры", который не открыт.
Но ведь перерисовывается только та часть ui, которая зависит от обновлённых данных.
Веб по природе event-driven, нелинейный. А оба лагеря пытались навязать линейность — ООП через lifecycle методы, ФП через пайплайны редьюсеров.
Платформа сопротивлялась и тем и другим
. А оба лагеря пытались навязать линейность — ООП через lifecycle методы
Что-то вы странное, на мой взгляд, пишете. Почему-то ООП в программах для Windows (классика там - Delphi, но не только) никакой линейности не навязывало, несмотря на то, что в Windows весь поток управления всегда был организован через очередь событий (оконных сообщений, в тамошней терминологии). Что в веб не так было?
Проблема, как водится, в том, как это используют реальные люди
Редакс был и остается хорошей идеей, но, реальные живые разработчики просто использовали его как key-value with extra steps. Не создавали переиспользуемых селекторов, не писали логику в редьюсера, а просто экшен-на-загрузку данных → экшен-на-установку-данных-в-стейт. Разумеется, смысла в таком редаксе нет никакого
То же самое и с самим реактом. Вместо большого числа довольно чистых небольших компонентов с простым, инкапсулируемым поведением и композицией, одна большая парутысячестрочная страница, где просто накиданы стейты и эффекты для всего функционала, имеющегося на этой странице
Создается впечатление, что большинству программистов просто сказали «писать теперь надо на реакте» и они пишут на реакте, не вдаваясь в философию, просто заставляя это работать как умеют
Даже если в React/Redux поддерживать максимально чистый код, всё равно остаётся большое количество абстракций и усложнений. Но, как по мне, проблема ещё в другом: react часто тянут туда, где он вообще не нужен и выглядит избыточным. Например, простой одностраничник без сложной логики, пара инпутов, а в итоге всё пишется на React, да ещё и с использованием React Hook Form
Не понимаю од в сторону редакса. В каком месте это хорошая идея, идея диспатчить событие и прогонять его по всем обработчикам и иметь глобальный стейт на все приложение? Данные должны быть инкапсулированы, то есть методы работы с ними и сами данные должны жить бок о бок, а не быть размазанными по редьюсерам санкам селектам и прочим костылям. Вместо целостной сущности, которая будет предоставлять методы записи и чтения, нам, чтобы реализовать что-то сложнее тупой записи в хэш мапу. нужно написать редьюсер, по сути методы модификации, экшены - события-триггеры, подтянуть диспатчер и запушить в него событие в виде экшена. Почему вместо того, чтобы инкрементировать тупой каунтер так
class Counter {
private _value = 0;
public get value() {
return this._counter;
public increment() {
this.counter++
}
}
counter.increment()Я должен делать так
action = createAction()
dispatch(action)Почему, вместо нормального чтения
counter.valueЯ должен делать так
const value = state.counter.valueЯ опустил весь код связанный с созданием редьюсеров или слайса, не это имеет значение, а то, что мы даже для реализации примитивных вещей начинаем использовать какую-то прослойку, которая буквально нам ничего не дает. Вызов метода это изменение состояние, вызов экшена это декларация о намерениях его изменить, но между твоим событием и результатом который ты ожидаешь, лежит слой, где может происходить что угодно. Я не понимаю, что пишут, как пишут и в чем видят плюсы разработчики, которые не поносят редакс
У вас очень слабое понимание архитектуры, ваш пример даже не реактивный / событийный.
О эксперт по архитектуре. Не понял правда при чем здесь мой пример. При чем здесь реактивность/событийность. Речи шла о том, что редакс не решает проблем, он усложняет разработку, вводя дополнительные ограничения на работу со стейтом и делая это максимально ублюдски. А и да, архитектор, редакс это паб/саб,

Понимаю что многим сложно думается и уточню - приведен пример с классом, и там подписок нет.
Я уже знаю куда пойдет диалог - в конструирование хелловорлд велосипедов на классах, участвовать в этом не хочу, тем более с таким «архитектором».
Последние годы наблюдается отчётливый разворот:
Astro делает ставку на островную архитектуру и минимизацию клиентского JS.
HTMX показывает, что гипертекст всё ещё мощный инструмент.
SvelteKit компилирует код и избегает тяжёлых рантаймов.
Qwik уходит от полной гидратации и загружает код лениво.
Svelte, а заодно и Solid, с их оптимизациями времени компилиции поближе то к ФП, чем тот же старый React. И вдобавок используют под капотом совсем ненативный механизм сигналов, который тоже вполне себе ФП-шный. Уж по больше фпшный, чем хуки в Реакте. То что Qwik уходит от полной гидратации и загружает код лениво не делает его менее ФП-шным, а Astro вообще никаких ограничений на используемым фреймворкам не предъявляет, а код его шаблонов фактически тот же JSX, разве что он вроде бы полноценный SGML.
HTMX может и показывает, что гипертекст всё ещё мощный инструмент, только он всё так же опирается на серверные шаблонизаторы, которые функциональнее некуда. Нет, в теории, кто-то может пытаться изменять переданный объект внутри шаблона, но тут уже слово гавнокод начинает играть новыми красками коричневого.
В современном браузере ООП API используется только в методах DOM API и Canvas API, причем первый за приделами библиотек и не используется особо.
Спасибо!
Очень круто, что Вы подметили важный момент: функциональные идеи никуда не исчезают, но современные инструменты стараются использовать их гораздо аккуратнее, чем это было ранее. Как раз это и было главной мыслью статьи: проблема не в самом ФП и не в том, что оно присутствует (оно будет присутствовать, потому что декларативные подходы действительно удобны). Проблема в том, как именно эти идеи интегрируются в веб-платформу.
Svelte, Solid или Qwik используют функциональные идеи, но делают это так, что они не ломают модель браузера и не требуют переизобретать нативные механизмы. Это большой контраст с эпохой, когда ради «чистоты» приходилось городить собственные события, кастомные формы или тяжёлые слои маршрутизации.
То есть современный подход все же в том, чтобы использовать функциональные идеи там, где они усиливают веб, а не заменяют его собой.
Использую HTMX, где это возможно, нраица
Веб снова стал прост и понятен для огромного числа случаев. По сути, это то, каким должен был быть HTTP+HTML изначально, с частичным обновлением, триггерами и т.п.
Без всего этого мракобесия с node_modules под гигабайт, чтобы нарисовать пару кнопок, таблиц и переходов
Почему не упомянули?
А теперь пришел ИИ с новой парадигмой rewrite-only code, по которой в общем плевать что там раньше было написано: ФП, ООП или ГК. Проще и дешевле будет выкинуть и завайбкодить с нуля заново при появлении новых бизнес-требований.
Проще и дешевле будет выкинуть и завайбкодить с нуля заново
Было бы, если бы код не требовал его прогляда, причем - квалифицированным сотрудником, помощника программиста (AKA джун) на такую работу не поставишь.
Переписать вряд ли. А вот писать код в принятой парадигме проектом, запросто. И теперь разработчику даже на надо погружаться в детали реализации. Главное следить чтобы бизнес логика соответствовала ожиданиям
А в контексте каких фронтендов автор оригинала рассуждает? Фронтенд для SaaS это одно, для новостных сайтов другое, какой-нибудь встраиваемый виджет - третье, фронтенд роутера - четвертое. Где-то важен размер бандла, где-то и 100Мб - нормально.
Ненормально, когда бизнес любой фронтенд пытается построить одним инструментом тупо исходя из того, каких специалистов больше на рынке и дешевле. Ненормально, когда из-за потребности в специалистах появились толпы мастеров одного инструмента, до кучи и не понимающих как сделать что-то вообще без фреймворка. Возможно просто те, кто залетел тогда в айтишку, заматерели, обросли бородами освоили другие инструменты и распробовав, начали задаваться правильными вопросами?)
Конечно, не надо никаким принципам слепо верить. Но функциональный подход может помочь избавиться от некоторых реальных багов. В ООП всё красиво структурировано, а ФП менее читаемое, но уменьшает хрупкость ПО. А лучше применить эти парадигмы в связке по ситуации. Со временем понял, что с более функционально ориентированными языками увереннее можно работать, именно, что касается непредвиденных багов.
А можете ли Вы объяснить, в чём суть ООП и ФП? С точки зрения конечного результата. Ведь, наша задача заключается в том, что бы всё работало. Важно ли как это реализовано? Что даёт ООП и ФП для эффективности реализации?
ООП ставит ограничение над глобальным окружением — инкапсулирует внутри класса определенную логику, создавая отдельные сущности. Помогает с проблемой дублирования кода. Хотя сильное стремление избавиться от дублирования может создать другие проблемы. ФП ставит ограничение над изменением состояния и приводит функции к математическому идеалу.
ООП каким-то мифическим образом (слишком переоценен эффект) упрощает читабельность кода, хотя иногда может, наоборот, усложнять всё своими многослойными абстракциями. Хотя вот, если подумать, структурировать код можно легко и без ООП и принципы, которые присваивают ООП, были и до его появления.
В некоторых сферах ООП, это почти как стандарт. Помогает уменьшить цену за обслуживания — просто сейчас разработчики такие пошли, что умею работать только с абстракциями. И это даёт какую-то общую базу всем, чтобы не выстрелили себе в ногу.
Давайте, посмотрим, например, следующий вопрос:
Проблема модалок —> игнорирование
Годами разработчики реализовывали свои модальные окна вручную, создавали порталы, ловили фокус, писали обработчики escape. И ведь всё это браузер уже умел делать нативно! Просто сообщество не доверяло платформе.
Здесь, на странице комментариев, есть блок (div), который содержит окно, которое отображается в определённых обстоятельствах. Но что означает появление этого окна? Задание реальных координат и придания атрибута "Видимый". И что должно было бы сделать здесь ООП? Если бы у нас было настольное приложение, то у нас была бы отдельная форма.
И что значит "нативно"?
Frontend прошел огромное количество этапов развития, не всегда верных по своей сути, но все же необходимых. Именно благодаря этому frontend не стоит на месте. Но я все же всей душой люблю backend
Сколько за это время было наворочено всяких сложностей! Приходилось исправлять ранее допущенные ошибки и городить новые слои. А если на это дело посмотреть с другой стороны, то что мешало развиваться настольным приложениям? Что такое фронт-энд настольного приложения? Это — внутренние (нативные) компоненты операционной системы, объединённые в логические группы для решения отдельных (локальных) задач. Иерархия таких компонентов — это аналог DOM. Что же нам мешает иметь стандартный и единый для всех фронт-энд, а за бэк-эндом сокетами по сети обращаться?
jQuery-код был слишком императивным
Я просто зверею от таких набросов. Вообще-то, всё наоборот: jQuery вывел DOM operations (которые были тогда и остались сейчас чудовищно императивными из-за DOM API) на уровень ФПшности, свойственной Javascript как языку в целом (а это высокий уровень). И не вина jQuery, что средняя обезьяна писала такие перлы:
var children = $('#animDummy1').children();
for(var i = 0;i < children.length;i++){
children.eq(i).css('left', (i*120+'px') );
}
Не согласны? Приведите примеры «слишком императивного jQuery-кода». А я покажу, где в них ошибка.
А как надо было написать?
Лучше всего было бы использовать sibling-index(). (Пример открывать в Хроме). Тогда можно обойтись pure CSS, что означает, что никогда не возникнет ситуации с… слово забыл, как называется состояние БД, когда неатомарная транзакция обламывается на середине?.. «неконсистентность»?.. короче, когда добавите ещё один дочерний элемент, а скрипт забудете перевызвать. Но даже сегодня эта фича поддерживается не всеми браузерами, так что, не будем пенять чуваку из 2012-го года, что он про неё не знал ))
Я бы написал примерно так:
// https://stackoverflow.com/questions/25155384/is-the-sort-order-of-jquerys-each-guaranteed
$('.carousel .dot')
.each((i, el) => $(el).attr('aria-label', StringTable.CarouselDotLabel.format({slideIndex: i})));
Только, соответственно, нужно не атрибут для скринридера устанавливать (этот пример показывает ужасающую недекларативность нынешнего состояния WAI ARIA), а задавать значение --sibling-index вручную, для его последующего использования в CSS.
Что конкретно не так:
Не надо использовать переменные (
var childrenв примере с SO). Они дублируют условие на выборку из DOM (которая в его случае ещё и размазана по селектору и последующему вызову.children()) и нарушают DRY. Переменные, которые нельзя не использовать (i,el) по возможности должны иметь абстрактные имена, т.к. их семантика уже где-то описана (в моём примере это'.carousel .dot'), что, опять же, нарушит DRY.Не надо использовать циклы. Надо использовать лямбды. Лямбды описывают желаемое преобразование, циклы описывают способ его достижения, который в 99% случаев неважен.
Схему единичного преобразования желательно описывать одним запросом, при помощи implicit iteration / chaining. Пусть движок (jQuery) и не поддерживает атомарность, но в коде чётко появляются DOM-запросы, а это уже хорошо (для читабельности).
Информация
- Дата регистрации
- Дата основания
- 1990
- Численность
- свыше 10 000 человек
- Местоположение
- Россия
Как функциональное программирование изменило фронтенд и почему отрасль возвращается к платформе