Как стать автором
Обновить

Как мы подружили склад и Kotlin: техническая изнанка управления товаром

Время на прочтение7 мин
Количество просмотров5.1K
Всем привет! Меня зовут Влад Кошкин, я Java-разработчик в одной из команд направления Warehouse Management System (WMS) в Lamoda. Помимо интернет-магазина, у нас есть собственный склад, где прием товара от поставщика, хранение, сборка заказа, упаковка и отправка покупателю полностью оцифрованы и в значительной мере автоматизированы.

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

Также в этой статье я сделал небольшое ревью наших технологий: как мы переехали с Java Server Faces на Kotlin и Android, как работаем сейчас и какие у нас амбиции на ближайший год.



Путь товара по складу


На складе мы используем систему Warehouse Management System и мобильный сканер, которым пользуются сотрудники. Пользователь оперирует десятками операционных сущностей: грузовик, товар, полка шкафа, посылка, упаковочный материал и другие. Каждая из них, даже грузовик, имеет штрихкод с уникальным номером. Абсолютно все значимые изменения статуса объектов транслируются в систему. Устройство дает инструкции сотруднику склада, что именно делать, и организует рабочий процесс.

Упрощенно цикл движения товара на складе выглядит следующим образом:

  • Прием грузовика и распознавание/идентификация товара. Наша задача — понять, какие вещи и в каком количестве приехали на склад. Допустим, это была фура с кроссовками. Сразу после разгрузки мы производим соответствие между коробками обуви и номенклатурой (списков всех наименований товаров от конкретного поставщика), которая хранится у нас в базе данных. Другими словами, мы «показываем» системе товар, поступивший на склад. Здесь же каждая пара кроссовок получает уникальный номер в виде штрихкода.
  • Размещение товара на локации. Склад состоит из многоярусных полок. Наша система сама находит свободное место для нового товара в той зоне, где находится сотрудник, и затем прокладывает путь на мобильном сканере. Работник берет коробку с кроссовками, сканирует ее и необходимую полку, чтобы «привязать» товар к конкретной локации.
  • Подбор и резервация товара для заказа. Пользователь выбрал модные кроссовки в честь «Черной Пятницы», после чего его заказ отобразился у нас в системе. Система находит конкретные товары на складе, бежит по списку и ищет ту самую пару обуви нужного размера, чтобы заблокировать её для других заказов. Одновременно покупками занимаются сотни людей, и мы не хотим, чтобы одна и та же вещь попала в разные заказы.
  • Физический поиск товаров на полках. Наша система генерирует для сотрудника инструкцию, где именно на складе находится нужная пара кроссовок. Он видит путь в своем мобильном сканере — последовательность шагов, где указано, что именно делать. Например, сначала подойти к нужной полке и отсканировать ее, затем взять коробку с кроссовками и отсканировать. Каждый скан логируется в системе.
  • Сортировка и упаковка посылок. Тележка с заказанными кроссовками отправляется на сортировку. Товар должен попасть в конкретную коробку, которую сотрудники упакуют и передадут в доставку. Каждый из этих шагов также сопровождается сканированием штрихкодов.



Мобильный сканер обладает такими характеристиками:

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

Что нас не устраивало в устройствах для склада




Для осуществления всего вышеперечисленного в распоряжение сотруднику выдается мобильные устройства на базе Windows Embedded CE 6.0 и Android со встроенным сканером штрихкодов. Серверная часть представлена в виде JSF 2.2 (JavaServer Faces) приложения, работающего в WildFly 10. Сам клиент — это открытый веб-браузер на устройстве.

Такое взаимодействие имеет следующие недостатки:

  • Sticky Sessions. Один из наиболее существенных недостатков JSF — его stateful-подход. Это означает, что состояние пользователя не отделено от сервера и хранится на нем. Такая неклассическая клиент-серверная архитектура — не тот результат, который мы хотели бы видеть.
  • Нет возможности осуществлять полноценный BG-deployment. При рестарте сервера приложений контекст JSF-бинов уничтожается. Вместе с ним уничтожается и накопленный стейт, включая данные сессий пользователей. Помимо сессий пользователей, мы также могли потерять состояние бизнес-процесса, в котором работал сотрудник. При написании кода и логики с этим приходилось считаться.
  • Работа в браузере. Клиент взаимодействует с сервером через браузер. Это значит, что пользователю доступна вся функциональность и возможности браузера. Сотрудники могут обновлять страницу, нажимать кнопки «назад–вперед», а некоторые даже умудрялись слушать музыку ВКонтакте из соседней вкладки. Сложность в том, чтобы не дать пользователю возможность остановить или поломать бизнес-процесс в результате случайно нажатой кнопки «назад».

Переход на Kotlin и Android-приложение: процесс и сложности




Однажды мы достигли точки невозврата и решили, что сейчас затраты на изменения кода будут явно меньше, чем затраты на его поддержку потом. К тому же, JSF сам по себе является «слегка» легаси. Это не та технология, от которой хотелось бы работать. По ней трудно найти специалистов, которые хотят ее развивать.

Так зародилась идея переезда. Мы сравнили популярные JavaScript фреймворки: React и Angular. Оказалось, что ни один из них не мог полностью решить наши проблемы. В итоге с учетом наших потребностей выбрали нативное приложение на Android и Kotlin.

Важно упомянуть, что каждый бизнес-процесс в проекте WMS представляется пользователю в виде нескольких диалоговых окон: некоторые из них исполняются в веб-приложении на десктопном компьютере, а некоторые — на мобильном устройстве. Например, разгрузка грузовика. Сначала системе необходимо сообщить, что в определенное время мы ожидаем приезд грузовика с некоторым количеством номенклатур. Эта часть исполняется сотрудниками через веб-клиент на десктопном компьютере. Но сканирование и опознание товаров происходит при помощи вышеупомянутого мобильного клиента.

Миграция мобильных диалогов из нескольких страничек происходила в несколько этапов: создание новых HTTP-эндпоинтов и написание клиентского кода на Android, затем тестирование и деплой в продакшен.

Но не обошлось без ложки дегтя: ранее мы работали только с веб, и теперь приходилось тщательнее следить за тем, что можем позволять пользователю, а что нет. Например, при смене Activity в терминологии Android мы часто забывали сфокусироваться на нужном инпуте, и сканирование штрихкода не работало, как нужно. Иногда даже сталкивались с утечками памяти из-за бесконтрольного поведения наших activity-объектов.

Чуть позже мы добавили мониторинг в New Relic. Он помог решать инциденты и сделал процесс более наглядным.

Со временем наша экспертиза в Kotlin увеличивалась: мы отказались от коллбэков в пользу более наглядного coroutine-подхода. Код стал выглядеть синхронно, а его объем уменьшился.

Что мы получили благодаря переходу


  • Полностью отделенный от сервера клиент: взаимодействие с бизнес-логикой теперь носит stateless-характер. Это открывает новые возможности для балансирования нагрузки между нодами.
  • Выборочное обновление клиентских устройств. Реальный кейс: выкатываем новую версию приложения на десяти устройствах и выборочно выдаем на тестирование складским сотрудникам.
  • Заменили браузер нативным Android-приложением. Исчезла возможность обновлять страницу, нажимать кнопки «вперед–назад». Поведение пользователя стало более детерминированным.
  • Стали использовать вибрацию и звуковое сопровождение на устройстве. Склад — шумное место. Когда пользователь совершает ошибку, он чаще всего не смотрит на экран. В такой момент наше устройство вибрирует и издает громкий звуковой сигнал.
  • Получили приложение, написанное на свежем языке, у которого мощная система типов, никакой JavaScript-магии. Kotlin комьюнити постоянно растет и развивается, язык не стоит на месте.

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

При этом внешний вид приложения никак не изменился. Для пользователя весь переезд прошел незаметно: никакой разницы в дизайне и в использовании. Все кнопки остались на тех же местах, у них такая же форма и такой же цвет.

Текущая архитектура WMS: к чему мы пришли


  • Монолитный Java EE (Enterprise Edition) сервер, который крутится в WildFly версии 10 и написан на Java 8.
  • Клиентская часть теперь состоит из мобильного приложения на Android 4.4 и веб-приложения для складских работников, написанное на Angular. Последнее нужно для запуска и оркестрирования процессов на складе. Типичный конечный пользователь — это старший сотрудник склада, который создает задание для подчиненных. Оно будет отображаться на Android-устройствах.
  • Устройства общаются с сервером по Rest API. В качестве хранилища выступает PostgreSQL 11.7. Недавно мы переехали с 9 версии и получили бонусом к общей производительности вменяемые hash-индексы. Также увеличилась скорость чтения из реплик. Реплики нам очень нужны: бизнес строит множество отчетов и рассчитывает производительность сотрудников на основе этих данных. Для общения с базой используем Hibernate 5.1.9.
  • Общение с соседними системами происходит посредством шины. Ее ядро — Apache Camel версии 2.16. В качестве источников данных мы используем Active MQ, Kafka и HTTP-эндпоинты.
  • Для мониторинга мы используем ELK-стек, Grafana, а также New Relic. Мы следим за системой в оба: мониторим трафик и производительность.

Вызовы и планы развития на 2021 год


Сейчас для WMS в Lamoda начинается новый технологический этап: впереди много аналитики, кода на Kotlin, новых фреймворков и подходов. Нам предстоит решить проблемы с распределенными транзакциями, балансированием нагрузки, авторизацией и оркестрированием.

Также у нас много планов по улучшению. Мы собираемся распилить наш Java EE монолит на набор сервисов с использованием Spring Boot 2. Там, где бизнес-логика попроще, будем использовать Kotlin, где посложнее — оставим или обновим версию Java до 11. Таким образом, мы существенно упростим разработку новых бизнес-процессов и облегчим поддержку старых.
Теги:
Хабы:
+6
Комментарии0

Публикации

Информация

Сайт
tech.lamoda.ru
Дата регистрации
Дата основания
Численность
5 001–10 000 человек
Местоположение
Россия