Мы создали агентные рабочие процессы, чтобы параллельно выполнять задачи мобильной разработки, но быстро упёрлись в ограничения наших рабочих машин. Всего три-четыре таких процесса уже могли полностью загрузить ноутбук: компиляторы, симуляторы и эмуляторы начинали конкурировать за ресурсы. Кроме того, ноутбук приходилось постоянно держать включённым. Если кто-то случайно закрывал крышку, работа прекращалась.
Наши web- и backend-команды уже использовали River — нашего ИИ-агента в Slack — чтобы работать, не занимая собственные компьютеры. Нам было нужно то же самое для мобайл. Но River работал на Linux: он мог редактировать Swift-код, однако для сборки и тестирования iOS-приложения всё равно приходилось возвращаться к тем же ноутбукам, которые уже были перегружены.
Наша способность делегировать работу выросла быстрее, чем способность её выполнять. Поэтому мы создали Remote Dev.
Два ограничения: слишком много сборок на одном Mac или отсутствие iOS-инструментов в Linux
Что мы создали
Несколько агентов, несколько задач
С Remote Dev мы больше не ограничены количеством сборок и симуляторов, которые способны выдержать наши ноутбуки. Каждая сессия River получает собственное окружение, поэтому один агент может отлаживать что-то на Android, второй — работать над iOS-функцией, а третий — тестировать PR, и всё это одновременно.
А поскольку всё запускается удалённо, мы можем стартовать отдельную задачу в каждом доступном окружении прямо из Slack, вообще не запуская локально Xcode или Android Studio.
Работает в фоне
Одно из главных преимуществ Remote Dev — то, какую часть процесса разработки River способен выполнять самостоятельно. Он может внести изменения, собрать приложение, запустить тесты, взаимодействовать с симуляторами, собрать скриншоты и создать PR. Если что-то ломается, он может изучить логи, исправить проблему и попробовать снова — пока мы занимаемся другими задачами.
Мы можем делегировать такие вещи, как rebase веток, разрешение merge-конфликтов, проверка падений CI, обработка замечаний в PR, разбор входящих crash-репортов и code review. Все эти небольшие задачи, которые раньше постоянно отвлекали нас в течение дня, теперь может выполнять River.
Мы можем пойти ещё дальше — использовать автоматизированные рабочие процессы, которые запускаются без ручного старта. Некоторые из них работают ночью: автоматически подхватывают баги, реализуют исправления, тестируют их и создают PR. Поэтому утром мы можем прийти к уже готовым исправлениям, ожидающим ревью.
Он доказывает, что действительно работает
Одна из самых больших проблем с кодом, созданным ИИ, — понять, работает ли он на самом деле. То, что код компилируется, ещё не означает, что функция ведёт себя ожидаемо. С Remote Dev мы можем пойти дальше обычных сборок и тестов. Агенты могут перемещаться по приложению, взаимодействовать с элементами и делать скриншоты или записи результата как на iOS, так и на Android.
При исправлении бага River может сначала воспроизвести проблему и записать неправильное поведение, затем внести исправление и повторить те же шаги, чтобы показать результат до и после. Это значительно упрощает обзор изменений. Вместо того чтобы смотреть только на код, мы можем увидеть, что именно изменилось, и проверить результат.
Недавно мы пошли ещё дальше. Мы добавили River возможность автоматически создавать объясняющие видео из этих записей, показывая приложение внутри 3D-моделей телефонов, с анимациями и озвучкой. Всё это генерируется автоматически, без ручного монтажа. Теперь River может не только реализовать исправление и проверить его, но ещё и создать видео, объясняющее, что именно он сделал. Довольно круто.
Теперь любой может участвовать в мобильной разработке
Одна из вещей, которая радует нас больше всего, — возможность сделать мобильную разработку доступной людям, у которых вообще не настроено mobile-окружение.
С River и Remote Dev web-разработчик может исправить баг, дизайнер — поработать над UI, а PM — протестировать функцию, и всё это через Slack.
Но всё ещё не хватало одной вещи. River мог взаимодействовать с приложением и отправлять скриншоты, но что, если вы хотите попробовать его сами? Поэтому мы создали Live Preview.
Мы транслируем iOS Simulator и Android Emulator напрямую из Remote Dev-окружения River на веб-сайт Quick через WebSockets. Браузер показывает живую трансляцию устройства и отправляет взаимодействия обратно на удалённый симулятор или эмулятор, поэтому любой может открыть ссылку и в реальном времени пользоваться настоящим запущенным приложением.
Каждая сессия Remote Dev автоматически получает собственный Live Preview для обеих платформ. Сессиями можно делиться, поэтому несколько человек могут одновременно смотреть и совместно работать с одним запущенным приложением. Мы также добавили поддержку глубоких ссылок и живую трансляцию mobile CLI, чтобы было проще переходить сразу к нужным экранам и видеть, что происходит внутри.
Никакой локальной настройки, никаких сборок для установки, даже Mac не нужен.
Это открывает мобильную разработку для гораздо большего числа людей. Вместо пересылки скриншотов туда-сюда можно просто отправить ссылку и сказать: «Попробуй сам!»
Как мы это сделали
Мы развернули парк удалённых Mac с нашим окружением разработки и iOS-симуляторами. Агенты подключаются к этим машинам по SSH, но с Android всё оказалось сложнее. Android Emulator использует аппаратную виртуализацию, поэтому его запуск внутри облачной VM требует вложенной виртуализации, которую macOS не поддерживает из коробки. Мы обошли это ограничение, подключившись к Android-эмулятору, который работает на отдельной Linux VM с включённой nested virtualization. При такой схеме агенты могут собирать и iOS-, и Android-версии на Mac, а тестировать обе платформы в рамках одной SSH-сессии.
Каждый агент получает готовый Mac с подключённым Android-эмулятором. После использования мы заменяем Mac, а простаивающие машины периодически обновляем.
Затем мы занялись сокращением времени на подготовку среды. Первичная компиляция приложения и checkout основной ветки занимали о-о-о-очень долго — больше 30 минут. Поэтому вместо подготовки Mac после поступления запроса мы перешли к пулу заранее прогретых машин: основная ветка уже checkout-нута — что само по себе непросто, потому что наш monorepo огромен, — инструменты установлены, приложения собраны, кэши прогреты. Агент получает Mac, синхронизирует свою ветку и запускает заранее подготовленный экземпляр Android VM для подключения. Агент продолжает работать в собственном чекауте, локальном или облачном, и синхронизирует изменения с Mac. Все скрипты и сборки затем выполняются уже на Mac. Благодаря этому время от запроса Mac до проверки изменений в коде на запущенном устройстве сократилось до нескольких минут.
Пришлось также построить немало фоновой инфраструктуры для управления этим пулом. Когда сессия заканчивается, мы уничтожаем Mac и готовим замену. Мы также периодически заменяем простаивающие Mac, подтягивая свежий main и заново собирая приложения и кэши. Ротация выполняется поэтапно, чтобы пул оставался доступным и не прерывал активные сессии.
Инфраструктура уже работала, но River всё ещё её «не видел». Он продолжал утверждать, что iOS-сборку нельзя запускать на Linux, поэтому мог писать код, но не мог проверить результат. Тогда мы создали навык, который научил агентов тестировать свои изменения и подтверждать свою работу. Понадобилось несколько итераций, прежде чем симбиоз двух машин стал действительно бесшовным. Изначально River продолжал забывать об удалённом Mac, замолкал во время взаимодействия с ним или слишком долго не возвращался к пользователю.
Итерация за итерацией мы улучшали навык и одновременно добавляли нужные инструменты: CLI, который скрывает сложность SSH-флагов. А вместо sleep и таймаутов в ожидании завершения длительных задач на Mac мы использовали панели tmux, за которыми River мог наблюдать в реальном времени.
Как мы помогали людям начать этим пользоваться
Меняем то, как мобильные разработчики работают сегодня
Несмотря на ограничения наших ноутбуков, команды привыкли разрабатывать мобильные приложения локально: взаимодействовать с настоящим симулятором, собирать приложение и тестировать его самостоятельно. Это было не только неэффективно из-за ограничений ноутбуков, но и плохо масштабировалось для большой миграционной задачи, которая стояла перед нами. Перевести людей на River оказалось не только технической, но и психологической задачей. Нужно было изменить привычку.
Некоторые уже пробовали ранние версии River, и опыт был далеко не идеальным: сборки не работали, всё было слишком медленно и мало подходило для повседневной работы. «Это не для меня, вернусь к локальной разработке» — примерно так люди и думали. Нам нужно было сделать River достаточно хорошим, чтобы люди начали пользоваться им всё чаще.
Но, как мы все знаем, одного принципа «построй — и они придут» недостаточно. Даже внутри компании. Нужно показать людям инструмент. Нужно постоянно рассказывать, насколько он стал хорош. И повторять это снова и снова. Поэтому мы использовали сторителлинг и внутреннюю рекламу, чтобы донести до людей, что River теперь действительно хорошо работает с мобайлом.
Нам пришла идея превратить River в реального персонажа, который мучается с мобильной разработкой, чтобы люди могли узнать в этом себя. А затем этот реальный River получает дома настоящий Mac, после чего может собирать mobile-приложения — и внезапно все его проблемы решаются. Люди не видят всей сложности решения, которую мы описываем в этой статье, — они просто видят, что теперь всё работает как по волшебству. После появления персонажа River следующие внутренние кампании стало делать проще. Вот один из примеров — разумеется, полностью созданный ИИ — пародия на рекламу Mac vs PC. Это добавило не только storytelling и юмор, но и немного ностальгии для тех, кто видел оригинальную рекламу.
В итоге использование River выросло. Сначала River создавал всего 6% объединённых мобильных pull requests. Со временем показатель изменился настолько, что тенденция локальной разработки развернулась, и доля River выросла до 61% всех объединённых мобильных pull requests.
Публичная работа, multiplayer и циклы самоулучшения
Одно из главных преимуществ River — мультиплеерность по умолчанию. Ранее в этом году Тоби рассказывал, как это уже меняет культуру Shopify и позволяет людям учиться на том, как другие используют агентов.
В нашем случае мы использовали мультиплеер не только для изучения того, как другие работают с River в мобайл-разработке, но и для улучшения будущих сессий. Мы можем видеть, где люди застревают, где инструкции ведут не туда, где доступ к инструментам отклоняется. Всё это.
Для этого мы использовали Jev — очень быструю и очень дешёвую модель-классификатор. Она наблюдает за всеми мобайл-разговорами River, размечает их по нескольким вопросам и анализирует каждое сообщение. Мы классифицируем каждый разговор по качеству результата, а неудачные случаи используем как входные данные для LLM, чтобы находить способы улучшения.
Мы запускаем этот процесс итеративно, используя самого River, поэтому River помогает улучшать себя для будущих задач.
Это только начало
То, что начиналось как способ предоставить River доступ к окружению мобильной разработки, открыло гораздо больше возможностей, чем мы ожидали. Теперь мы не просто ускоряем мобайл-разработку — мы меняем то, кто может участвовать в ней, как мы сотрудничаем и сколько работы можем делегировать агентам.
И мы по-прежнему каждый день находим новые возможности. Мы добавляем рабочие процессы, которые в реальном времени следят за состоянием наших приложений, а ИИ-агенты автоматически создают PR для исправления crash-проблем, готовые к быстрой проверке. Мы также используем несколько агентов для параллельного bug bash приложения, моделируя разных продавцов на разных устройствах, языках и пользовательских сценариях, чтобы находить проблемы, которые иначе могли бы пропустить.
Это лишь несколько примеров того, что мы сейчас исследуем. Каждая новая возможность открывает ещё больше направлений. Это только начало.

