
Когда видишь компанию со стороны, одни вещи понимаешь, а другие остаются секретом. О том, что SM Lab отвечает за IT-решения в группе компаний «Спортмастер», можно догадаться уже по названию и логотипу. Но, например, сколько разработчиков заняты этими решениями? Какие именно у них проекты? Это куда менее очевидно.
Мы проводим конференции по разным IT-направлениям, на них неоднократно выступали спикеры из SM Lab, и некоторые вещи можно понять по их докладам. Например, на Mobius рассказывали про «Генерацию этикеток для термопринтеров на основе языка разметки ZPL», а на Heisenbug помогали другим с «Первыми шагами в нагрузке».
А на этой неделе SM Lab примет участие в нашей Java-конференции JPoint, и я решил, что сейчас самое время задать вопросы о Java-разработке сотрудникам самой компании. Публикую результат, в котором соединены вместе ответы нескольких разных людей.
— Что вообще такое SM Lab? Что именно там делают, какие языки и технологии используют?
— SM Lab — ИТ-компания в составе группы компаний «Спортмастер». Мы трансформируем бизнес-процессы, переводя их в цифровое пространство, и создаём уникальные технологические решения для ритейла. Развиваем флагманские продукты — продающие сайты и мобильные приложения, разрабатываем внутренние продукты, поддерживающие бизнес-процессы компании — платформы, сервисы, back-office системы и другое.
Мы используем Java 21, Kotlin, Spring, Oracle 19.5, JS, Vue.JS, Swift, Elasticsearch, 1С, K8s, MongoDB, Nginx.
— А если говорить конкретно про Java-разработку: например, сколько разработчиков, какой технологический стек?
— SM Lab насчитывает более 120 Java и Kotlin разработчиков (это суммарно). Среди них есть и чистые джависты, и чистые котлинисты. По процентному соотношению Java/Kotlin сейчас примерно 70/30.
Наш стек конкретно в JVM-мире: Java, Kotlin, Spring, Prometheus, Docker, ElasticSearch, RabbitMQ, Kafka, Oracle, K8s, Grafana, Maven.
— Можете привести пример того, как Java-разработчики сталкиваются с предметной областью? Какая задача у них может возникнуть в SM Lab, которая вряд ли возникла бы в компании совсем другого профиля?
— Например, на Java у нас написан продукт «Касса». Касса — это ключевое понятие в ритейле. Этот продукт помогает эффективно решать критически важные для retail-компании задачи по исполнению сделки с клиентом: прием платежей, выдача товаров и оказание услуг, формирование фискальных чеков. А также предоставляет данные, чтобы учитывать эти операции для формирования отчетности.
Тут мы находимся на передовой при изменениях в законодательстве или просто взаимодействии с покупателями. Поэтому при работе с чеками пришлось подробно разбираться в реквизитах и тегах для ФНС (особенно при печати чеков коррекции), некоторые моменты приходилось уточнять непосредственно в законодательстве на сайте КонсультантПлюс. Часто ли в мире Java-разработки открывают этот сайт? :)
— А если не привязываться к специфике: можете ли подробно рассказать о любом крупном и «долгоиграющем» проекте с Java-разработчиками? Давайте пойдём с самого начала: когда и как он возник и развивался?
— Первый интернет-магазин «Спортмастера» появился в начале 2010-х. Он был реализован на платформе 1C-Bitrix. В результате роста количества покупателей она перестала справляться с нагрузкой, из-за чего были попытки её оптимизировать и доработать. Через какое-то время пришли к выводу, что дальнейшие усилия в данном направлении бессмысленны, и было принято решение о создании собственного сайта.
Примерно в 2013 году началась работа по проектированию и реализации. Проект разрабатывался на Java 1.8 с использованием Spring 4, для полнотекстового поиска использовался ElasticSearch 1.4, распределенный кеш был реализован на Hazelcast. Для работы сайта необходимо было загружать много разнообразной информации из бэкофисных систем. Для этих целей был выбран ETL Pentaho.
В 2015-ом году новый сайт вышел в продакшн. Не все запланированное было реализовано: админка тогда осталась в Битриксе. С этого момента сайт начал быстро развиваться и обрастать новой функциональностью. Стали появляться новые сервисы и интеграции. Появилась мобильная версия сайта, реализованная на Angular и использующая API проекта, появился «Киоск» — специальная версия для больших тач-устройств, установленных в магазинах. Через какое-то время появилось первое мобильное приложение, которое также использовало наш API. Также была реализована версия сайта для контакт-центра.
Активное развитие продолжалось примерно до середины 2018 года. В это время все больше набирал популярность онлайн-формат, что кратно увеличило аппетит бизнеса: захотелось быстро поднимать аналогичные сайты для других бизнес-направлений. После оценки возможности переиспользования наработок мы поняли, что получившийся монолит будет трудно адаптировать под другие бизнес-требования. Также к этому моменту накопилось определенное количество труднорешаемых проблем: поддержка админки в битриксе съедала все больше ресурсов, неудачное решение с ElasticSearch не позволяло обновиться на актуальную версию, а используемая очень сильно устарела, проект не успевал адаптироваться к постоянно возрастающей нагрузке.
В связи со всем этим было принято решение об очередном перепроектировании.
Выделили определенный набор требований:
общую функциональность (корзина, товары, контент и т.д.) вынести в отдельные сервисы
кодогенерация по контрактам
отзывчивость и масштабируемость
сокращение времени на поддержку
Таким образом, в 2020 году началось создание новой версии сайта СМ 3.0 — уже на собственной платформе, которую решили писать на Kotlin + Spring 5 с использованием реактивного стека. Сразу же была заложена возможность кодогенерации по контрактам. Для этого используется доработанный OpenAPI Generator. Для снижения затрат на поддержку с самых первых дней много внимания уделялось написанию автотестов. На текущий момент у нас используются практически все виды автотестирования. На бэкенде мы используем kotest с собственными расширениями для модульного и интеграционного тестирования. Для автотестов вокруг Selenide нарастили свой фреймворк с кодогенерацией, распараллеливанием, шахматами и поэтессами. Плюс активно используем wiremock для API-тестов.
Много споров было вокруг того, какую архитектуру выбрать, но в итоге предпочтение отдали набиравшей популярность DDD. На данный момент можно констатировать, что у нас получилось реализовать чистый DDD.
Фронт реализовали на VueJS 2, но в прошлом году мы успешно мигрировали на третью версию.
Для сокращения ручного труда с самого начала разработки мы стремились к чистому CD, об этом уже рассказывал мой коллега на Joker. И в итоге у нас это получилось: на данный момент момент пайплайн в GitLab сразу же после мержа ветки разворачивает новую версию приложения в Kubernetes. Для этого была проделана следующая работа: мы перешли на trunc-based разработку, был создан свой Feature Toggle-сервис, научились поднимать короткоживущие динамические окружения для проведения автотестов. Также для удобства ручного тестирования и демонстрации функциональности добавили возможность поднимать собственные окружения для любой ветки. Для повышения качества кода в пайплайн мы также интегрировали статический анализатор Detekt, настроили QualityGate в SonarQube, который следит за минимальным покрытием кода тестами, интегрировали DependencyCheck от OWASP, который позволяет автоматизировать поиск уязвимостей во внешних зависимостях.
Разбиение монолита на сервисы помогло отбросить всю дополнительную работу и сосредоточиться именно на сайте.
Раз был упомянуто выступление на Joker, я решил заодно посмотреть его и кратко пересказать для Хабра суть.
Она оказалась такой:
Ранее в SM Lab после деплоя возникало небольшое снижение трафика. Дело было в том, что обычно всё работает в «прогретом» состоянии, а после деплоя нового кода сервису сначала требовалось время на прогрев. И в такие моменты пользователь мог получать ответ с большой задержкой, расстраиваться и уходить на другой сайт. В такой ситуации деплоить хочется пореже и по ночам, но это увеличивает time-to-market и в целом осложняет жизнь.
Рассмотрев разные варианты, в компании пришли к следующему: при балансировке нагрузки с Kubernetes использовать решение для так называемой EWMA-балансировки (exponentially weighted moving average). В этом случае запросы пользователей по умолчанию отправляются туда, где они с большой вероятностью окажутся обработан быстро. Так что «прогреваемые» инстансы не получают сразу же много запросов и не подводят всех этих пользователей долгой обработкой, а постепенно «входят в строй». При этом важно не раскатывать апдейт одновременно везде, а немного распределить его во времени (чтобы не оказалось, что всё прогревается одновременно, и отправлять запросы пользователей для быстрой обработки пользователей «некуда»).
Применив это, получилось в разы снизить время ожидания для 99-го перцентиля, а благодаря этому — деплоить быстрее и спокойнее, сократить time-to-market и уйти от «ночных деплоев».
А ещё одно выступление SM Lab на JPoint было про архитектурные вопросы:
В вечном выборе «аджайл или водопад» нет единственного верного ответа, на практике компании обычно выбирают что-то «между», потому что обе крайности с недостатками. Если пытаться «по-водопадному» спроектировать всё заранее, неизбежно потом сталкиваешься с тем, что на практике многое оказывается не как было «на бумаге». Но если совсем уж «импровизировать на ходу», тоже можно обнаружить, что забрёл не туда: какие-то важные требования остались невыполненными, и реализовать их уже сложно, так что всё-таки надо было сразу зафиксировать главное.
А что будет этим «главным»? В выступлении разбирают, как в SM Lab могут выглядеть ASR (Architecture Significant Requirement) на конкретном небольшом примере «полезного чат-бота».
После ответов компании картина частично стала мне яснее, однако всё-таки не полностью. Но на нашей конференции JPoint, которая пройдёт уже 3-4 апреля, SM Lab будут присутствовать — так что если у кого-то из её участников тоже остались вопросы, то вот там будет удобная возможность всё доспросить в перерывах между докладами.