Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Привет, Хабр! Команда Учи.ру традиционно подводит итоги учебного года. Для нас — это сезон не только крупных продуктовых релизов, но и изменений под ИТ-капотом Учи.ру. Сегодня команда поделится, что нового произошло в архитектуре и разработке платформы и что сподвигло их на эти изменения.
Начали активно работать в сторону сервисной архитектуры
С середины 2021 года мы стали активно заниматься осмыслением и переработкой существующей архитектуры, которая впоследствии начала приобретать очертание микросервисной. Примерно с того же самого времени количественная характеристика по доставке кода в большое монолитное приложение Учи.ру имеет тенденцию к понижению.
Опытный архитектор всегда ощущает момент, когда большое и неповоротливое монолитное приложение начинает мешать бизнесу адаптироваться к постоянно меняющимся условиям рынка. Поэтому мы стали успешно внедрять сервисный подход и выносить из монолита не очень большие и не перегруженные части — сервис заданий, состоящий из интерактивных упражнений, и другие, о которых расскажем позже. Это облегчает дальнейшее развитие проекта, помогает лучше понимать работу продукта и делить ответственность между командами.
Модульный распил монолита
Там где подобный подход оказался трудоемкой задачей, мы начали с разделения кодовой базы на отдельные модули для облегчения последующих работ по переезду. Делить монолиты логично на директории — модули (package). Rails по умолчанию не дает такой возможности, не считая rails engines, но они оказались неудобны в разработке. А packs-rails позволяет обособить модули в отдельные папки (packs/feature1, packs/feature2), у каждой из которых есть свои app, config, lib, spec. Он добавляет правила автозагрузки кода (для zeitwerk), чтобы все это заработало.
Позже это поможет проще перенести код в отдельный сервис, если понадобится. Если пойти дальше, то можно взять библиотеку с открытым исходным кодом (gem) packwerk, чтобы отслеживать степень зацепления модулей между собой. В идеале мы пытаемся добиться высокой внутренней связности модулей и низкого внешнего зацепления (зависимости) с другими. Packwerk позволяет проверять код и искать зависимости между модулями, сопоставлять разрешения из конфигурационного файла, выбрасывая исключения всякий раз, когда используется константа из неразрешенной зависимости.
Начали применять FSD
Подобную технику можно применить и к интерфейс-приложениям. В Учи.ру мы стремимся разделять фронт и бэк. Но так же в нашем сервисе есть продукты, существующие давно. Некоторые из них выполнены на устаревшем стеке — к ним относятся Олимпиады. В этом продукте мы перешли с единого бэкенда с фронтендом — ruby и slim — на раздельный бэк— ruby — и фронт — next.js.
Там где это уже было, мы начали применять Feature Sliced Design (FSD). Это еще один шаг к упрощению наших задач. Мы стали использовать FSD в разработке новых приложений, рефакторинге или расширении текущих.
Единый подход в организации приложения позволит нам сократить тот контекст, который вынужден обозревать разработчик, переключаясь на очередной проект. Это упрощает поддержку и ускоряет разработку нового функционала.
Сделали инструмент для тестировщиков
Поскольку отдел тестирования следует за выбранным курсом в области архитектуры, то аналогичные подходы возможно применить и к тестированию распределенных систем. Раньше у нас были проблемы с автоматическим тестированием: например, на прогоне тестов появлялось много учеток, которые нужно было чистить. А из-за ограничений по безопасности у нас предусмотрены несколько разных блокировок учетных записей от перебора — это приводило к неуспешным прогонам.
Чтобы решить эти проблемы, мы сделали шлюз для тестировщика, через который можно выполнять системные действия, не открывая доступа в интернет. В числе этих действий: сброс пароля, ограничения на перебор телефона, почты, логина, а также блокировок по IP адресам. Это позволило отвязаться от админки и необходимости дорабатывать ее под нужды инженеров-тестировщиков.
Начали использовать шапку как сквозное приложение для всей роли учителя
Шапка учителя — это микросервис, который по ESI-технологии встраивается в любое приложение-потребитель: например, в задания от учителя, личный кабинет (ЛК) и так далее. Он позволяет централизованно переиспользовать эту шапку, где она нужна, и выполнять сбор обратной связи, онбординг, переключать классы в ЛК учителя и олимпиадах.
Микросервис позволяет сделать изменения в шапке один раз, а потом в любом приложении-потребителе запускать функционал: например, показ модальных окон или опросников. Это упрощает разработку и поддержку фич, которые одинаково выглядят и работают вне зависимости от конечного приложения-потребителя.
Частично перешли с классической модели аутентификации на JWT
В связи с эволюцией архитектуры встал вопрос о системе аутентификации, отвечающей текущему вектору развития платформы. В настоящем варианте обнаружились следующие недостатки:
гетерогенная (разрозненная) система;
отсутствие стандарта работы с аутентификацией;
большая разница между работой мобильного приложения (JWT) и остальной части — rails-based cookies.
Рост числа сервисов и необходимость читать cookies монолита вызывает определенные сложности (алгоритм подписи проприетарный и зависит от версии rails) и приводит к росту сетевой нагрузки на систему аутентификации и авторизации. Из-за этого приходится делать дополнительные запросы на проверку состояния сессии и ее дешифровки при каждом обращении к серверу, даже если это статика с интерфейс-приложением. А клиентские приложения сейчас максимально просты и беспомощны.
Перечисленные процессы порождают не всегда оправданные сложности в транспортировке состояния сессии между приложениями. Также разработчикам надо взаимодействовать с аутентификацией по-разному, в зависимости от платформы. При реализации альтернативных источников аутентификации, отличных от входа с главной страницы, приходится всегда изобретать костыли или использовать монолит для входа. И это не всегда удобно. А JWT позволяет на разных устройствах сбрасывать сессию относительно просто.
Поэтому мы частично перешли на JWT. Сервис состоит из сервера со статикой, содержащего две входные точки (entrypoint):
script.js — встраивается в страницу и предоставляет API для взаимодействия с сессией текущего пользователя;
worker.js — нужен для фоновых процессов: поддержания access token в актуальном состоянии во время работы пользователя на сайте.
После инициализации библиотеки клиент может получить доступ к транспортному уровню сессии, забрать access token и, приложив его к специальному заголовку, работать с защищенными маршрутами серверов.
Система состоит:
из браузера пользователя;
worker’a, устанавливаемого в нем;
сервиса, занимающегося хранением скриптов для этого самого worker’a;
и js-файла, дающего начало процессу развертывания.
Это не все, что было сделано за этот год: на основе разработанных технологий и созданного базиса мы сделали новые возможности для дальнейшего развития сервисов, ориентированных на пользователей. Об этом мы расскажем в следующем тексте.
Хотите развивать EdTech вместе с нами? Присоединяйтесь к команде Учи.ру — переходите на сайт и выбирайте открытые вакансии!