Інженерна підноготна Сінтри

June 4, 2022 in Projects

Сінтра - це наш сервіс для планування особистого бюджету. Робимо його ми з Сашею Зайцевим, удвох. Це мій перший пост про Сінтру, хоча у серпні буде чотири роки з початку розробки і три - з запуску.

Пропоную почитати Сашин пост про становлення Сінтри. А я розкажу, на чому воно все тримається.

Що з себе ставить Сінтра? Головна частина - це веб-додаток, у якому і відбувається керування бюджетом. Для введення витрат на ходу є мобільний додаток. Ну і незрима, але важлива третя частина - повідомлення та біллінг.

Сінтра це сайд-проєкт, як для мене так ї для Сашка. Тобто, робимо ми його у вільний від роботи час, за лічені години на тиждень. Код пишу здебільшого я один. У таких обставинах критично важливо не марнувати часу на тривіальні речі, і витягувати якнайбільше користі зі своєї роботи.

Бекенд

Таким чином, перше, на що ми не марнуємо час - це бекенд. Тому відразу вирішив не писати свій бекенд - на Ruby on Rails, наприклад. Натомість я обрав Firebase - готову платформу для розробки додатків.

З моєго досвіду, більшість функцій бекенду - це перемудрений доступ в базу. Firebase містить в собі базу-як-сервіс Cloud Firestore. Достатньо описати правила доступу для користувачів, і база готова до вживання. Вона працює і офлайн, що необхідно для мобільного доступу. До того ж, у клієнт вбудована “жива синхронизація”, тому зміни з мобильного додатку миттєво з`являються у вебі і навпаки, без жодних зусиль з нашої сторони.

Окрім бази, Firebase дає хостінг для статики. До речі, з усіх альтернатив по хостінгу (Vercel, Netlify) я вподобую саме його, бо хостінг Firebase не прив`язаний до Git і є найбільш гнучким. Тобто питання “де захостити сайт” теж вирішене.

Нарешті, Firebase також включає Cloud Functions. Деякі операції на клієнті не зробиш. Наприклад, відправку повідомлень, або обробку підписок. Для цього можна написати функції, що будуть виконуватись у хмарі, або за запитом, або за розкладом.

До речі, тут цікавий момент - оскільки ми працюємо з вашою приватною фінансовою інформацією, то з самого початку вирішили не чіпати даних на бекенді. Взагалі. Тому всі обчислення та логіка виконуються на вашому пристрою. Наприклад, якщо треба відправити повідомлення про перевитрату, то саме клієнт обчислює її і ставить повідомлення у чергу, а бекенд тільки відправляє.

Firebase має щедрі безкоштовні обмеження. Ми зних ще майже не вилізли. Якщо захочемо спригнути, існують сумісні self-hosted замінники - найкрутіший це Supabase.

Недоліки Firebase. Клієнт важить від 600 кб і більше. Немає доступу до бази як цілого, тобто бекап робиться по записах і сплачується так само.

Фронтенд

Наш веб-додаток - single-page application на React. Це моя улюблена бібліотека - з 2015 ще нічого кращого не бачив. Мобільний додаток, відповідно, на React Native. Про останній скажу так: хоч він і не ідеальний, але нативні бібліотеки часом не краще.

Взяли React Native щоб не писати код двічи. Я маю на увазі не код React компонент, він на вебі і мобілі практично не перетинається і не може перетинатись - бо не тільки набір образотворчих засобів, але й потреби дизайну різні. Але шар бізнес-логіки у нас шариться абсолютно весь.

Бізнес-логіка у нас базується на Redux Toolkit. З Firestore вибирається (та синхронізується) “робочий набір” даних, що потрапляють до Redux. Цей набір залежить від стану додатка - чи залогований користувач, чи є поточно обраний бюджет, і так далі. У Redux знаходяться здебільшого необроблені дані. Потім з Redux за допомогою reselect обчислюються похідні - такі як залишок бюджету на сьогодні - і передаються до React. Всюди користуємся хуками (авжеж) та async thunk.

Окрім React ще є декілька модулів, що моніторять зміни у Redux і за допомогою тих самих селекторів виставляють повідомлення та інше.

Взагалі, я дуже задоволений такою моделлю. Вона, можливо, не так добре масштабується. Селектори обчислюються, грубо кажучи, на кожну зміну будь-де у Redux, тому якщо їх надто багато, додаток уповільниться. Але ми знаємо, що “робочий набір” даних завжди буде невеликим - бо це, спрощуючи, перелік витрат одного користувача за один місяць.

Мова

Я почав кодити Сінтру на JavaScript. Зручно мати одну мову на бекенді, вебі і мобілі. Але через рік чи півтори я переклав все на TypeScript. Чому не почав з нього? Тому що на початку я ще нічого про TypeScript не знав і було невідомо як це. До того ж не був впевнений, що з Typesript буде зручно працювати Саші, який допомагає з версткою та іншим.)

Виявилось, що TypeScript - головний помічник у маленькій команді. Я вже докладно про це писав. Завдяки типам можна досягнути доброї впевненості у правильності кода, без написання юніт-тестів. При цьому задати типи набагато легше, ніж написати юніт-тести. Вони легше у рефакторінгу і не такі крихкі при змінах. Говорячи просто, ми б ніколи не встигали писати вичерпні тести, це нерентабельно. А коли код тримає в купі TypeScript, я мав час покрити тестами складні і важливі місця бізнес-логіки.

Як щодо ускладнення написання коду для Саші, то тут треба розуміти, що явно заданих типів в типовому коді залишається небагато - більшисть виводяться автоматично. До того ж, цікава особливість TypeScript - він буде компілювати код у JavaScript і зі зламаними типами, і без типів взагалі. Таким чином, якщо в команді є людина, що добре знається на типах і може налаштувати проєкт, то всі інші можуть продовжувати писати “майже” на JavaScript.

Решта

Звичайно, користуємся бандлером Webpack. Але це вже погана звичка, треба шукати щось краще. (Ну і, якщо ви не знали, то у React Native свій бандлер, що навіть компілює у мікрокод.)

Статичний сайт для головної сторінки ми збираємо у Hugo. З Hugo цікава ситуація. Хоча я не дуже його люблю, але що інше не пробовав - все гірше. Мій сайт також на Hugo, до речі.

Помилки збираємо у Sentry. Sentry виграв гонку до найкращого збирача помилок, як на мене.

Пошту відправляємо через Mailgun. Найцінніше тут для нас - це безкоштовний план (бо не так багато відправляємо.) Але, ще ми користуємся їх шаблонізатором, це теж економить час.

Підраховуємо відвідування у Plausible - це ну дуже мінімалістична аналітика, яка навіть не трекає сесій. Замість будування портрету користувача (що вона не робить взагалі), Plausible дозволяє оцінити популярність сторінок та подій через статистику.

Поради

Головне, що потрібне для успіху інженера у маленькій команді - це не закопуватися у технічні підробиці. Чим менше команда, тим більше у інженера влади, щоб перетворити проєкт у храм чистого коду і правильної архітектури. Але успішний продукт і технічно ідеальний проєкт - це дві різні цілі. Щоб вийшов добрий продукт, треба, по-перше, дотримуватись регулярних релізів, а по-друге, зосереджувати розробку на потребах користувачів. Краще, коли для цього є продукт-менеджер та дизайнер. Але якщо їх немає, треба свідомо розвивати ці навички у себе.

Buy me a coffee Liked the post? Treat me to a coffee