Русский
Русский
English
Статистика
Реклама

Организация кодовой базы и тестирования в монорепозиторий

Всем привет. Меня зовут Илья, я фронтенд-разработчик изюнита BuyerX вАвито. Хочу поделиться тем, каким образом унас вкоманде организовано хранение кодовой базы, почему мы пришли киспользованию монорепозитория и как улучшаем DX-работы сним, а также кратко рассказать проорганизацию тестирования.



Текущее положение дел


Юнит BuyerX отвечает застраницы и функциональность, которая помогает пользователю выбирать товары наАвито. То есть мы стараемся сделать пользователя покупателем. Кнашей зоне ответственности относятся главная страница, страницы объявлений и страницы споисковой выдачей. Страницы споисковой выдачей могут быть специфичными подопределённые категории: например, где-то не нужны поисковые фильтры или нужен особый заголовок страницы и расположение самих элементов.



Главная страница Авито



Страница поисковой выдачи



Страница объявления


Разработка этих страниц вызывала определённые проблемы:


  • Все шаблоны жили вогромной основной кодовой базе, где было сложно ориентироваться и вносить изменения.
  • После внесения даже маленьких изменений сборка проекта занимала продолжительное время до5-10 минут вхудшем случае и потребляла большое количество ресурсов компьютера.
  • Когда хотелось, чтобы отдельные компоненты работали наReact-е, приходилось дублировать вёрстку и вшаблоне, и вкомпоненте длятого, чтобы сделать механизм серверного рендеринга.

Кроме того, главная страница, страницы объявлений и страницы споисковой выдачей позволяют создать непрерывный сценарий покупки дляпользователя. Поэтомув своё время мы приняли решение переписать их слегаси-технологии Twig наReact, чтобы вбудущем перейти наSPA-приложение, а также оптимизировать процесс загрузки компонентов длякаждой изстраниц. Так, кпримеру, сниппет объявления наглавной и странице поиска одинаковый. Тогда зачем грузить его два раза?


В связи сэтим появился npm-пакет, который мы гордо назвали single-page. Задача этого пакета содержать внутри себя верхнеуровневое описание каждой изстраниц. Это описание того, изкаких React-компонентов состоит страница, и вкаком порядке и месте они должны быть расположены. Также пакет призван управлять загрузкой нужных и выгрузкой уже ненужных компонентов, которые представляют собой небольшие React+Redux приложения, вынесенные вотдельные npm-пакеты.


Например, припереходе настраницу срезультатами поиска, пользователю необходимы поисковые фильтры, которые позволят сузить выдачу. Вданном случае single-page определяет, что необходимо запросить пакет сфильтрами и делает соответствующий запрос. Если пользователь уже перешёл настраницу объявления, то поисковые фильтры ему не нужны, а значит и сам пакет можно не использовать, чтобы он не ухудшал производительность страницы.


Сам пакет single-page уже работает как описано. Однако длятого, чтобы все описанные механики приносили пользу, переход между страницами должен быть бесшовным, как вSPA-приложениях. Ксожалению, намомент написания статьи бесшовных переходов между страницами нет. Но это не значит, что их не будет. То, каким образом сейчас работает пакет single-page это основа, которую мы будем развивать дальше. Она уже задала определённые правила, связанные сорганизацией кодовой базы, которых мы вюните придерживаемся.


Расскажу, как именно происходила эволюция работы срепозиториями npm-пакетов, и кчему мы пришли.


Отдельные репозитории для npm-пакетов


Как я упоминал ранее, изначально главная страница и страница споисковой выдачей были написаны сиспользованием шаблонизатора Twig. Был один большой шаблон страницы, который импортировал всебя более мелкие шаблоны отдельных компонентов страницы.


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


Стало понятно, что необходимо переходить нановый стек React. Переход проходил поэтапно. Сначала вюните договорились, что все новые компоненты будут написаны сразу наReact-е и будут рендериться настраницу послееё загрузки. Эти компоненты слабо влияли наSEO, поэтому подход имел право нажизнь. Пример такого компонента блок спросмотренными и избранными объявлениями наглавной странице:



Для работы новых компонентов наReact-е иногда нужны были уже существующие компоненты, написанные наTwig-е. Поэтому мы начали переносить некоторые изних наReact вурезанном виде. Так, кпримеру, сниппет, который используется вблоке просмотренных объявлений, был частично перенесён нановый стек, хотя наTwig весь шаблон сразличными условиями, влияющими наинформацию всниппете, содержал более 1000строк.



Сниппет вблоке просмотренных объявлений, который был перенесён сразу нановый стек


А вот как выглядят сниппеты вразличных категориях:



Сниппет вкатегории бытовой электронике



Сниппет вкатегории работа



Сниппет вкатегории недвижимость



Сниппет вкатегории автомобили


Вынос вnpm-пакет это только часть работы. Длятого, чтобы пакет был полезен, он должен быть использован восновной кодовой базе. Поскольку все компоненты это отдельные пакеты, то вмонолите (основной кодовой базе) необходимо подключить их как зависимости, а далее проинициализировать эти пакеты вкоде. Так как блок просмотренных объявлений и сниппет были выделены вотдельные npm-пакеты, то вкодовой базе монолита они были подключены как зависимости. Чтобы увидеть изменения, которые появились сновой версией пакета, достаточно поднять его версию безвнесения каких-либо дополнительных изменений.


Как видите, между пакетами уже появляются зависимости: монолит зависит откомпонента блока просмотренных и избранных объявлений, который всвою очередь зависит откомпонентов сниппета. Но вданном случае связь небольшая, поэтому после внесения изменений вnpm-пакет сниппетов необходимо:


  • поднять его версию;
  • опубликовать её;
  • подключить новую версию вкомпоненте правого блока;
  • поднять его версию;
  • поднять версию вмонолите.

Это может звучать сложно, но наделе процесс занимал минуты две и не требовал особых навыков.


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


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


Уподхода, когда каждый npm-пакет жил всвоём репозитории, был и свой плюс. Приподнятии версии зависимости вкаком-нибудь пакете, необходимо было убедиться, что этот пакет не сломается приработе насайте. То есть нужно было протестировать все внесённые изменения. Проверки побольшей части приходилось делать руками существовавшего набора тестов и инструментария было недостаточно дляпокрытия большинства сценариев. А принахождении каких-либо багов втестируемом пакете, их нужно было исправить. Поэтому нередко присутствовала практика, когда версию зависимости поднимали не везде, а только там, где это необходимо. Содной стороны, это усугубляло рассинхронизацию версий зависимых пакетов, а с другой сильно упрощало тестирование засчёт отсутствия некоторых проверок.


Однако вкакой-то момент рассинхронизация версий зависимостей привела кновым проблемам: пакет мог содержать сильно старую зависимость и простое её обновление могло сломать работу всего пакета. Из-заэтого приходилось тратить лишнее время наактуализацию зависимостей, внесение правок всам пакет и, возможно, взависимые тоже, а также натестирование этого пакета. Конечно, вкаждом репозитории были тесты, чтобы проверить, что всё работает корректно. Но тесты были только скриншотные, что ограничивало круг покрываемых вещей. Плюс не вовсех репозиториях был подключен CI, чтобы тесты прогонялись накаждом пул-реквесте.


Что получилось наэтом этапе:


  1. Количество связанных пакетов выросло.
  2. Каждый пакет жил вотдельном репозитории.
  3. Вкаждый репозиторий создавался пул-реквест свнесением изменений, связанных споднятием версий зависимости.
  4. Ситуация, когда пакет не имел последнюю актуальную версию зависимости была нормой. Плюс, кэтому моменту уже создавался пакет single-page, который взависимостях имел все ранее созданные пакеты.

Всё это привело к тому, что мы начали искать пути дляулучшения работы срепозиториями и всеми нашими пакетами.


Переход к монорепозиторию


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


После небольшого эксперимента и ресёрча, стало понятно, что Lerna поможет решить часть наших проблем:


  • С ней не будет необходимости вкаждом пакете самим поднимать версии зависимых пакетов.
  • Отпадёт необходимость постоянно помнить прозависимости, потому что Lerna знает, какие пакеты какими версиями связаны.
  • Количество пул-реквестов уменьшится доодного, вкотором видны все зависимости, которые будут изменены.

Мы завели отдельный репозиторий, вкоторый начали переносить все пакеты и связывать их зависимостями черезLerna.


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


Длярешения этой задачи внутри нашего юнита нашелся доброволец, который хорошо разобрался вособенностях работы Lerna и поделился знаниями намастер-классе. Но как быть состальными? Как быть сновыми разработчиками, которые приходят вкомпанию и вносят свои изменения? Проводить мастер-класс каждый раз не будешь. ВReadMe инструмента, как и внутри нашего монорепозитория, есть инструкция дляработы, но она не всегда помогает. Из-занепонимания случалось следующее:


  • врепозитории обновлялись лишние пакеты;
  • восновной кодовой базе монолита поднято меньше зависимостей, чем должно быть;
  • или наоборот зависимостей поднято больше, чем должно быть.

Кроме того, перед тем, как опубликовать пакет, необходимо обновить длянего changelog. Вбольшинстве случаев он является копипастой, но её необходимо повторить внескольких репозиториях. Дляодного-двух это не проблема, но когда пакетов становится десяток, легко где-то допустить ошибку или забыть добавить запись вchangelog. А это значит, что придётся вносить исправления и ждать, когда завершит свою работу билд CI.


Возникшие проблемы мы решили черезавтоматизацию. Дляэтого написали специальный скрипт, который:


  • находил все зависимые пакеты;
  • поднимал вних dev или latest версию взависимости отпотребности;
  • добавлял changelog всем пакетам;
  • заменял новые версии вpackage.json файле монолита нановые и, вслучае dev пакетов, ещё и публиковал их.

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


Работа CI


Остаётся ещё один вопрос, который хочется подсветить: CI.


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


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


Итоги и планы


Задва года мы прошли процесс перехода отбольшого количества слабо связанных репозиториев доавтоматизации работы смонорепозиторием черезLerna. Приэтом, есть гарантия того, что всё будет работать корректно благодаря прогону тестов накаждом пул-реквесте. Количество самих пул-реквестов уменьшилось с8-9 вхудшем случае додвух: вмонолит и вмонорепозиторий. Приэтом пул-реквест вмонорепозиторий содержит сразу все изменения.


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

Источник: habr.com
К списку статей
Опубликовано: 09.10.2020 16:18:18
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании авито

Разработка веб-сайтов

Системы управления версиями

Управление разработкой

Frontend

Lerna

React

Ci

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru