Реактивный фронтенд. История о том, как мы снова всё переписали

    Привет, это снова Катя из Яндекс.Денег. Продолжаю свою историю о том, как я перестала верстать и начала жить. В первой части я рассказала, как меня сюда занесло и чем занимаются наши фронтендеры. Сегодня — про фронтовый стек, откуда там React и куда делся БЭМ.

    Спойлер: БЭМ пока никуда не делся ¯\_(ツ)_/¯. Погнали!



    Внимание: высокая концентрация фронтенда. Много текста, картинок и кода, как обещала.

    Часть 2. Про технологии


    Далекий 2016. Пытаюсь писать на React, выходит довольно сносно. Еще не подозреваю, что через год буду переводить на React целые сервисы. 2017 начинается в Яндекс.Деньгах, у меня начинается БЭМ головного мозга, и я все еще не подозреваю.

    Бэкенд на Node.js, мой первый раз


    Для знакомства с проектом новый разработчик получает тестовое задание. Мне повезло: у меня это была задача из бэклога. И в первый же день я столкнулась с Node.js.

    Фронтендер в Яндекс.Деньгах отвечает не только за клиентскую часть, но и за серверную прослойку в виде Node.js-приложения. Задача приложения – оркестрация данных от Java-бэкенда для подготовки во view-ориентированном виде, а также серверный рендеринг и роутинг. Сказали бы мне такое пару лет назад, я бы ничего не поняла, а все довольно просто: когда на сервер приходит запрос из браузера, Node.js формирует HTTP-запросы на бэкенд, получает необходимые данные и шаблонизирует веб-странички. В качестве серверного фреймворка мы используем Express, а для разработки внутренних приложений без завязки на legacy решили использовать Koa2. Разработчики полюбили дизайн фреймворка, и мы решили не даунгрейдиться до Express, так Koa2 остался в стеке. Но мы не раскатываем на внешних пользователей код на Koa2: у фреймворка нет достаточной поддержки, зато есть открытые уязвимости.

    Мы уже писали про место Node.js в нашем фронтенде, но с тех пор кое-что изменилось. Node.js 8 стала LTS и уже работает на наших production-серверах. Также мы хотим отказаться от Nginx-серверов, которые поднимаем на каждом хосте для раздачи статики — их заменят отдельные сервера с Nginx, а когда-нибудь и CDN.

    Чтобы шарить код между проектами, но не выкладывать его в открытый доступ, используем целый набор инструментов: храним модули в Bitbucket и собираем их в Jenkins. Еще мы используем локальный реестр пакетов и благодаря этому не ходим во внешнюю сеть — это ускоряет сборку и повышает безопасность всей системы. Такой подход нам подсказали джависты, они классные. Любите своих бэкендеров ;)

    А еще мы провели эксперимент — внедрили в одно из приложений диспетчер процессов, который упростил администрирование сервисов на Node.js. Он помог с кластеризацией, а еще избавил нас от одного старого bash-скрипта, который запускал приложения.

    И целого стека мало


    У нас во фронтенде везде javascript. И на сервере, и на клиенте, и под капотом внутренних инструментов. Мы знаем и другие языки, но javascript отлично со всем справляется.

    А вот БЭМ в рамках наших задач справляется не со всем.

    Что такое БЭМ
    БЭМ – подход к веб-разработке, придуманный Яндексом во времена статических HTML-страниц и CSS-каскадов длиною в жизнь. Никакого компонентного подхода еще не было, а поддерживать единообразие множества сервисов было нужно. Яндекс не растерялся и разработал свой собственный компонентный подход, который сегодня позволяет создавать изолированные компоненты и писать гибкий декларативный код.

    БЭМ не только методология, но и большой набор технологий и библиотек. Часть из них заточена под специфику БЭМ, а некоторые вполне могут использоваться в отрыве от БЭМ-архитектуры. Если вам в проекте понадобится мощный шаблонизатор или достойный пример компонентной абстракции над DOM, вы знаете, где их можно найти ;)

    Поэтому мы начали переводить сервисы на React. Некоторые из них уже живут в двух приложениях, построенных на разных стеках:

    – характерная для Яндекса БЭМ платформа;
    – молодая и модная экосистема React.

    Технологии Яндекса


    Пришло время рассказать, за что я полюбила БЭМ.

    Уровни переопределения


    Уровни, уровни, уровни… БЭМ! Профит!
    Уровни переопределения – одна из основных фишек БЭМ методологии. Чтобы понять, как они работают, посмотрим на картинку:


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


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

    Какие бывают уровни
    На картинке выше несколько уровней переопределения:
    • Базовый уровень – библиотека – поставляет исходный модуль кода;
    • Следующий уровень – проект – модифицирует этот модуль под нужды проекта;
    • Уровень выше – платформа – делает тот же модуль специфичным для разных устройств;
    • Вишенка на торте – уровень экспериментов – изменяет модуль для проведения A/B тестирования.


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

    Разработчик сам решает, какие уровни ему нужны: можно создать уровень с темой оформления или уровень с тем же кодом на другом фреймворке.

    Уровни позволяют писать сложные модули на основе простых, легко комбинировать поведение и шарить один и тот же код между сервисами. А собирает этот код ENB – Webpack в мире БЭМ.

    При знакомстве с БЭМ меня особенно порадовали UI-библиотеки, в которых лежат уже готовые компоненты. Мы расширяем эти компоненты в рамках новых библиотек и шарим их между проектами. Это здорово облегчает жизнь: я редко верстаю, не пишу однотипного JS и быстро собираю интерфейсы из готовых блоков.



    Теперь подробнее рассмотрим инструменты БЭМ платформы, чтобы понять, с чем БЭМ справляется недостаточно хорошо и почему он не подошел для решения наших задач.

    BEM-XJST


    Начну с любимого – шаблонизатора bem-xjst. До Яндекс.Денег я использовала Jade, и Bem-xjst отлично проиллюстрировал минусы Jade, которых я тогда не видела. Шаблоны bem-xjst декларативные [1], в них нет if hell [2], и они отлично соответствуют требованиям компонентного подхода [3]. Все это хорошо видно на примере:



    В песочнице можно посмотреть результат шаблонизации и поиграться с ним.

    Как это работает. Внутри – секрет идеальной архитектуры ;)
    • пишем BEMJSON. BEMJSON это JSON, описывающий БЭМ-дерево. БЭМ-дерево это представление DOM-дерева в виде независимых компонент;
    • bem-xjst принимает на вход BEMJSON и применяет шаблоны. Этот процесс можно сравнить с рендерингом в браузере. Браузер обходит DOM-дерево и постепенно применяет CSS правила к его DOM-узлам: размер, цвет текста, отступы. Так же bem-xjst обходит BEMJSON, ищет соответствующие его узлам шаблоны и постепенно применяет их: тег, атрибуты, содержимое. «Применить шаблон» значит сгенерировать из него HTML-строку. Генерацией HTML из BEMJSON занимается один из движков шаблонизатора – BEMHTML.


    Писать шаблоны просто: выделяем сущность и пишем функции, которые шаблонизатор вызовет для рендера частей HTML-строки. Самое сложное – выделить сущность. Правильные сущности – залог хорошей архитектуры!

    Чем длиннее ваша борода, тем выше шанс, что вы уже заметили отсылку в названии шаблонизатора: XSLT (eXtensible Stylesheet Language Transformations) => XJST (eXtensible JavaScript Transformations). Он использует принципы из XSLT и потому такой декларативный. Если вы не знаете, что такое XSLT, считайте, что вам повезло :)

    Bem-xjst изоморфный. Мы рендерим HTML страницы на сервере и динамически меняем его на клиенте. Для шаблонизации в рантайме bem-xjst предоставляет API, которым мы пользуемся при написании клиентского javascript-кода.

    I-BEM


    С помощью bem-xjst мы описываем представление, а логику – с помощью i-bem. I-bem – абстракция над DOM, которая предоставляет высокоуровневый API для работы с компонентами. Проще говоря, позволяет писать это:



    вместо этого:



    Чтобы писать код, не нужно знать про внутреннюю реализацию компонента. Мы оперируем сущностями, которые описали в шаблоне: все равно, будет это jQuery-селектор или DOM-элемент. Мы можем создавать кастомные события, подходящие для конкретной объектной модели, а работа с нативными событиями и интерфейсами будет скрыта во внутренней реализации. Там же описана низкоуровневая логика, а значит мы не нагружаем код с основной логикой лишними проверками. В итоге, код легко читается и не зависит от конкретной технологии.

    I-bem позволяет описывать логику работы компонента как набор состояний [1]. Это и есть декларативный javascript. В i-bem реализован собственный Event Emitter: при изменении состояний компоненты автоматически генерируют события, на которые может подписаться другая компонента [2].

    Так выглядит большая часть клиентского javascript-кода на БЭМ:



    Как это работает
    • по событию domReady i-bem находит в DOM-дереве компоненты (блоки) и инициализирует их – создает в памяти браузера js-объект, соответствующий блоку;
    • при наступлении нужных событий мы устанавливаем блоку маркеры, отражающие состояние. Роль маркеров выполняют CSS-классы. Например, при клике на input, мы добавляем ему класс «input_focused», который служит маркером;
    • при выставлении таких маркеров i-bem запускает коллбэки, заданные в javascript-реализации блока.

    Писать логику просто: нужно описать возможные состояния блока (те самые маркеры) и задать обработчики изменения этих состояний (те самые коллбэки).

    С i-bem мы без труда переопределяем поведение компонент, создаем стройный API их взаимодействия и динамически изменяем их в рантайме. Так чего же не хватает?
    Мы любим БЭМ за декларативность, легкую масштабируемость и высокоуровневые абстракции, но не готовы больше мириться с его ограничениями. Ниже мы рассмотрим проблему клиентского рендеринга, хранения данных и другие ограничения БЭМ-платформы. Со временем эти проблемы, возможно, будут решены БЭМ-контрибьюторами, но мы не готовы ждать.

    Современный веб c SPA и адаптивностью под мобильные устройства требует адаптивности и от нас. Поэтому мы решили перейти на собственный стек. И выбрали React.

    Новый кленовый стек на React


    React принес в нашу жизнь virtual DOM, hot reload, CSS in JS и большое комьюнити, частью которого мы стали.

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

    Библиотеки


    Разбиение интерфейсных сущностей на независимые БЭМ-блоки отлично дружит с компонентным подходом React. Разработчики Яндекса написали bem-react-core и перевели на React базовую UI-библиотеку компонент. Мы написали над ней библиотеку-адаптер, которая учитывает специфику этих компонент и поставляет их в качестве HOC:



    Такие библиотеки подключаются не в приложении, а в основной библиотеке компонент:



    Приложение зависит только от основной библиотеки и получает все компоненты из нее:



    Это сокращает количество зависимостей приложения, и библиотеки не попадают в бандл дважды под разными версиями.

    Технологии


    React не завязан на конкретные технологии и мы сами выбираем инструменты и библиотеки. В моем вооружении есть axios, redux, redux form, redux thunk, styled-components, TypeScript, flow, jest и другие классные штуки. Чтобы не допускать зоопарка, мы согласовываем использование новых технологий с другими разработчиками – отправляем в специальный репозиторий pull-реквест с анализом того, чем полезна технология и почему выбрали именно ее.

    Заходит фронтендер в бар, а бармен ему и говорит


    Для приложений на React мы создаем платформу, которая объединит библиотеки и процессы для их создания и поддержки. Сердце этой платформы – консольная утилита Frontend Bar. Bar умеет готовить много вкусных штук.

    В меню:

    1. Конфиг со льдом: bar смешает и встряхнет ваши yml переменные и приготовит шаблон конфига для ansible.
    2. Сок с ароматом конфигураторов: bar создаст новое приложение на основе модульной заготовки – Juice.
    3. Сет базовых настроек библиотеки. Ожидается в скором времени.

    Создать сочное приложение теперь легко – «frontend-bar make juice». Make juice, not war! Когда Bar разворачивает новое приложение, он выполняет набор конфигураций из Juice: генерируется package.json, .babelrc, код ключевых мидлвар и роутов, код корневой компоненты. Frontend Bar облегчит выделение новых микросервисов и поможет соблюдать единые правила написания кода.

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



    Спойлер: выберем луковую.

    Что получилось и стало ли лучше? Давайте разбираться


    Динамические интерфейсы


    Было


    Выше я писала, что bem-xjst предоставляет API для шаблонизации в рантайме. I-bem, в свою очередь, умеет работать с DOM-деревом. Подружим их и сможем динамически генерировать и изменять HTML. Попробуем изменить кнопку по событию:




    В этом примере видно слабую сторону БЭМ: i-bem не хочет дружить с bem-xjst и не хочет ничего знать про шаблоны. Она добавляет блоку класс, но не применяет шаблон [1]. Мы перерендериваем компонент вручную [2]:

    • описываем новый кусочек БЭМ-дерева [3];
    • затем применяем новый шаблон [4];
    • и инициализируем еще один компонент на текущей DOM-ноде [5].

    Кроме того, i-bem не создает diff БЭМ-деревьев, поэтому происходит перерендер всей компоненты, а не изменившихся частей. Рассмотрим простой пример: перерендерить содержимое модального окошка по требованию. Оно состоит из трех элементов:



    Для простоты будем считать, что может измениться только один элемент.



    Хочется сделать [1] и расслабиться. Но i-bem не станет разбираться, что изменилось, полностью перерендерит весь компонент и тоже расслабится. В этом-то примере серьезных последствий не будет, но что, если вот так неаккуратно перерендеривать целые формы? Это ухудшает производительность и вызывает неприятные сайд-эффекты: где-то мелькает инпут, где-то зависает бесхозный тултип. Мы из-за этого грустим и вручную управляем частями компоненты, чтобы сделать точечный перерендер [2]. Это усложняет разработку, и мы опять грустим.

    Стало


    React пришел и все разрулил. Он сам отслеживает состояние компонент, мы больше не управляем рендерингом вручную и не задумываемся о взаимодействии с DOM. React содержит имплементацию virtual DOM. При вызове React.createElement создается js-объект DOM-узла с его свойствами и наследниками – virtual DOM этого компонента, который сохраняется внутри React. При изменении компонента React вычисляет новый virtual DOM, а затем diff сохраненного и нового, и обновляет только ту часть DOM, которая изменилась. Все летает, а нам остается лишь оптимизировать сложную логику, используя shouldComponentUpdate. Это успех!

    Хранение данных


    Было


    В БЭМ мы готовим все данные на сервере и передаем их в компоненты страницы:



    Компоненты изолированы и не будут делиться данными друг с другом, а значит, в разные компоненты придется прокидывать одни и те же данные [1]. Мы не сможем получить их на клиенте, поэтому каждый компонент заранее принимает набор данных, которые нужны для всех возможных сценариев его работы. Это значит, что мы нагружаем компонент данными, которые могут ему не понадобиться [2].

    Иногда нас выручает глобальная сущность, в которой хранится часть общих данных, но глобальное хранение переменных плохо вписывается в концепцию БЭМ. Поэтому мы написали bem-redux, который адаптирует Redux для БЭМ. Redux – стейт-менеджер, управляющий потоком данных. Он отлично управляет нашими данными в рамках простых интерфейсов, но при разработке сложной компоненты мы упираемся в проблему рендеринга, которую я описала выше. Redux не дружит с i-bem, мы фиксим баги и грустим.

    Стало


    Redux + React = <3
    Redux хранит данные для всего приложения в одном месте [1]:



    Компонента сама решает, когда и какие данные ей нужны [2]:



    Нам нужно только описать сценарии работы компоненты [3] и указать, откуда брать данные для его выполнения [4]:



    А React сделает все остальное [5]:



    Такой подход позволяет следовать принципу единой ответственности и инкапсулировать логику компоненты в самой компоненте, а не размазывать ее в коде страницы. Это успех!

    За все приходится платить


    За успех мы расплатились нехилым количеством legacy на React. Больно видеть, как твой код, написанный всего пару месяцев назад, плавно превращается в deprecated.

    Дело в том, что React это view-layer библиотека, а не полноценный фреймворк. Ты можешь выбрать все инструменты, но тебе придется выбрать все инструменты. А также самому организовать код, сформировать подходы к решению типичных задач, выработать набор соглашений и написать недостающие плагины. Мы пишем собственные валидаторы для redux-форм и до сих пор не научились работать со сложными анимациями. И мы пробуем и выкидываем, пишем и переписываем. А переписываем не всегда, отчего растет наш бэклог.

    React достаточно молод и не готов к enterprise-разработке, в отличие от БЭМ. И пока мы учились его готовить, перепачкали всю свою кухню и сами замарались по локоть. И мы по-прежнему ведем споры о том, нужен нам flow или все-таки нет, и все еще не до конца понимаем, что хранить в сторе, а что в локальном стейте. Пишем как придется и ездим на конференции, чтобы узнать, как надо. Бьем шишки, но уверенно движемся вперед.

    Неожиданные плюшки


    Новый стек позволил по-новому взглянуть на ряд задач и предоставил простые пути их решения.

    CSS in JS


    Было


    Рассмотрим простой кейс из жизни: раскрасить и анимировать иконку по событию, примерно так:



    Кода всего ничего:



    Правда, по правилам БЭМ, придется разнести его аж по трем директориям:



    Оверхэд? Спорный вопрос. Важнее то, что в js мы добавляем эти классы вручную при наступлении нужных событий. Обычная ситуация, но чем кастомнее или сложнее интерфейс, тем чаще придется добавлять и удалять классы. А если изменить нужно не только иконку, но и текст? Не совсем та логика, которую хочется видеть в js-коде:



    А что, если длительность анимации от чего-то зависит и устанавливается динамически? Тогда мы перепишем СSS-анимацию на jQuery и немного погрустим.

    Стало


    Styled-components, я люблю тебя! СSS in JS – one love! Мой внутренний верстальщик ликует:



    Модульность сохранилась, CSS-анимация работает и никакой ручной работы с классами. Приятный бонус нового стека.

    Типизация


    Было


    Раньше мы писали тонны jsDoc. Давайте посмотрим, полезен ли он:



    Этот пример взят из продакшен кода. Что содержит state? Понятия не имею. Да, есть readme, но увы, он немного устарел. Да, нам стыдно, но с документацией и комментариями так бывает часто, они ненадежны. Придется углубиться в код. Или не углубляться и нечаянно все сломать. Спешим, не углубляемся, ломаем и грустим.

    Стало


    На помощь пришла типизация. «Тык» на тип, и вся подноготная метода перед глазами. Лень разбираться? Precommit checker запустит flow, и разобраться все равно придется.

    Я невзлюбила flow с первого взгляда. Сроки горят, менеджер пингует, а у тебя и там «cannot get property», и тут «property is missing». Но недавно мне рассказали, что типами можно проектировать О_о Как проектировать типами? Примерно вот так:



    Мой мир перевернулся. Flow перестал быть кошмаром. Описывать API модулей типами до написания кода оказалось удобно и полезно. Надежный код – приятный бонус!

    Значит, больше никакого БЭМ?


    Нет. БЭМ жив, а мы продолжаем поддерживать приложения на БЭМ-стеке. Со временем и они переедут на React, а пока мы готовим для этого почву: переводим библиотеки компонент, формируем набор инструментов и соглашений, учимся планировать сроки миграции.

    На БЭМ реализован наш шаблонизатор e-mail рассылки. Мы готовим письма на сервере, и описанные выше ограничения БЭМ-платформы не затрагивают это приложение. Использование БЭМ для его разработки – уместное элегантное решение.

    К тому же наши дизайнеры прототипируют с помощью БЭМ и иногда приносят нам сверстанные компоненты вместо макетов. И даже если мы перестанем писать на БЭМ, он все равно найдет нас :)

    Я читал первую часть. Что там про верстальщиков?


    Я участвовала в переводе одного из приложений с БЭМ на React и уяснила важную вещь.

    До прихода в Яндекс.Деньги я была простым верстальщиком и потратила не один год, верстая тонны HTML и JSX. Я не воспринимала всерьез фронтенд-сообщество и его изменчивый мир. Не понимала, зачем изучать первый Angular, чтобы завтра забыть о нем и изучать второй. Не понимала, зачем менять jQuery.Ajax на Fetch, чтобы заменить потом Fetch на Axios.

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

    Всем React!
    Яндекс.Деньги 128,80
    Об электронных платежах и устройстве Я.Денег
    Поделиться публикацией
    Комментарии 45
      0
      Что думаете насчет redux-thunk? Хватает ли вам его и не рассматриваете ли альтернативы для управления сайд-эффектами?
        0
        Мы рассматривали в качестве альтернативы redux-saga. Было рассмотрено множество критериев: тестирование, архитектура, поддержка, связность и другие. Счет плюсов и минусов по каждому критерию оказался равным. Выбрали thunk, потому что уже работали с ним, когда писали на react native. А saga — слишком мощный и более своеобразный инструмент.

        Redux-thunk хорошо справляется со своими задачами, нам его хватает.
        0
        Все жизненные истории по переходу с одной парадигмы кода на другую всегда такие одинаково-меланхолические :-)

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

        Это всё не зависит от переносов между фреймворками. Разве что при переносе что-то просто таки придётся выпрямлять, в то время как без переносов оно может жить годами без модификаций (а может и не жить, если есть кому бороться за улучшение кода).

        Не понимала, зачем изучать первый Angular, чтобы завтра забыть о нем и изучать второй. Не понимала, зачем менять jQuery.Ajax на Fetch, чтобы заменить потом Fetch на Axios.

        И в силу вышесказанного, не понимать вот тут — это как раз нормально. Не надо изучать первый ангуляр, если переезд всё равно будет только на второй. С принципами ознакомиться — да, стоит. Изучать? Ну такое.
        Переносы сами по себе имеют вполне выразимую стоимость (стоимость всех человеко-часов программистов, стоимость повторного QA, и так далее), и не всегда она как-то даже рядом стоит с выигрышами от улучшения кода, особенно с учётом того, что улучшение кода можно отлично проводить и без переносов.
        Но когда потенциальные выигрыши таки значительны — там да, взяли и понесли.
          +1
          Я вот весьма косвенно отношусь к веб-разработке (пилю всякое на php+jquery в свободное время), но прям чувствую боль, когда пытаюсь понять, а чем же новым пользоваться, чтобы быстрее, лучше и без рефреша.

          Профессионалы — понятно, они целыми отделами заранее знают технологию. А с любителями вопрос «изучить, забыть, изучить снова» встает очень остро.
          Расскажите, как быть?
            +1
            но прям чувствую боль, когда пытаюсь понять, а чем же новым пользоваться, чтобы быстрее, лучше и без рефреша

            Ну, добро пожаловать в наш мир. Чувствовать боль в таких случаях — это как раз нормально.
            На моей практике вообще никогда не существовало ситуаций, когда можно было откинуться в кресле, ткнуть пальцем в технологию из некоего заготовленного списка максимально подходящих, и не поиметь проблем, сразу или же (еще больнее) потом.
            Это уж не говоря про то, что еще и при самом составлении списка происходит огромное количество страданий.

            Пока что максимально великое откровение, которое я тут знаю — это «Никто в мире не знает, как решать конкретно твои проблемы. Даже если они довольно типичные. А уж если нетипичные, то тем более». Поэтому без боли и необходимости думать самому по каждому конкретному случаю — не выходит.

            ЗЫ: Ну а если сказать более практично, то с php+jquery можно нынче куда угодно двигаться. Можно уменьшать серверную часть. Можно съехать с jquery в сторону уменьшения императивности. Можно и не делать этого (мне, например, императивный js очень нравится, и от попыток присобачить туда декларативности побольше я всегда вижу больше проблем, чем пользы). Можно смотреть в направлении модульности — даже я бы сказал нужно, если вдруг вы пока этим не озадачивались. Модульность из js уже точно никуда не денется, возможно она будет не совсем такая, как нынешние RequireJS, CommonJS, итд, но какая-то подобная будет в любом случае. Можно смотреть на разделение функциональных стилей и look&feel — этого вообще до сих пор в мире никто не смог сделать так, чтоб всем понравилось (спасибо примитивности css). Короче, тысячи путей, и это помимо предложений «изучите фреймворк Х, авось вам понравится».
              0
              Распечатаю, и в рамку, настолько хорошо :)

              Ладно, вот тогда вопрос дня: какой фреймворк в первую очередь изучить человеку, который умеет в php+jquery, но хочет зарабатывать как все остальные фронтендеры, а не веками пилить сайт своего завода?
                0
                Тот, который хочет работодатель, ищущий фронтэндеров за хорошие деньги, разумеется.
                Если говорить про вотпрямщас, то это скорее всего будет один из троицы Vue, Angular2 (то есть 2+), React. Но важно понимать, что через годик эта троица может уже выглядеть как-то иначе, а через пару лет — почти наверняка.
                  0
                  Пока обдумывал ваш ответ, вспомнил прекрасное

                  — Слушай, это легко. Пиши весь код в TypeScript. Все модули, использующие Fetch компилируй в ES6, транспайль их с Babel с stage-3, и загружай с SystemJS. Если у тебя нет Fetch, используй polyfill, или Bluebird, Request или Axios, и обрабатывай промисы с await.
                  — У нас очень разные определения «легко».
                    +1
                    Это вы еще не слышали, на каком языке геймеры разговаривают :-)

                    Но да, в той статье всё хорошо написано. И, на самом деле, этот микс из фреймворков, пакетов, фич, и прочей лабуды — он не настолько страшен, как издалека кажется. Умных слов много, а принципов работы этого куда меньше. С некоторыми вещами можно разбираться и подольше, как с теми же модулями, но во многие — нет необходимости погружаться дальше одного предложения. То есть, например, «транспайлер — это то, что переделывает не работающий в браузере JS (или TS, не суть) в работающий». Всё. Научно там разжевывать можно долго, но это всё будет про шашечки, а не про ехать.
                      0
                      Это как раз легко, так как каждый пункт тут сводится к «открой гитхаб и выполни шаги из ридми». С этим даже обезьяна справится при условии владения командной строкой, линуксом и английским. А вот отладить все это, чтобы не было багов, чтобы удобно было разрабатывать, чтобы работало под виндоуз, чтобы в результате не получалось 2 мегабайта яваскрипта, чтобы работало в ИЕ — это действительно другое определение слова «легко».
                    0
                    Упс, написал ниже большой коммент, а вы оказывается не просто любитель, ваяющий что-то для себя или какого-то своего сообщества, а, как минимум, видящий себя профессионалом в будущем, да и сейчас уже возможно деньги за веб-разработку получающий, то есть формально к профессионалам уже относящийся.

                    Тут критерии другие, если среднесрочная цель выйти на достойный уровень оплаты в веб-разработке. Прежде всего анализ требований рынка, как по уровню оплаты на позициях типа миддл/регуляр, так и количеству вакансий. Ну и сравнение своих актуальных знаний и навыков с требуемыми. Сначала просто по «чек-листу» вакансии, потом с помощью попыток прохождения собеседований по всем более-менее адекватным вакансиям с активным требованием фидбэка в случае отказа.

                    Навсидку на вашем месте я бы смотрел в сторону Angular или Vue на фронте и Laravel на бэке (сам по дефолту выберу React+MobX и Symfony :) ). И вообще определился бы, что интересней, фронт или бэк, и основные усилия прилагать к выбранному пока до полноценного миддла не дорастёте. А уж потом смотреть интересно ли становиться фулстэк разработчиком или нет.
                      0
                      Я немного потерялся в последовательности ответов.
                      Если вы мне — то спасибо за развернутый коммент.

                      Я — любитель, но в комменты могут прийти разные люди с похожими вопросами, и им это будет полезно. И тем, и тем :)
                  0
                  Если относитесь весьма косвенно, то просто посмотрите туториалы, демки, конкурсы и т. п. и посмотрите, что вам ближе, понятней. Если ещё затрудняетесь с выбором, то попробуйте какие-то простые задачи (можно уже решенные, можно новые, но которые вам абсолютно понятно как решать на привычном стэке технологий, в общем чтобы не приходилось думать а как вообще задачу решать, а только как решение перенести на новый стэк) решить одновременно на оставшихся кандидатах. Ну и где-то раз в год-два можно повторять, если боитесь, что упустите что-то новое, что кардинально упростит вам жизнь. А может по результатам анализа в целом окажется, что и ваш текущий стэк вполне себе приемлем, что проблем, которые решают новые или значительно обновленные технологии, у вас просто нет. Ну, например, в ваших любительских проектах крайне редки изменения существующей функциональности, добавления бывают, но переделывать то, что уже сделали вам не интересно. Или у вас нет проблемы входа новичка в проект. Или не сталкиваетесь постоянно с багами, связанными с неявными сайд-эффектами, когда сделали что-то новое или починили старое, а тут внезапно вылазят ошибки, казалось бы никак не связанные с тем, что делали.

                  Главным критерием, по-моему, для люителей должна быть простота и скорость разработки, за милисекундами отклика или рендеринга вам, по-моему, смысла нет гнаться, если оптимизация сама по себе вам удовольствия не доставляет.

                  Ну и хорошо бы проанализировать что вы чаще делаете — пишите что-то новое, реализуете какие-то идеи типа «а не запилить ли мне...» или изменяете существующее, реализуете идеи типа «вот я это уже сделал, а теперь вижу, что это можно по другому и спать теперь не могу». Вряд ли вы найдёте стэк, который удовлетворят обеим подребностям, одинаково хорошо подходящий для быстрой разработки или прототипирования идей (RAD есть такой термин) и для долгосрочной поддержки с постоянными изменениями (ближе к «кровавому ентерпрайзу»)

                  Не думаю, что вам нужно фокусироваться на таких критериях как скорость работы стэка или время сборки — всё сколь-нибудь популярное имеет приемлимые метрики.
                +1

                В начале статьи думал, что будет история про react-bem-core :)
                Спасибо.
                З.ы. Не придираюсь, но почему "реактивный фронтенд"? От слова React?

                    0
                    Опередили, спасибо :)
                      +8

                      React не имеет никакого отношения к реактивному программированию. Название статьи вводит в заблуждение, потому что ни о каком РП в статье речи не идет.

                        –1
                        Ну, кое-какое имеет. React неплохо служит в качестве целевого объекта некоторых реакций, если не пользоваться его внутренним стейтом и контекстами без чёткого понимания как они мешают реактивности.
                          +1
                          Ну то есть на самом деле никакого не имеет, как правильно сказали.
                          Реактивное программирование можно довольно скромными усилиями хоть на голом JS поднять. Означает ли это, что JS имеет «кое-какое» отношение к реактивному программированию? Нет.
                            0

                            С такой логикой любой коллбек можно реактивным назвать.

                      –3
                      Неужели к вот такому
                      &__toggler{
                        ...
                      }
                      можно привыкнуть и даже чтобы было удобно?
                      И это ещё простой селектор.
                        +1
                        Яндекс знатные почитатели NIH синдрома. create-react-app — не, сделаем своё. Nightwatch? Не, сделаем своё. Фреймворк? Не, своё. Потом, правда, выкинем, и будем пользоваться React.
                          0
                          1) Где был компонентный подход к разработке, когда появился BEM (2008 год)?

                          2) Мы (не Яндекс) тоже написали свой feature-starter-kit вместо create-react-app — наши задачи не влезали в готовый инструмент для широкого использования и поэтому ограниченого по функциональности.
                          0
                          А где-то можно потыкать в сайтик сделанных на этих всех описанных модных-молодёжных плюшках?
                            0
                            Можно: money.yandex.ru
                              +4
                              Потыкал минут пять. Вот скажите, как так происходит? Почему в современном вебе несмотря на реакты-редуксы и прочую хрень на выходе получаются кривые, косые и ЧУДОВИЩНО тормозные сайты?

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

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

                              Кнопки «других способов пополнения» со страницы пополнения кошелька ведут на десктопную версию сайта (всего два клика с главной и упс, мобильная версия кончилась).

                              Я провёо всего 5 минут на вашем сайте и абсолютно не являюсь профессиональным тестировщиком и проигнорировал проблемы вёрстки.

                              Как так происходит? Грош цена всем этим БЭМам если на выходе сайт, создающий впечатление кривой поделки.

                              Дело не конкретно в вас, весь веб сейчас такой. Просто вы тут пытаетесь учить других как делать его хорошо и правильно, но то что вы делаете не хорошо и не правильно.
                                +1
                                Нисколько не в защиту Яндекса, ибо сам эту контору не люблю, но…
                                У вас в мобильной версии

                                Ну вы уже должны были сами всё понять.
                                Мобильная версия сама по себе не взлетит. Не взлетит она и с реактами-редуксами и прочими умными словами. Мобильная версия — это по прежнему такое особое чудо, которое надо допиливать и тестировать отдельно.

                                И не смотря на всё это — это лучше, чем было раньше, когда мобиловерсия сайта сжирала столько же, или даже больше сил, чем обычная.
                                  0
                                  Промахнулся тредом (когда же это уже поправят), ответил ниже.
                                  +1
                                  У них тормоза скорее всего не от яваскрипта или БЭМ, а от злоупотребления анимациями. То есть арт-директор видимо в мечтах видит какие-то футуристичные интерфейсы, где все выезжает, трансформируется, подмигивает и подпрыгивает в векторе, но реальные браузеры на обычных устройствах, особенно если недоступно аппаратное 3D ускорение, или элементы DOM неудачно выстроились в дереве, просто не могут это нормально отображать и перерисовывать страницу по 60 раз в секунду.

                                  У меня например, 100% сайтов, на которых есть эффекты при прокрутке страницы, дергаются и притормаживают, а если не притормаживают, то анимации смотрятся как-то неестественно и отвлекают внимание.

                                  Я кстати крайне не люблю эти анимации. Белая страница с сухой таблицей с аккуратно подобранными отступами и шрифтами в 10 раз лучше всех этих гигантских современных блоков с 40-пиксельными шрифтами.
                              +3
                              Океей, десктоп. С текстом на главной такая же фигня: cloud.mail.ru/public/5kkt/ST6WpV8d9
                              Правда тётка уже не дергается.

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

                              Страница «Оплата->Налоги». Сначала загружается всё, потом с паузой до секунды догружается поле ИНН. Да, яндекс, вы клёвые, вы умеете апдейтить на ходу куски страницы. Но начерта это здесь? Кому нахрен сдалась форма в её промежуточном виде, без единственного значимого поля?

                              В «Помощи» попадаешь в другую вселенную.

                              Со страницы создания кошелька опять почти никуда не выбраться.

                              Ищо:
                              cloud.mail.ru/public/NHvF/CKqVQcwx1
                              cloud.mail.ru/public/FBV1/naXJFFYm8

                              Десерт: cloud.mail.ru/public/EnWQ/c4b2LPTUp

                              P.S. Хабр, гори в аду. Мискликнул в кнопку «написать комментарий» внизу страницы и весь набранный текст пропал.
                              P.P.S. Повторю, сайт ЯД не как-то особенно плох на фоне других сайтов. И вообще я потенциально не являюсь целевой аудиторией и мои претензии можно проигнорировать.
                                0
                                Очень интересно читать такие статьи, да и вообще, в блоге Яндекса почти все статьи интересные (особенно про автоматическое тестирование), но конечно, осталось ощущение какой-то переусложненности.

                                Насчет «уровней переопределения» — по моему, тут есть риск, что два уровня могут переопределять одно и то же свойство (или задействовать один и тот же псевдоэлемент) или конфликтующие друг с другом свойства (один уровень ставит overflow: hidden, а другой добавляет выходящий наружу элемент).

                                Также, по моему, это выглядит довольно странно:

                                tag()('button')


                                Так как непонятно, почему не просто tag('button') (подозреваю, там какая-то магия, но все равно выглядит странно).

                                Функции в такой записи, на мой взгляд, плохо читаются:

                                export const addPhone = (params) => () => axios.что-то.там


                                Больше напоминает результат обфускации. По моему, так export function xyz() было бы куда читабельнее.

                                Когда вы разрываете куски названий классов

                                .title {
                                    &__toggler { 
                                


                                То они перестают искаться. То есть, если в таком коде сделать поиск по title__toggler, то ничего не найдется. Это, по моему, минус.
                                  0

                                  Оно лежит в понятных местах на ФС и в полнотекстовом поиске по всему проекту нет необходимости.

                                    0
                                    BEM — хороший пример Соглашения по конфигурации, когда js/css/шаблоны находятся в предсказуемых местах. Соглашение позволяют легко войти в другой проект, созданный по таким же соглашением с минимальным количеством «WAT».
                                    Также, по моему, это выглядит довольно странно:
                                    tag()('button')


                                    Тело шаблона — это отдельный вызов функции, которая ожидает аргумент.

                                    Можно использовать сокращенный синтаксис, который выглядит привычнее:
                                    block('link')({ tag: 'button' });


                                    Посмотрите пример
                                    0
                                    Правда, по правилам БЭМ, придется разнести его аж по трем директориям

                                    Не обязательно, этот код может быть записан в файле блока.
                                      +1
                                      никто не читает теги

                                      Вот зачем вы это пикабу сюда приносите?

                                        0
                                        А еще мы провели эксперимент — внедрили в одно из приложений диспетчер процессов, который упростил администрирование сервисов на Node.js. Он помог с кластеризацией, а еще избавил нас от одного старого bash-скрипта, который запускал приложения.

                                        Хм… учитывая ваши масштабы, наверно вам нужно смотреть на n|solid platform (у него есть сертифицированные модули) или pm2.
                                        Рассматривали ли MobX вместо Redux?
                                          0
                                          Мы пробовали MobX и нам понравилось. Но Redux есть в БЭМ-стеке и уже знаком большинству разработчиков, поэтому мы остановились на нем.
                                          +4

                                          Спасибо, но тем, кто постит код картинками, готовят отдельный котёл в аду.


                                          Попробуйте может объяснить, я даже готов понять.

                                            0

                                            Предвосхищая «ой, ну подумаешь» и оставляя в стороне то, что код не выделить и не скопировать, да и индексации ноль, я просто оставлю одну картинку. Зашёл почитать статью на мобилке:


                                            0
                                            Но мы не раскатываем на внешних пользователей код на Koa2: у фреймворка нет достаточной поддержки, зато есть открытые уязвимости.

                                            1. Какие уязвимости не позволили koa2 использовать в prod?
                                            2. Пробовали ли вы внести свой вклад в koa2?
                                              0
                                              Мы связались с одним из контрибьюторов koa2 по поводу имеющейся уязвимости. Один из наших разработчиков участвует в создании патча, устраняющего проблему, но до того, как патч будет принят, мы не можем раскрывать подробности.
                                              0
                                              Styled-components, я люблю тебя! СSS in JS – one love! Мой внутренний верстальщик ликует:


                                              1. Как решаете вопрос с поддержкой подсветки?
                                              2. Как с читаемостью когда CSS кода нужно много в JS?
                                                0
                                                1. Большинство наших фронтендеров используют плагины, перечисленные в официальной документации — www.styled-components.com/docs/tooling#syntax-highlighting.

                                                2. При адекватном форматировании код легко читается, а много кода это повод разбить его на несколько компонент. Мы не испытываем проблем с читаемостью.
                                                0
                                                Пример с ChangePhoneForm на реакте, это настоящая реализация в проекте?
                                                зачем байндить метод в рендере? Вы же в компонент Form будете передавать каждый раз новую ф-цию. Почему не сделать метод, как arrow function или не забайндить в конструкторе? Или я чего-то не понимаю?
                                                  0
                                                  Пример с ChangePhoneForm — не настоящая реализация, а упрощенный пример кода. Вы правильно заметили, что делать bind нужно в конструкторе.

                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                Самое читаемое