Это гостевой пост от Оскара Лече — разработчика из Нидерландов, который в настоящее время работает в Recharge.
Я создал для своего сына.
Языки давались ему непросто. А поскольку значительная часть ранней математики по сути завязана на языке — текстовые задачи, инструкции, лексика сравнения и последовательности, — его трудности с чтением перекинулись на предметы, которые на первый взгляд казались несвязанными. Мы перепробовали множество подходов дома. Когда я посмотрел на то, что предлагалось на рынке ПО, мне не понравилось то, что я нашел: подписки для ребенка, который может запустить приложение два раза, или бесплатные приложения с рекламой, нацеленной на шестилетних детей. Я не хотел подписываться ни на то, ни на другое.
Днем я работаю штатным инженером (Staff Engineer), я родом из Гуатемалы, а сейчас живу в небольшом городке недалеко от Амстердама. Потратив достаточное количество вечеров на попытки использовать чужие инструменты, я вернулся к тому, что умею делать лучше всего, и начал программировать.
Дизайн напрямую вытекал из его потребностей. Все озвучивается вслух, поэтому ребенок, который еще не умеет читать или читает медленно, может заниматься самостоятельно, не дожидаясь взрослого. Сложность подстраивается под продемонстрированные успехи, а не под возраст, потому что ребенок может опережать сверстников в одной области и отставать в другой, и его нельзя оценивать по дате рождения. Приложение работает на том языке, на котором действительно говорит семья: наше общение переключается между испанским, нидерландским и английским. Приложение стоит около евро при единовременной покупке, в нем нет рекламы и подписок, потому что ребенок, которому нужна дополнительная практика, не должен превращаться в источник регулярного дохода.
Я выложил его в App Store, чтобы его могли установить племянники и дети моих друзей. Затем его купили другие родители. Без какого-либо рекламного бюджета Samio поднялся на 2-е место в категории платных образовательных приложений в нидерландском App Store — родители находили его и рассказывали о нем другим родителям. Затем учителя начали спрашивать, нет ли версии для классов. Поэтому я создал и ее.
Я написал каждую строчку кода платформы самостоятельно, но Samio не является историей одного человека во всех смыслах. Моя жена Ольга — моя соучредительница. Она тестировала самые первые версии с нашими детьми и прямо говорила мне, что не работает, и многое из того, что изменилось между первыми итерациями и релизом, было создано благодаря ей. Она управляет брендом и социальными сетями Samio. Я занимаюсь разработкой.
Что такое Samio и почему оно нравится людям
Samio — это обучающее приложение для детей от 4 до 12 лет: обучение грамоте и чтение, математика от счета до дробей, правописание и грамматика, определение времени, естествознание, физика, логические головоломки и программирование. Дети помладше соединяют блоки, чтобы провести робота через головоломки. Дети постарше читают настоящий код на Python и JavaScript, чтобы решать кейсы.
Три вещи родители и учителя отмечают снова и снова.
Оно разговаривает. Каждое меню, инструкция и упражнение озвучиваются на родном языке ребенка. Именно это решение позволяет детям, еще не умеющим читать, играть самостоятельно, и именно о нем чаще всего упоминают родители.
Оно адаптируется под уровень навыков, а не под возраст. Дети проходят шестиэтапную программу в зависимости от своих реальных успехов, а не даты рождения.
Оно ничего от вас не требует. Одна покупка, никаких подписок, никакой рекламы, никаких покупок в приложении, и оно работает офлайн: в самолете, в машине или в классе с ненадежным Wi-Fi.
Приложение доступно на семи языках, каждый из которых сопровождается голосовыми подсказками. Вокруг него теперь выросла школьная платформа, где учителя управляют классами, назначают задания и отслеживают прогресс, работающая на той же кодовой базе. Именно здесь Expo перестает быть просто удобством и становится причиной существования всего этого проекта.
Почему я выбрал Expo
Честный ответ: потому что я один человек и я не нативный мобильный разработчик.
Мой бэкграунд — это full-stack веб. React, Node, MongoDB. Если бы для выпуска приложений под iOS и Android потребовались Swift и Kotlin, две кодовые базы и собственная инфраструктура сборки, Samio так и осталось бы проектом, который запускался на одном планшете в моей гостиной. Это не риторика. Это чистая правда. Я уверен, что многие из вас могут это понять.
Expo избавило меня от целого пласта работы, на которую у меня не было времени. Мне никогда не приходилось работать в Xcode. eas build создает бинарные файлы для профилей разработки, превью и продакшена, eas submit отправляет их на рассмотрение Apple и Google, а я возвращаюсь к написанию функций. Подпись, провижининг, сертификаты, сборочные машины — я обо всем этом не думаю.
Вторая причина становится еще более важной по мере роста продукта. Одна кодовая база, пять платформ. Детское приложение работает на iOS и Android. Панель управления учителя работает в браузере из той же кодовой базы React Native с помощью react-native-web. Для инди-разработчика, продающего ПО школам, это решающий фактор. В школах используют Chromebook, iPad и всё остальное, что есть в шкафу, и я могу поддерживать их все, не создавая отдельные продукты.
Как заставить одного человека работать как целая команда
Приложение работает на Expo SDK 55, React Native 0.83 и React 19. Поддержание рабочего приложения на актуальных версиях обычно является задачей целой команды. Благодаря системе обновлений Expo один человек вполне может с этим справляться.
Под этим капотом скрывается полноценная настройка CI и тестов, что звучит абсурдно для команды из одного человека и именно поэтому у меня она есть. Три сборочных профиля Expo (разработка, превью, продакшен), Expo Submit для обоих магазинов, Jest с jest-expo и Testing Library для юнит-тестов, а также сквозные сценарии (E2E) в Maestro, охватывающие как потребительское приложение, так и школьный продукт. TypeScript на всех уровнях. Тесты — это то, что позволяет мне быстро выпускать релизы, не ломая продукт, которым дети пользуются в классах.
И еще есть ежедневная рутина. Я написал два скрипта разработки, dev-ios.sh и dev-android.sh, которые сокращают задачу «запустить этот вариант на том устройстве» до одной команды. Оба скрипта учитывают варианты сборки. Они считывают имя приложения, слаг и идентификатор бандла прямо из app.config.js, поэтому команда --variant schools запускает приложение для учителей, а не детское, без каких-либо дополнительных изменений.
На Android скрипт сам определяет целевое устройство. Он выводит список доступных для adb устройств, отдает предпочтение физически подключенному телефону, а не запущенному эмулятору, поэтому подключение устройства сразу начинает работать, поддерживает бесстилевую отладку и автоматически настраивает adb reverse, чтобы Metro был доступен с реального телефона по USB. На iOS он запрашивает simctl и выбирает самый новый из доступных симуляторов iPhone, анализируя номера моделей и поколения, поэтому он продолжает работать по мере выхода нового оборудования от Xcode, а не ломается из-за жестко закодированного имени устройства.
У обоих есть путь быстрой разработки --no-build, который пропускает компиляцию и просто переустанавливает и перезапускает существующий бинарный файл. Именно этим я пользуюсь чаще всего, потому что при тестировании на реальном школьном оборудовании вы итерируете JavaScript гораздо чаще, чем прикасаетесь к нативному коду. Они также очищают кэши Gradle, которые незаметно скапливаются внутри node_modules — а это несколько гигабайт, если их не трогать.
В этом нет ничего гламурного. Но каждый из этих шагов был небольшим налогом, который я платил по несколько раз за вечер, и избавление от них — главная причина, почему человек с полной занятостью вообще смог это выпустить.
Релиз делается одной командой:
Это запускает expo prebuild --clean для нужного варианта, внедряет учетные данные Firebase из переменных среды в формате base64, чтобы в репозитории не хранилось ничего конфиденциального, считывает текущее состояние версии из Expo с помощью build:version:get, патчит Info.plist и build.gradle соответствующим образом, собирает локально с помощью eas build --local, отправляет через eas submit, а затем записывает инкрементированную версию обратно в блок нужного варианта в app.config.js, чтобы следующая сборка начиналась с правильного номера. По ходу дела скрипт очищает кэши Metro и Gradle.
Добиться этого было непросто. Плагин локальной сборки Expo иногда завершает работу с ненулевым кодом из-за проблемы с очисткой временной директории, даже когда артефакт в порядке, поэтому скрипт проверяет наличие выходного файла, а не полагается на код возврата. Но в результате отправка любого приложения в любой магазин сводится к одной строке, которую я могу запустить в 11 часов вечера, не задумываясь об этом. Для одного человека, поддерживающего четыре страницы в магазинах, это разница между релизами раз в месяц и релизами раз в неделю.
Пять платформ, одно место для исправления багов
Детское приложение и «Samio for Schools» публикуются как отдельные страницы в обоих магазинах, но это один и тот же репозиторий. Динамический app.config.js, привязанный к переключателю APP_VERSION, определяет слаг, идентификаторы бандлов, иконки, экраны-заставки и конфигурацию Firebase для каждого варианта с соответствующими профилями Expo Build для каждого из них. Панель учителя — это тот же кодовой базы через react-native-web.
Это детское приложение на iOS и Android, школьное приложение на iOS и Android, а также веб-панель. Пять платформ, одно место для исправления багов.
Ассеты — это единственное, за что я плачу в этом плане. Дети смотрят на эти экраны часами, поэтому иллюстрации и аудио хранятся в репозитории в полном качестве и сжимаются в процессе сборки, а не ухудшаются на источнике. Обратная сторона — тяжелый проект: более 300 иллюстраций ручной работы плюс записанный заранее голосовой звук на семи языках. Именно поэтому я перешел с облачных сборок Expo Build на eas build --local. Загрузка стала непрактичной, но сам конвейер не изменился вообще. Те же команды Expo, те же профили, тот же шаг отправки. Теперь он просто запускается на моем компьютере.
То, что действительно было сложно
Все, что описано выше, — это инфраструктура. Вот проблемы, над которыми я просидел реальные вечера.
Аудио-ориентированный дизайн. Голосовой слой использует expo-audio вместе с react-native-audio-api, с записанными заранее естественными голосами, а не системным TTS, поэтому произношение правильное на каждом языке. Поддержание синхронизации аудио, текста и взаимодействия на семи локалях и работа в автономном режиме были самой сложной задачей взаимодействия в приложении и тем, чем я горжусь больше всего.
Обводка букв с реальной обратной связью. Дети обводят буквы пальцем и получают проверку для каждой буквы и каждого штриха, поэтому приложение отличает правильно сформированную букву от фигуры, которая просто выглядит похоже. Создано на базе react-native-svg с использованием react-native-gesture-handler.
Студия рисования, которая ощущается как нативная. Creative Studio поддерживает сведение для зума, панорамирование и полный набор инструментов с использованием react-native-reanimated с ворклетами, а также react-native-view-shot, чтобы дети могли сохранять и делиться тем, что они создают.
Оффлайн-режим прежде всего. react-native-mmkv для быстрого локального сохранения и expo-file-system для асслетов, чтобы упражнения и модуль программирования работали вообще без подключения. Школы стали главным стимулом. Нельзя полагаться на школьный Wi-Fi.
Если вы единственный разработчик своего продукта
Я создал Samio в одиночку по вечерам, и теперь эти приложения используются в школах Нидерландов, США и Гватемалы. Десять лет назад для этого потребовалась бы целая команда. Инструментарий сейчас настолько хорош, что с Expo можно зайти очень далеко в одиночку.
Если у вас есть идея приложения и вы хотите донести его до магазинов, я думаю, вам стоит принять во внимание следующие три решения:
- Используйте единую кодовую базу для iOS, Android и веба с первого дня, а не переносите код позже.
- Поместите конвейер релизов в скрипт до того, как он вам понадобится, чтобы выпуск никогда не конкурировал со сборкой.
- Пишите сквозные тесты, даже будучи в одиночку. Именно они позволяют вам выпускать релизы среди недели.
Если вы начинаете что-то подобное, создайте аккаунт Expo и запустите свою первую сборку eas build. Это займет примерно столько же времени, сколько выпить чашку кофе. А если вы хотите посмотреть, во что превратился Samio, он доступен в App Store и Google Play.












