Привет! Меня зовут Максим, я руководитель мобильной разработки в KTS. Недавно я попросил рассказать об используемых технологиях бывшего коллегу Сеню Суздальницкого, CTO Sizl — стартапа доставки еды в Чикаго.
Получилось большое интервью, в котором мы обсудили:
почему между Flutter, React Native и нативной разработки для мобильных приложений он выбрал KMP
работу в «Рокетбанке» и «Кухне на районе»
нюансы запуска стартапа в США
доставку заказов силами основателей
вкусовые предпочтениях американцев
почему Android-разработчик делает бэкенд и DevOps
Работа до Sizl
KTS
Я приехал в Москву после учёбы в Красноярске.
Сначала работал в «Айтеко» и параллельно учил Android. Однажды прошёл интенсивный курс по Kotlin и понял, как много он привносит в андроидную жизнь.
Вскоре приятель позвал меня в KTS на должность Android-разработчика. Во время работы в компании я занимался приложением для технадзора строительной компании ПИК и несколькими другими небольшими проектами.
«Рокет-банк» и React Native
«Рокет-банк» был стартапом, основатели которого потом сделали «Кухню на районе». Когда я начал там работать, «Рокет» уже выкупили QIWI, и в целом это была уже совсем другая компания с другой командой. Хотя общая атмосфера сохранила молодёжный неформальный вайб кальянов и неоновых ламп.
Я работал в команде из 2 Android-разработчиков, 3 iOS-разработчиков и 5 разработчиков React Native.
React Native интегрировался с API на стороне iOS и Android, но не обеспечивал полную самодостаточность. Например, сложные перфомансные задачи вроде анимаций или отображения видео требовали нативной разработки.
По моему опыту, React Native — скорее инструмент унификации, чем супер-буст в скорости разработки. Скорость все равно зависит от личной эффективности каждого разработчика. К тому же из-за наличия трёх разных команд требовались постоянные проверки совместимости и взаимодействия между iOS, Android и React Native.
Было ощущение, что с двумя нативными мобильными командами вместо трёх скорость была бы примерно такой же, но тогда потерялась бы унификация между платформами. Получается, что вся польза от React Native — в унификации интерфейса и бизнес-логики, обеспечивая согласованность между платформами.
«Кухня на районе»: приложение для складов и курьеров
Когда я только устроился в «Кухню», там ещё была оригинальная команда «Рокет-банка». Я написал CTO и спросил, не ищут ли они мобильного разработчика в команду. Оказалось, что место есть.
У «Кухни» был backend на Ruby и нативные приложения для Android и iOS. Первое время ребята, как и в «Рокете», продолжали использовать React Native, потому что им казалось, что это классный инструмент. Но к моему приходу от него уже отказались из-за проблем с производительностью и необходимости поддерживать три разных команды.
Улучшение работы склада
Когда меня взяли на работу, то дали одну общую задачу — сделать работу склада лучше. Это было большое здание, внутри которого находилось производство и разные помещения хранения: холодные склады, склад упаковки, морозильные камеры.
Работники склада и курьеры пользовались одним софтом и разделялись по типу учётной записи. У курьеров была мобильная версия, а на складе работали с веб-сервисом.
Мне показали склад и познакомили с разработчиком, который писал бэкенд. После этого я сам решал, как именно улучшать складскую работу. Сначала я сделал мобильную версию внутреннего сервиса для работников склада.
Пользоваться веб-софтом на складе было неудобно. Сотрудники постоянно перемещались и сканировали бар-коды на физических товарах. А веб-приложение стояло на ПК в одном месте. Получалось, что сотрудник брал в руки Bluetooth-сканер и шёл сканировать коробки и ящики. Но чтобы понять, что именно он отсканировал, надо возвращаться к ПК и смотреть, что показывает веб-приложение.
Когда есть мобильное приложение, то в одной руке у вас сканер, а в другой телефон. Сотрудник, как быстрый ковбой на Диком Западе, сканирует ящик и сразу видит: это замороженная курица, которая поступила на склад 3 дня назад в объеме 20 кг. Теперь работники склада могли проводить все операции прямо с телефона — начиная от приёмки до выдачи сырья.
Внедрить приложение было просто: достаточно приехать на каждый склад и показать приложение начальнику. Начальник склада — человек умный, потому что тяжело управлять складом, если ты недостаточно разбираешься в деле. Так что я показал приложение ему, а потом он сам всё объяснил своим сотрудникам.
Улучшение работы курьеров
После этого я начал работать с той частью сервиса, которой пользовались райдеры-доставщики.
Я просто пытался всё сделать чуточку лучше. Например, часто курьер, доставив заказ на высотки, не может отметить заказ как «доставленный», потому что нет Интернета. Я внедрил отложенные отправки статусов доставок и улучшил трекинг локации райдеров.
Внедрить приложение для райдеров оказалось сложнее, чем на складе: если все склады находились в одном здании и у них был один начальник, то кухонь было 50 по всей Москве. Есть ответственный за все кухни. Есть ответственные за группы кухонь по районам. И есть ответственный за каждую кухню отдельно. На каждой из них могло быть много курьеров.
Если сотрудник склада в каком-то месте не понимал работу приложения, он мог подойти к начальнику, которому до этого всё объяснил я. Но в курьерской части просто невозможно всё объяснить каждому курьеру отдельно. Поэтому райдеров нужно приравнивать к внешним пользователям, которые скачали приложение и хотят сразу понять, как что работает. Поэтому часть для доставщиков я хотел сделать максимально понятной и красивой и ориентировался на дизайн-подходы «Рокета».
В «Кухне» работала одна поддержка для клиентов и для курьеров. Если райдер попадает в ситуацию, когда не открывается дверь или что-то ещё, он звонит в поддержку, и они решают эту проблему. Я договорился с одной из сотрудниц, и при добавлении новой версии приложения она оповещала об этом курьеров. А от них требовалось зайти в Play Store и обновиться. Иногда бывали небольшие проблемы, но благодаря качественной работе QA всё проходило хорошо.
У меня вообще было много свободы в «Кухне». Не нужно было ни за кем ходить и отчитываться. Однажды я рассказал директору, что у нас будет новое приложение для доставщиков, а он ответил: «Круто!»
Sizl — что это такое и зачем
Sizl придумали несколько ребят из тех, которые сделали «Кухню».
Если у «Кухни» была концепция домашней еды, то в Sizl такого нет. Мы готовим и доставляем Real food — это не фаст-фуд, но и не гурманский ресторан. Качество еды лучше, чем если бы её приготовил дома среднестатический человек, и готовится она из хороших, всегда свежих продуктов.
Но мы хотим быть не просто историей про доставку, а внести в бытовые процессы приобретения еды более завлекающие вещи. Сейчас мы работаем над игровыми механиками с уже продуманными персонажами и лор.
В планах внедрение геймификации в разные взаимодействия, чтобы сделать заказ еды более увлекательным. В основе идеи геймификации — понятная механика в стиле тамагочи. И у нас есть ощущение, что это должно хорошо сработать.
Как запускались
Мы запускались очень постепенно, разделив всё по этапам.
Запуск в агрегаторах. В первые пару дней мы запустились в агрегаторе и заказывали сами у себя. Этому есть сразу причины:
После релиза хочется увидеть, как всё будет работать: что клиент может сделать заказ, а линейный персонал на кухне его увидит, соберёт и доставит
Догфудинг — практика использования сотрудниками компании собственных продуктов и сервисов. Потому что ты — свой самый лояльный клиент. Это нормально: заказать еду у себя, как все остальные клиенты
У агрегаторов сложная и никому не понятная система ранжирования. Есть ощущение, что если в ресторане не делают заказы, агрегаторы не показывают его вообще. Поэтому нам показалось важным первое время поднимать активность самим
Подключение промоушена в агрегаторах. Для этого нужно выбрать разные поддерживаемые агрегатором акции, например: «Закажи два, получи третье в подарок». Мы начали пробовать разные комбинации, заказов стало больше.
Запуск в приложении проходил по той же схеме: сначала заказывали сами, потом конвертировали людей из агрегаторов в пользователей приложения.
Сейчас мы полноценно доступны у трёх агрегаторов и в нашем приложении.
Как доставляли заказы и дежурили на кухне
Когда мы только запустились, у нас не было райдеров.
Мы ожидали, что заказов за день сначала будет немного, поэтому не хотелось тратить деньги на курьера, который будет сидеть фуллтайм на кухне и ничего не делать. Из-за этого на кухне должен был всегда находиться ещё один человек кроме повара. Этот человек должен был способен доставить заказ и решить какой-нибудь вопрос, потому что на запуске на кухне много чего происходило: например, нужно съездить к поставщику и докупить какой-то ингредиент.
Сейчас у нас несколько поваров и курьеров, но некоторые ребята из операционной команды всё ещё выезжают на кухню. Я тоже выезжаю, но уже не на дежурства, а для какой-то специфичной работы: поменять жёсткий диск в системе видеонаблюдения или посмотреть, как дела с апдейтом приложения для райдеров.
Почему доставляем заказы на велосипедах
Каждая кухня обслуживает один район, в пределах которого можно доставить заказ за 30 минут.
Мы всегда доставляем заказ на велосипедах, кроме исключительных случаев. В этом наше преимущество по сравнению с другими доставками, потому что не приходится стоять в пробках и искать парковку. В Штатах в большинстве домохозяйств есть автомобили. В обычное буднее время дороги всё время перегружены, и на велосипеде получается быстро доставить заказ.
Если на улице жуткая непогода, мы можем привезти заказ на машине — но это скорее исключение, чем правило.
Какую еду готовим и почему
Вообще если можно говорить о дурном вкусе в еде, то американская кухня, безусловно, является выражением дурного, вздорного и эксцентрического вкуса, вызвавшего на свет такие ублюдки, как сладкие соленые огурцы, бэкон, зажаренный до крепости фанеры, или ослепляющий белизной и совершенно безвкусный (нет, имеющий вкус ваты!) хлеб.
И. Ильф, Е. Петров, «Одноэтажная Америка», 1935г.
Уже по ходу работы мы выяснили две вещи.
Во-первых, в целом в Америке посредственная еда. И в доставке, и в ресторанах — еда проигрывает той еде, которая в России. Если верить писателям-соотечественникам, которые были здесь 90 лет назад — за это время как будто ничего не поменялось.
Во-вторых, среднему американцу вполне себе заходят русские блюда: борщик, шаурма, сырники. Мы сначала боялись, что американцы не поймут в меню таких позиций и не будут их заказывать.
У нас нет фокуса на какой-то специфичной кухне. Поэтому рядом с борщом у нас в меню есть и чизбургер, и хот-дог. Сейчас мы думаем добавить какие-то азиатские направления, вроде роллов и воков.
Про плюсы хед-офиса в общем доме
Мы живём все вместе в пятиспаленном пентхаусе. В этом есть и плюсы и минусы.
Удобно решать задачи. Когда вы все вместе, можно сесть и быстро решить любой вопрос: планировать, договариваться. Не нужно созваниваться и списываться.
Это бывает удобно и для прямой деятельности компании. Несколько раз были ситуации, когда на кухню одновременно прилетало 5-6 заказов одновременно, а там только один курьер. В таких ситуациях мы просто садились в две машины, доезжали до кухни и сами доставляли заказы.
Или иногда на склад приходит доставка от поставщика упаковки, а складских сотрудников у нас нет. Можно быстро решить эту задачу вместе: поехать, забрать, привезти, увезти. Это не sustainable-стратегия, но сейчас это выгодно.
Про понимание боли курьеров
То, что все мы поработали райдерами, очень хороший плюс.
Мне кажется, что в разработке у многих людей, особенно в больших корпорациях, есть разрыв между тем, что ты делаешь, и непосредственной деятельностью компании. Например, разработчик сидит, делает софт для курьеров, но не знает их боли и вообще не понимает, существуют ли они. А мы все знаем.
Sizl — почему выбрали KMP, а не Flutter, React Native или нативную разработку
Почему выбрали KMP, а не Flutter или React Native
Изначально я вообще не рассматривал вариант кроссплатформенных подходов, потому что не видел в этом никакой выгоды.
React Native я не брал на рассмотрение по нескольким причинам:
Со времён работы в «Рокете» мне запомнилось, что для React Native нужно нанимать 3 команды — а это затратно и нецелесообразно, потому что результат себя не оправдывает
RN мне представляется бесперспективным инструментом с тех пор, как от него отказались в Airbnb
Flutter не привлекает меня из-за отсутствия нативных интерфейсов: весь UI в Flutter — это UI Flutter.
Например, я хочу, чтобы пружинистый скролл на iOS работал как пружинистый скролл на iOS, а на Android как на Android. Поведение интерфейса во Flutter для меня всегда было блокером к его использованию.
KMP мне тоже сначала не нравился, потому что раньше управление памятью в Kotlin/Native (iOS) работало не так, в Kotlin/JVM (Android). Это было связано с особенностями native-рантайма — например, нужно было в явном виде указывать, в какие места памяти будет асинхронный доступ. Мне всё это совершенно не нравилось, но скоро эту проблему решили.
Поэтому в начале я выбрал нативную разработку. Кодил на Android и планировал нанять в команду iOS-разработчика. В какой-то момент в Android-части я столкнулся с проблемой задержки в обработке действий.
Я хотел, чтобы пользователь мгновенно видел результат каждого действия в приложении. Например, когда добавляет товар в корзину, можно было показать результат: товар лежит в корзине. Но для подтверждения изменений нужно было обращаться к серверу. Мне не нравилось заставлять пользователя ждать ответа сервера, лучше показывать результат сразу локально, отправляя запрос на сервер после.
Мой план был в том, что — скорее всего — при добавлении товара в корзину всё пройдёт гладко. Поэтому я сразу же показывал результат пользователю. А если что-то пошло не так, сервер все равно выдаст актуальную информацию, и локальное отображение скорректируется — приложение покажет корзину без борща и скажет пользователю: «Блин, борщ закончился».
Сделать это на Android было сложно, и когда я закончил, показалось явно неудобным сидеть и кодить такую же штуку на iOS.
Примерно в то же время происходили ещё две вещи.
Во-первых, в KMP обновили memory manager. Всё упростилось, и разработка стала более схожей с обычной Kotlin-разработкой.
Во-вторых, я смотрел на работу Telegram. Там уже была библиотека tdlib, на которой сделаны все клиенты. Мне показалось интересным то, что клиенты Telegram — в основном фронтенды для этой библиотеки. Я подумал: «А что, если сделать такой же бэкенд для фронтендов на KMP?»
Эти моменты совпали с тем, что я не хотел дублировать сложную логику на iOS и подтолкнули к тому, чтобы начать использовать KMP.
Разница в работе KMP по сравнению с нативной разработкой
Работа с KMP требует единоразовых усилий на начальной настройке, после чего процесс разработки становится более гладким и предсказуемым.
Android-часть уже была.
В iOS-части нужно было решить несколько задач раз и навсегда. Например, сделать механизм подписки на события из платформенной части, выбрать решение для BigDecimal и UUID, потому что их нет в КМП. После этого у меня лично не возникало ситуаций, чтобы каждая фича потребовала больше времени, чем если бы я писал ее на нативной платформе. Пришлось провести некоторое время, разбираясь в деталях, потому что документации 1,5 года назад не хватало. Сейчас такой проблемы нет.
Если бы мы выбрали нативную разработку, каждая условная задача на создание экрана или фичи была бы разделена на четыре:
интерфейсы для iOS
интерфейсы для Android
логика для iOS
логика для Android
Время на задачу по логике на KMP сопоставимо со временем на эту же задачу на нативном iOS.
Какие сложности были 1,5 года назад с KMP-библиотеками
Работа с KMP, в общем, достаточно безболезненна, но есть и сложности.
1,5 года назад, если была нужна библиотека, которая не является частью KMP, нужно было либо писать свою обёртку, либо использовать существующее решение с GitHub, которое может быть не совсем актуальным. Например, при работе с BigDecimal-значением я нашёл решение для iOS и Android, но KMP-версия была довольно устаревшей и с некоторыми багами.
За последнее время количество библиотек выросло в два раза:
Также для узких нишевых библиотек, например SignalR, KMP-версии нет. В этом случае выбор между использованием голых вебсокетов и написанием нативной реализации может зависеть от конкретных потребностей проекта и сложности работы с библиотекой. В случае с SignalR я открыл доку и один раз накодил библиотеку. Ну как библиотеку — реализовал те кусочки, которые мне были нужны.
При этом не было ситуаций, когда один раз написанная общая часть оказывалась неприменимой к другой платформе. Поэтому работа с KMP требует единоразовых усилий на начальной настройке, после чего процесс разработки становится более гладким и предсказуемым.
Что в приложении Sizl выносят в общую KMP-часть
Мы шарим почти весь код логики приложения: управление состоянием, сетевые запросы, хранение локальных данных.
Некоторые компоненты, такие как платежи, пуш-уведомления и UI, специфичны для каждой платформы. Логика навигации частично переиспользуется, но реализация переходов тоже остаётся на платформенном уровне.
Как из Андроидера стал ещё и Иосером
В начале я хотел нанять iOS-разработчика, потому что думал, что придётся отдельно писать два нативных приложения. Но я всё время откладывал этот момент, потому что ещё со времён работы в KTS помнил, как тяжело было найти иосера. Их почему-то вообще не было на рынке. Не знаю, наверное, рынок сейчас изменился, но мои флешбеки из прошлого до сих пор живы.
Когда я перешёл на кроссплатформенную разработку, то решил — ладно, сделаю core, а потом найду человека чисто на интерфейсы, на фронтенд. А потом подумал, что можно и фронтенд самому написать. Подходы к вёрстке очень похожи с учётом использования Compose на Android и Swift UI на iOS.
В общем, так никого и не нанял.
Заключение: в чём сила и будущее?
В чем сила, не знаю.
О будущей цели думать сложно, могу сказать только о настоящем. Сейчас получается так, что я пишу и на iOS, и на Android, что-то на бэкенде, что-то на DevOps. Эта T-шейперская штука, и она как будто бы реально работает. На практике это очень удобно.
Сейчас я задумываюсь о том, что было бы, если бы я, наоборот, сконцентрировался на чём-то одном? Если бы я остановился на Android, я бы мог назвать себя Adnroid-экспертом с 10 годами опыта в этой области. Но я, конечно, объективно не могу этого сделать. Пока я для себя ещё не понял, хорошо это или плохо.
Заключительное слово от KTS
В конце хочется сказать про Sizl в целом.
Успешный запуск стартапа невозможен без высокого уровня самостоятельности и ответственности каждого из её участников. Хотя формально в команде нет руководителей, но этого и не требуется.
Любой из команды может взять под контроль горящую задачу, решить её сам или найти исполнителя. Но главное, что каждый нацелен именно на рост, развитие, а не просто решает проблемы.
Желаем Sizl скорейшего расширения и ждём новостей о новых успехах!