Как стать автором
Обновить
838.5
Яндекс
Как мы делаем Яндекс

Как переписать фронтенд нагруженного проекта и не потерять главного

Время на прочтение9 мин
Количество просмотров17K

Обложка статьи


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


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


Знакомо? Если да, то вы в непростой ситуации. Она закономерно возникает в большинстве проектов, которые за годы своего существования накопили достаточный объём legacy.


Возможно, вас ждут и такие опасности:


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

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


Недавно команда фронтенда Яндекс.Маркета также столкнулась с описанной ситуацией. У нас начало расти время разработки нового функционала, появились участки кода, которые могут сопровождать только «старички», нанимать и адаптировать новых членов команды стало сложнее и дороже. Чтобы справиться с этим, нам пришлось обновить свой технологический стек и переосмыслить часть процессов разработки и поставки нового функционала.


Как менялся фронтенд Маркета


Яндекс.Маркет существует уже 19 лет. Подумать только, пройдёт ещё немного времени, и он будет старше некоторых своих разработчиков. За эти годы фронтенд был переписан несколько раз.


XSLT


На заре развития сервиса и в последующие десять лет основой фронтенда Маркета была технология XSLT. На клиенте использовались JS-скрипты с рядом вспомогательных библиотек, БЭМ и набор портальных UI-компонентов Яндекса. Cерверная часть фронтенда работала на XScript — внутренней разработке Яндекса, базирующейся на XSL-трансформациях.


Главная страница Яндекс Маркета на XSLT


Вот так декларативно делались http-запросы к бэкендам на фронте Маркета в 2015 году:


<w.resource id="market-touch:models-top">
    <x:http>
        <x:guard type="StateArg">market:models-top.ids</x:guard>
        <x:method>getHttp</x:method>
        <x:param type="StateArg">market:config.some-host</x:param>
        <x:param type="String">GetCards?ids=</x:param>
        <x:param type="StateArg" as="Long">market:models-top.ids</x:param>
        <x:param type="String">&amp;type=micro</x:param>
        <x:param type="String">PopularModels?</x:param>
        <x:param type="String">&amp;region=</x:param>
        <x:param type="String">&amp;n=</x:param>
        <x:param type="StateArg" as="Long">market:models-top.count</x:param>
        <x:param type="StateArg" as="String">market:exp.guru-params</x:param>
    </x:http>
</w.resource>

А вот такие сообщения об ошибках получал разработчик:


<xscript_invoke_failed reason="UNKNOWN"
   object="Yandex/Example/Example :
      exampleRequestAuth /usr/local/www/assessor-ng/test.xml"/>

Представьте, сколько времени потребовалось бы, чтобы передать все необходимые знания новому члену команды в 2020 году. Неприемлемо много для быстро развивающегося проекта.


NodeJS


В 2016 году фронтенд Яндекс.Маркета перешёл на NodeJS. Это было непросто и потребовало много времени. Процесс был поступательным, в нём приняло участие большое количество инженеров Маркета. Использование NodeJS позволило нам работать с одним языком, решая задачу сразу в двух окружениях: на сервере и на клиенте. Появились полиморфные части кода и новая архитектура серверной части фронта. Был придуман и запущен процесс обучения команды. Мы стали эффективнее.


Изменения произошли и на клиенте. Появился новый JS-шаблонизатор Yate (Yet Another Template Engine). Он был разработан внутри Яндекса и наследовал некоторые идеи из XSLT. Использование этого шаблонизатора позволило заменить лишь инструмент, частично сохранив парадигму в умах разработчиков, которые до этого несколько лет работали с XSLT. Нам удалось ускорить обновление кодовой базы Маркета и сократить время на адаптацию новых сотрудников. Yate когда-то даже был выложен на GitHub и имеет свой playground. Попробуйте, если интересно.


Главная страница Яндекс Маркет 2015 год


Актуальный стек


В 2019 году технологический стек фронтенда Маркета обновился вновь. На сервере появилась статическая типизация (Flow), была доработана архитектура, вынесен общий код. Страницы разделились на новые виджеты и начали загружаться на клиент прогрессивно.


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


Виджеты на странице категории Яндекс Маркета


Что касается прогрессивной загрузки, то в классическом подходе html-страница в рамках одного GET-запроса компонуется (шаблонизируется) на стороне сервера, затем отдаётся браузеру. Происходит это по такой схеме:


Схема классической модели загрузки web-страницы


В модели, реализованной на фронте Маркета, сервер оперирует виджетами, которые отдаются на клиент чанками, сразу отображаются и инициализируются. То есть пользователь уже может что-то набирать в поисковой строке, пока страница ещё догружается. А в это время на сервере будут запрашиваться данные для других частей страницы. Важно, что это происходит в рамках одного обычного GET-запроса/ответа.
Такая загрузка страницы напоминает прогрессивную подгрузку JPEG. Отсюда и название.


В сравнении с классической (слева), прогрессивная загрузка (справа) выглядит так:


Схема прогрессивной модели загрузки web-страницы


Больше деталей можно найти в этом докладе.


Клиент мобильной web-версии Маркета мы перевели на React + Redux. Почему не на Vue.js? Мы устроили соревнование между двумя фреймворками. Две команды энтузиастов портировали страницу поисковой выдачи Маркета на обе технологии. По итогам внутренних бенчмарков и тестов React в нашем проекте показал себя лучше. К тому же он был более распространён в других проектах компании.


После завершения текущего обновления последуют новые. Что будет меняться — зависит от трендов в индустрии фронтенда. Поживём — увидим.


Проводить подобные обновления сложно. Hо сложность эта полностью преодолима при правильной подготовке. Важно помнить, что если обновления не планировать и не проводить вовсе, то «сложно» со временем обязательно превратится в «невозможно», и вас могут ждать уже другие опасности. Не стоит до этого доводить.


Как переписать фронтенд нагруженного проекта


Оглянувшись на недавнее обновление технологического стека в Маркете, приведу несколько советов.


Оцените, нужно ли вам обновляться именно сейчас. Стоит остановиться и ещё раз подумать, точно ли обновление — единственный выход, и не лечатся ли проблемы на сервисе как-то иначе.
В Маркете на этом этапе собирается рабочая группа из руководителей и опытных разработчиков. Задача такой группы — определить целесообразность обновления, выбрать перспективные технологии, предложить первичный план и стратегию.


Изучайте популярные технологии и тренды в индустрии. Стройте прототипы с использованием этих технологий в песочнице. Мы проделывали это с поисковой выдачей Маркета.


Стремитесь заранее понять, что подойдёт вашему сервису, а что нет. Не поддавайтесь хайпу, принимая решение внедрять что-то в проект. Смотрите на свои прототипы и результаты их тестирования. Оцените готовность команды работать с перспективной технологией. Если технология не подходит вашему сервису или команде, ищите альтернативы.


Зафиксируйте состояние ключевых метрик. Определите, какие метрики играют ключевую роль для вашего бизнеса, откуда и как сервис получает трафик, какие существуют внешние SLA, как распределяется нагрузка, когда стартуют маркетинговые компании и так далее. Что точно нельзя сломать? Следите за ключевыми метриками по ходу работ.


При обновлении фронтенда Маркета мы следим за всем перечисленным: используем Grafana, Graphite и другие инструменты для построения графиков, мониторинга и обнаружения деградаций на сервисе.


Разработайте план. Переходить на новую технологию придётся не останавливая сервис и не допуская никаких деградаций для пользователя. Альтернативный план также не будет лишним. Вы сможете лучше разобраться в том, насколько сложны работы, и двигаться к цели увереннее и быстрее. Продумайте, какими частями вы будете обновлять сервис: страницами, блоками, только сервер и потом клиент или как-то иначе.


При переводе Маркета на React нам пригодился и альтернативный план. Одну часть сервиса мы портировали постранично, другую — блоками и виджетами.


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


Обновление Маркета мы начали с самых важных страниц: главной, поисковой выдачи, карточки товара. Это самые конверсионные, самые нагруженные и самые технически сложные страницы сервиса.


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


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


Достаньте с высокой полки и изучите старые гайды по дизайну. Если их не было, переносите стили как есть (оптимизировать будете после), проводите дизайн-ревью обновлённой части сервиса. Только не пытайтесь проводить редизайн продукта при переходе на новую технологию. Переходите как есть.


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


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


Мы продумали файловую структуру заранее, зафиксировали и описали её в документации. Перестроили и проверили сборку до начала работ по обновлению основного функционала.


Не игнорируйте тесты. Полезны будут все виды тестов: unit, интеграционные, e2e. Если можете, допишите тесты на ключевой функционал до старта работ по переходу на новую технологию. Если тестов нет и писать некогда — пишите по ходу работ. Рефакторинг без тестов возможен, но больше похож на вождение автомобиля с закрытыми глазами. Может и пронесёт.


Замеряйте клиентские метрики вашего ресурса: TTI, TTR, TTFB, TTLB и другие. Зафиксируйте показатели до начала работ и следите за ними по ходу продвижения к цели. Это поможет обнаружить деградации вовремя, сэкономит время и силы команды, сбережёт деньги бизнеса.


В Маркете установлены SLA на ряд клиентских метрик: TTI (time to interaction), TTR (time to render) и другие. При переходе на React мы неоднократно выходили за допустимые границы скорости работы нашего сервиса. Наличие SLA позволяло нам сразу замечать деградации, оптимизировать проблемный код до поставки в продакшн.


Воспользуйтесь A/B-тестированием при обновлении важных частей сервиса. Проверить технические усовершенствования в эксперименте только на срезе аудитории сервиса — хорошая идея. Если что-то пойдёт не так, расследовать деградации и чинить баги будет проще.


Во время портирования мобильной web-версии Маркета на React, мы провели почти 200 дней экспериментов. Однажды A/B эксперимент даже помог нам обнаружить и устранить нетривиальную утечку памяти в браузере. В экспериментах мы неоднократно видели, как незначительные, на первый взгляд, изменения могут негативно влиять на ключевые бизнес-показатели Маркета.


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


Придумайте заранее способ запуска новой технологии поверх старой и наоборот, если это возможно. Мы переписывали Маркет постранично, а каждую из страниц — повиджетно. Нам очень пригодилась возможность использовать React-виджеты в Yate-шаблонах.


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


Надеюсь, наш опыт будет вам полезен. Главное, наберитесь терпения, начинайте с самого сложного и не забывайте радоваться победам. Лёгкого обновления.

Теги:
Хабы:
+28
Комментарии17

Публикации

Информация

Сайт
www.ya.ru
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия