Як я розробив ElectricityOff — застосунок для моніторингу вимкнень світла
Мене звати Зореслав Гораль. Я є Front-end розробником програмного забезпечення з досвідом більше 10 років. Працював на проєктах в різних доменах та з технологіями, починаючи від нативного JS і закінчуючи всіма можливими фреймворками. Також викладав курси зі спеціальності React в IT Cluster Academy.
З початком повномаштабної війни був мобілізований і через півтора роки знову повернувся до написання коду. Перед самим написанням коду закінчив навчальну програму в University of California, Berkeley за темою Entrepreneurship and Innovation is a Data-Driven World.
Там ми з командою створювали прототип проєкту, проходили всі кроки від ідеї до втілення. Це надихнуло, дало інструменти та змістило фокус з «розробницького» на «бізнесовий». Тобто під час створення аплікації я думав більше зі сторони СЕО та користувача продукту, а не зі сторони розробника, який постійно прагне покращити або й навіть переписати кодову базу з нуля.
Під час розробки продукту виникла ідея написати статтю (і так збіглося, що мені запропонували зробити це). Стаття вийшла в розповідному стилі, не перенасичена технічними деталями, тому вона буде цікава всім — як розробникам застосунків, так і користувачам. А можливо стане натхненням для тих, хто планує створити свій продукт, але ще цього не зробив з тих чи інших причин.
Як все почалося
Минулорічні вимкнення електроенергії мене майже не застали. Спочатку я користувався сайтом Прикарпаттяобленерго, вайбер чат-ботом Прикарпаттяобленерго та цим сайтом.
Наявні варіанти не дуже влаштовували. Хотілось такого рішення, щоб глянув на екран мобільного і одразу все стало зрозуміло: коли вимкнення, яка тривалість вимкнень, через скільки часу. І щоб це можна було зробити одною рукою десь в дорозі, щоб не потрібно було звірятися з годинником.
Так і виникла ідея аплікації. Велосипед вигадувати було не потрібно — на кожному девайсі є застосунок «Календар». Дизайн календаря був взятий за основу відображення головної сторінки застосунку.
Дослідивши сайт АТ Прикарпаттяобленерго, я побачив, що вони використовують АРІ. І перше, що я зробив, — створив простеньку HTML-сторінку, що брала дані з АРІ постачальника та відображала вимкнення у вигляді подій календаря. І тут виникла ідея: а чому б не потренуватися і не зробити мобільну аплікацію, використовуючи React Native? З вибором технології я недовго думав, оскільки є Front-еnd розробником з нахилом до React.
За основу взяв Ignite React Native boilerplate. Сподобалось, як в них організована структура проєкту; те, що вони використовують Expo; і в принципі там було все, що мені було потрібно для початку роботи.
Перша версія
Такий вигляд мала перша версія аплікації. Було три екрани: графік, вибір черг(и) та інформація.
Під час першого запуску аплікація запитувала в користувача чергу(и), записувала їх в локальне сховище та, безпосередньо використовуючи АРІ постачальника, рендерила графіки вимкнень щодо тих черг, які вибрав користувач.
Я хотів зробити все максимально зручно і зрозуміло, не спамити користувача чергами, що йому не цікаві. Щоб оновити дані, необхідно було натиснути кнопку «Оновити дані» або потягнути екран донизу та відпустити.
Старався, щоб всі жести та контроли були максимально дефолтними щодо операційної системи і зрозумілими користувачеві.
Після публікації в TestFlight вирішив поділитися аплікацією в LinkedIn. Вибрав LinkedIn, тому що тут в мене найбільш технічно грамотна бульбашка та сподівався отримати конструктивні відгуки.
У випадку з Facebook — підозрював, що це міг би бути The Mom Test. Пост набрав дуже багато реакцій, відгуків та коментарів. Людям було зручно користуватися застосунком.
На прохання користувачів Android локально збілдив apk і розповсюджував аплікацію за допомогою файлу.
Підготовка перед виходом в продакшн
У коментарях та в приватних повідомленнях люди запитували, коли аплікація буде доступна в маркетах. Але викладати аплікацію такою, як вона є, я не хотів. Була слабка ланка — пряма взаємодія аплікації з АРІ постачальника. У разі будь-якої зміни структури даних, аплікація перестала б працювати. А негативний досвід — гірше за 100 позитивних. Тому я склав дорожню карту, щось на кшталт:
- створити проксі-сервер для взаємодії з АРІ постачальника(ів);
- виправити зауваження та помилки;
- тиждень публічного бета-тестування;
- публікація в маркетах.
Архітектура першої версії застосунку.
Архітектура, яку я хотів зробити перед виходом в маркети.
Створення проксі-АРІ зайняло набагато більше часу, ніж я очікував. Спочатку я використав Vercel і швидко написав простенький Node.js Express сервер. Проблема з’явилась після публікації АРІ.
Справа в тому, що АРІ постачальника використовувало Cloudflare і було доступне тільки з України, а Vercel хостив аплікації не на українських серверах. Тому коли аплікація напряму комунікувала з АРІ провайдера, то в користувачів з України проблем не виникало; а у випадку з проміжним сервером — це виглядало як виклик АРІ з-за кордону.
Ще деякий час я витратив, щоб знайти рішення. Було основних два варіанти — знайти якийсь проксі-інструмент або український хостинг. Використав другий варіант — знайшов український хостинг з підтримкою NodeJs. Правда і тут довелося помучитись, оскільки у них ще cPanel, і нормально розгорнути NodeJs аплікацію з TypeScript не вдалося.
Довелось переписувати майже на чистому JavaScript. Також Proxy API повертала список постачальників та черг (що на початку були просто захардкоджені), щоб у майбутньому можна було підімкнути інших постачальників, окрім АТ Прикарпаттяобленерго.
Усі труднощі було подолано й аплікація опублікована в TestFlight. Тепер лишалося трохи почекати, і можна було б виходити в App Store та Play Market. Я мав проміжне Proxy API і вже не боявся, що зміни на стороні постачальника все поламають. У разі чого я б міг швидко все виправити на рівні Proxy API, і це ніяк би не зачепило користувачів.
Команда
Десь приблизно в цей час до мене в LinkedIn постукався Максим Дуда. Макс — дизайнер користувацького досвіду (UI/UX designer). Ми раніше працювали разом і були знайомі. Він запитав, чи в мене є Figma, де я беру іконки, і десь зник на пару днів. Я навіть не зрозумів, що він хотів на той момент.
За пару днів Макс з’явився і надіслав посилання на дизайн у Figma. Ми щось обговорили онлайн і домовились про офлайн-зустріч. На офлайн-зустрічі зійшлись на основних моментах щодо розвитку аплікації, як-от: зручність користування, доступність для старших людей, максимальне використання нативних контролів, мінімум або й відсутність налаштувань, відсутність зайвих кліків чи показу того, що не цікаво користувачу, аби не тубувати і не дратувати його.
Дизайн
Співпраця з Максом була дуже продуктивна. Він змінював флов, пояснюючи, чому так, скорочував тексти (бо люди не люблять читати довгі тексти), адаптував кольори, змінював іконки.
Ми відмовились від інлайн-повідломлень на кшалт «на сьогодні більше немає вимкнень», переробили екран вибору черги на модалку, змінили кнопку з надписом «вибрати чергу» на іконку, додали допоміжні тултіпи.
На деякі пропозиції я погоджувався швидко, на інші — тільки після аргументації. Ми постійно щось забирали — зайвий екран, зайву кнопку, зайве повідомлення, спрощували, скорочували та переписували тексти. Звертали увагу на всі «дрібниці», як-от автоматичний скрол до відмітки поточного часу, deep-linking в push-сповіщеннях.
У першому редизайні аплікація перестає бути схожею на демо-аплікацію Ignite boilerplate.
Сценарії
Оскільки активність моїх постів в LinkedIn була високою, згідно з принципами Design Thinking я вирішив зібрати сценарії використання аплікації. Але саме сценарії, а не поради, як зробити і яку фічу додати. Були сценарії, що дуже надихали, наприклад:
Я поставлю татові аплікацію, бо він перед виходом на вулицю телефонує мені і питає, чи можна користуватися ліфтом. Також дізнався, що люди, які емігрували за кордон, теж поставили собі аплікацію, щоб знати, коли можна телефонувати родичам в Україну. Або ж побратим, котрий служить, стежить за своєю чергою і чергою своєї сім’ї.
Ми з Максом почали готувати аплікацію до публікації: адаптували всі розміри іконок, скриншоти і т. д. А в голові вже був план щодо впровадження нових фіч.
Тоді кількість публічних бета-тестувальників iOS перетнула позначку 100.
Нові можливості
Серед запитів, що надходили від користувачів, можна виділити декілька:
- push-сповіщення;
- синхронізація з календарем;
- додайте Львів та інших постачальників.
Для всіх цих нових завдань потрібна була база даних. Вирішив використовувати MongoDB, але в процесі пошуку натрапив на Convex.dev. Це як все в одному. Але спочатку я не звернув на те увагу і використовував Convex.dev тільки як базу даних.
Приклад логів з адмін-панелі сервісу Convex.
Зміна архітектури
Розробляючи аплікацію, я старався зберігати зворотну сумісність, щоб під час виходу нової версії старі продовжували працювати. Тому вирішив додати ще один шар — Application API, що буде комунікувати з Proxy API та базою даних.
Додано шар Application API для взаємодії з Proxy API та базою даних.
Як працювала ця архітектура
Щоб відобразити список постачальників чи черг:
- аплікація викликала Application API;
- API комунікував з базою і повертав список постачальників чи черг.
Щоб відобразити події вимкнення електроенергії:
- аплікація викликала Application API з параметром «черги», котрий містив список вибраних користувачам черг;
- API комунікував з базою і повертав список подій щодо вимкнення електроенергії.
Оновлення подій:
- Cron на рівні Convex.dev кожні 30 хв робив запит до Proxy АРІ з параметром ID постачальника та оновлював дані в базі даних.
Цей підхід дозволив також зменшити навантаження на АРІ постачальника, і я вже не переживав, що постачальник зможе заблокувати запити через надмірну активність.
Така архітектура була опублікована в App Store. Кількість завантажень була приблизно 100 одиниць на добу. Наразі 2,4К завантажень.
Підімкнення інших постачальників
Дещо раніше до мене звернулися Олександр та Олег. Олександр з Черкас, тому він взявся писати сервіс, що витягує дані для Черкас з Telegram-каналу, а Олег — парсати картинки Львівоблененрго та повертати розпарсані дані в форматі JSON. Тут описано, як він це зробив.
Після того, як вони це зробили, підімкнення нових постачальників зайняло до 30 хв, оскільки це було передбачено архітектурою:
- додати в базу нових постачальників;
- додати в базу нові черги;
- додати нові ендпоінти в Proxy API, котрі б використовували Черкаси та Львів;
- додати cron job для виклику Proxy АРІ з параметром ID постачальника Львова та Чергінгова.
Так у нас сформувалася команда. Ми створили чат, де тестували аплікацію та обговорювали впровадження нових можливостей.
Дещо раніше, додаючи Web-socket до аплікації, я зрозумів, що окремо сокети не потрібні, оскільки Convex.dev все це робить з коробки і має хуки для React. Тому я переробив архітектуру, забравши непотрібний шар — Application API. Спрощена структура з новими підімкненими постачальниками наразі виглядає так:
Також я під’єднав Google Analitycs, оскільки мені не вистачало інформації про кількість користувачів, який відсоток користувачів використовує максимальну кількість черг (п’ять) та інше. Це було цікаво — думати які параметри можна трекати і як їх пізніше використати.
Виявилось, що доволі велика кількість користувачів стежить за максимально можливою кількістю черг.
Після того, як вимкнення практично припинились, — трафік поступово впав.
Push-сповіщення
Наступною глобальною фічею, яку ми хотіли впровадити, були push-сповіщення. Я вирішив використати Expo Push notifications service та взяти за приклад їхнє Node SDK. Спочатку перевірив отримання нотифікацій через push notification tool і після того продовжив написання логіки.
Аплікація не є персоналізована (я із самого початку цього дотримувався — ніяких реєстрацій). Тому виникло питання, де зберігати токени для надсилання нотифікацій користувачам.
Expo генерує Expo Push Token, базуючись на пристрої та ідентифікаторі аплікації. Тобто якщо користувач видалить і знову встановить аплікацію, або ж оновить версію, то для нього буде згенерований той самий push token. Тому токен був використаний в якості ID користувача, а ще була створена таблиця токенів в базі даних з полями token та список черг.
Для спрощення логіки надсилання повідомлень я вирішив створити ще одну таблицю в базі даних з усіма повідомленнями, а тоді порівнювати, чи ці повідомлення валідні для кожного користувача. І якщо так, то надсилати. Таблиця повідомлень складається з полів:
- тип повідомлення (поява нових даних, зміна, вимкнення або ввімкнення);
- ID постачальника;
- список ID черг вимкнень.
Поки я писав логіку отримання та надсилання повідомлень, Макс створив нові дизайни, де було додано сторінку «Повідомлення». Спочатку було вирішено не розсилати повідомлення, щоб не спамити в разі помилки навіть бета-тестувальників, а протестувати логіку, використовуючи сторінку повідомлень.
Коротко про те, як працює логіка повідомлень
Поява нових даних та їхня зміна:
- Cron з певним інтервалом запитує дані в Proxy API.
- Перед записом нових даних в базу він перевіряє, за якими чергами були зміни й чи були вони, і записує в таблицю повідомлень тип повідомлення (зміна даних або поява нових), ID постачальника та список черг.
- Після цього інший метод аналізує таблицю токенів, і для тих користувачів, що підписані на змінені черги, розсилає сповіщення.
Вимкнення та ввімкнення черг:
- Cron щогодини в XX:45 перевіряє таблицю подій, і якщо є вимкнення або ввімкнення через 15 хв, то записує в таблицю повідомлень тип повідомлення (вимкнення або ввімкнення), ID постачальника та список черг.
- Після цього інший метод аналізує таблицю токенів, і для тих користувачів, котрі підписані на черги, що мають бути вимкнені або ввімкнені розсилає сповіщення.
Коротко про Play Market
З Play Market мені не пощастило. Хоча я думав, що буде зовсім навпаки. Спочатку виявилось, що Google заблокував мій обліковий запис через неактивність.
Довгі пошуки того, як відновити, ні до чого не привели. Довелося створювати новий. Після цього виявилось, що для нових облікових записів перед публікацією потрібно провести закрите тестування, і для цього знайти 20 тестувальників, котрі протягом 14 днів мають тестувати аплікацію. Але навіть перед закритим тестування аплікація має пройти перевірку Google.
Перевірку я двічі не проходив — перший раз були помилки в аплікації, а другий — неправильно оформлена політика конфіденційності. Наразі тестувальники знайдені, й закрите тестування розпочалось. Тому сподіваюсь, що за 14 днів аплікація буде опублікована в Play Market.
Плани на майбутне
Поки ми не перемогли у війні й вимкнення електроенергії не припинились, застосунок ще буде актуальним. Особливо в осінньо-зимовий період. Тому закривати його ми не збираємось.
Наразі, поки вимкнень практично немає, я планую провести рефакторинг та оптимізацію коду. Інших постачальників плануємо залучати за потреби. Якщо будуть запити щодо конкретної області, де все дуже погано зі зручністю інформування про відімкнення.
Також плануємо додати нові можливості, наприклад, синхронізація з Google-календарем. І змушені шукати фінансування. Аплікація наразі працює на межі безкоштовних тарифних планів Convex.dev, кількість безкоштовних збірок на Expo теж обмежена в безкоштовному тарифі тощо.
Тому якщо вимкнення знову актуалізуються, потрібно буде десь шукати той мінімум, щоб забезпечити функціонування backend-серверів. Розглядаються варіанти різного виду реклами та створення pro-версії за платною підпискою з додатковими можливостями, яких не буде в безкоштовній версії.
Промахи
Великих промахів не було. У нас було спочатку внутрішнє тестування, далі — публічне бета-тестування, а тоді вже — реліз. Одного разу, коли постачальник змінив АРІ, — врятувала продумана архітектура, а саме: проміжне Proxy API, у котрому я протягом півдня вніс зміни відповідно до змін постачальника. Користувачів це зачепило так: протягом цього часу в них не було даних, але аплікація не падала.
Найбільшим промахом було те, що я неуважно зробив збірки для бета-тестування, продакшну та Android. Усі вони дивились на різне середовище — тестове та продакшн, push-сповіщення працювали на обох серверах, надсилалися одночасно, блокували одне одного.
Також користувачі могли отримувати сповіщення щодо черг, які вони обрали на попередній версії продукту і наразі не були на неї підписані. Довелося швидко випускати нові збірки для всіх середовищ — тестового, бета та продакшн, вимикати нотифікації на розробницькому сервері й швиденько публікувати нову версію в App Store.
Висновки
Коли ти працюєш як розробник — це одне, а коли ти маєш власний проєкт — це зовсім інше. Надто коли твоїм продуктом користуються 2000+ користувачів. Ти не маєш права на грубу помилку.
Це дуже корисний досвід — поставити себе на місце СЕО і думати за все, бути розробником і менеджером, планувати релізи, думати про зворотну сумісність, постійно ставити себе на місце користувача, збирати відгуки, аналітику та робити висновки на основі цих даних, рекламувати продукт тощо. Раджу всім спробувати створити як мінімум свій пет-проєкт.
22 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарів