Стендап Сьогодні

Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті

Підписатись на RSS
📢 Канал в Telegram @stendap_sogodni
🦣 @stendap_sogodni@shevtsov.me в Федиверсі

08.12.2022

Плани проєкту "зворотній ping" - вибір фронтенду

💬🪟🧑‍🎨 Наступне питання — на чому робити фронтенд? Та, хоча я великий фанат React, але для маленького проєкту, напевно, краще взяти Svelte.

Я вже робив маленький проєкт на Svelte - власне, коментарі на моєму блозі. Порівняно з React, вона чудово вирішує базові потреби додатка і дає можливість швидко розпочати розв’язання задач бізнесу.

Якщо не бачили, то у Svelte свій, особливий синтаксис: кожний файл містить один компонент; у файлі спочатку йде код JavaScript (майже) - імпорти та логіка, а потім шаблон HTML (майже). В результаті отримуємо більш-менш те ж саме, що й у React. Але, якщо React використовує стандартний JavaScript (та дуже прямолінійний JSX, то Svelte додає до JavaScript купу зручностей та синтаксичного цукру. Розібратися в цьому синтаксису навряд чи вийде без підручника. Це найбільший ризик у виборі Svelte, і саме через синтаксис я не думаю, що було б зручно писати на Svelte великий проєкт.

Також, порівняно з React, Svelte пропонує більш завершений комплект — він включає і сховище (аналог Redux), і пакувальник (аналог Webpack). TypeScript повністю підтримується — для мене це є необхідність. Тож, без зайвих налаштувань, можна відразу робити щось корисне. Це теж життєво необхідно для маленького сайд-проєкту.

Мабуть, доцільно будет порявняти Svelte з Ruby on Rails, де теж на кожну потребу є свій особливий і зручний DSL.


07.12.2022

Плани проєкту "зворотній ping" - вибір мови та хостінгу

📋🦡🎈 Продовжую планування для проєкту “пінг, але навпаки”.

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

При меті досягти найбільше з найменшими витратами мій вибір буде Golang та fly.io. Тут почати можна вже за $2 на місяць, і не хвилюватись про кількість запитів.

Але є інша сторона витрат — база даних. Зазвичай база — то окремий сервіс, тобто ще $2 на місяць, а скоріше за все, більше, бо сучасні бази не хочуть працювати на 256 MB оперативної памʼяті. Тому вирішив зробити ще один неординарний хід та розмістити базу даних всередині головного додатка, тобто вбудувати. Тоді не тільки не потрібно переплачувати, а ще й працюватиме швидше.

Можна було взяти для цього SQLite3, але ще краще, на мій погляд, випробувати одну з декількох вбудованих key-value баз, що існують для Golang. Поки зупинився на базі Badger. Якщо спрощувати, то це типу Redis, але працюватиме прямо в додатку. Вміє вона зберігати дані на диск (бо як без цього), синхронізувати (в майбутньому) декілька вузлів, підтримує транзакції. Єдине, що мені трохи не подобається, це те, що API роботи з базою — це не “просто писати в структуру даних”, а все ж таки схоже на роботу з сервісом.


06.12.2022

Плани проєкту "зворотній ping" за допомогою IFTTT

💡➡️📥 Якщо розвивати ідею про перевірку, чи є звʼязок, то можна зробити цікавий проєкт — такий собі зворотній ping. Ідея така: замість того, щоб пінгувати сервіс, сервіс отримує URL, який він має регулярно викликати. Корисно це тоді, коли сервіс не є досяжний напряму.

З іншого боку, повідомляти о наявності в Slack - це добре, але недостатньо; гарно було б додавати запис у календар. Або, я б хотів сам отримувати повідомлення про те, що звʼязок зʼявився, поки я не вдома.

З такою задачею мої руки тягнуться до IFTTT. IFTTT - це універсальний адаптер, що вміє повʼязати “вихід” одного сервісу зі “входом” іншого. Звісно, він підтримує і Slack, і Google Calendar, і все що можна собі уявити. Тож залишається зробити так, щоб моя “перевірялка” теж була інтегрована в IFTTT.

Для цього достатньо розробити API, що відповідатиме специфікації. Тож розбирався, як воно робиться.

Головне - IFTTT опитуватиме мій сервіс щогодини. Сервіс має повернути останню подію, або декілька подій. З одного боку, це легко підтримувати, бо навантаження не таке велике. З іншого, година — може й занадто довга затримка. Якщо потрібно відправити подію скоріше, то є ще “API реального часу”, тобто просто URL, за яким можна попросити IFTTT опитати сервіс скоріше.

Також потрібно зробити аутентифікацію та OAuth сервер. Та якийсь мінімальний інтерфейс налаштувань. Та купу маркетингових матеріалів. Але має вийти цікавий маленький проєкт, нічого схожого я поки не знайшов.


05.12.2022

Мої рекомендації протоколу для RPC - HTTP, JSON, стійке підключення.

🏭🚂🏢 Мої стислі рекомендації по вибору стандарту RPC (дивлячись з боку систем на Ruby / Go.) Беріть JSON over HTTP, але обовʼязково — з використанням стійкого підключення.

Стійке підключення (таке, що зберігається на декілька запитів) важливе тому, що на встановлення підключення витрачається набагато більше часу, ніж на будь-яку “обгортку” запиту. Особливо якщо це підключення зашифроване — тобто практично завжди. Стійке підключення доступне в будь-якому клієнті HTTP.

Чому HTTP? Тому що інспектувати та тестувати такий API завжди буде найпростіше — інструментів безліч — браузер, термінал, спеціалізовані інструменти на кшталт Paw.

Чому JSON? Інтуїтивно здається, що, оскільки це текстовий формат, то він має працювати повільно. Але ні — завдяки тому, що JSON - це найбільш розповсюджений формат даних, та його парсери довершено оптимізовані. У моїх тестах JSON працював так само швидко, як і бінарні формати, принаймні на невеликих структурах даних. До того ж JSON легко читати та писати вручну.

Окремо раджу не брати gRPC, принаймні для Ruby. Бінарна частина gRPC має нескінченні складнощі з компіляцією, несумісна з Alpine, а також регулярно тече. Частина, що написана на Ruby, а точніше генерується, не слідує конвенціям. Так, gRPC дає можливість генерувати код клієнта та сервера з однієї специфікації, але ця перевага не перевішує всіх складнощів, що він з собою несе.

Щось складніше за JSON-over-HTTP раджу брати, тільки якщо потрібна величезна пропускна здатність. І тільки обмежено. Бо цим ви завжди втрачатимете простоту.


04.12.2022

Як запостити файл на GitHub з мінімального середовища

😼🧙🐚 Величезний день роботи по дому — придбав перфоратор, повісив бойлер.

Розкажу, яким чином все ж таки можна запостити файл на GitHub з мінімального середовища (наприклад, на роутері).

Зовсім не обовʼязково для цього мати Git. Можна редагувати файли за допомогою API. Щоб зробити запит до API, достатньо мати wget або curl. Тіло запита — звичайний JSON, який можна побудувати шаблонним рядком.

Тут є нюанс — зміст файлу має бути закодований у Base64. У мене на роутері утілити base64 не виявилось. Що ж робити? У моєму випадку потреби обмежені: треба було записувати в файл щось. Тож підготував текст, який вже був закодований в Base64.

Далі — для зміни файлу, що існує, необхідно передати його поточний хеш. Це логічно, оскільки API має переконатись, що наша операція починається з відомого місця в історії Git. Цікаво, що при цьому не потрібно знати хеш коміту, а тільки хеш файлу. Легше всього дізнатись його теж через API.

Але як з відповіді цього API дістати значення, коли немає парсера JSON? Довелося парсити за допомогою регулярних висловів, а саме, командою sed -E 's/.*"sha": "([^"]*)".*/\1/'. Такий вислів знайде у тексті JSON значення поля sha, та залишить у виводі тільки його.

На останок, ще одна проблема: щоб створити новий коміт, файл треба поміняти. Можна було зробити взагалі просто: записувати у файл по черзі то текст, то порожнє значення. Поточний зміст файлу можна подивитись у тому ж API, що й sha. Але я трохи перемудрив та потроху дописував у файл по 3 символи. Чому по 3? Тому, що у Base64 у кожному символі кодується 6 біт вхідного тексту, тобто 3 символи вхідного тексту — 24 біти — рівно діляться на 4 символи Base64.

Якось так. Повний скрипт тут. Радий, що такі задачі зустрічаються хіба що заради вправи або забави.


03.12.2022

Скрипт для повідомлення про наявність звʼязку на основі Firebase

🔥🌚🌝 Скрипт для повідомлення про наявність звʼязку написаний.

Спочатку години три робив реалізацію на GitHub: маркер наявності звʼязку записував у файл, а перевіряв регулярним процесом GitHub Actions. Складність в тому, що на роутері дуже обмежене середовище, і там немає ані git, ані навіть команди base64. Можна поставити флешку та розгорнути повноцінну систему з пакетами та іншим, але не хочеться — в мене поганий досвід використання флешок як постійно увімкнений диск. Доводилось використати API, але з ним все теж не так просто. Я все ж таки знайшов, як це робити, але залишу розповідь на інший раз, бо рішення вийшло таке складне й незграбне, що продовжувати не хотілось.

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

Як щодо Slack, то насправді не так все складно — аплікація створюється тут, а далі те, що нам потрібно, називається Incoming Webhook і дозволяє постити в слак максимально простим запитом на фіксований URL: {"text":"Hello World!"}.

Скрипт для Firebase ось тут, і так — весь код цієї системи вміщується в один файл. Розгорнути його можна абсолютно безплатно, а з боку домашньої мережі потрібен будь-який пристрій, що робитиме запити HTTP GET.


02.12.2022

Як автоматично стежити за відсутністю звʼязку вдома

📶❌📢 У звʼязку зі повторюваною відсутністю звʼязку, хочу зробити такий собі інструмент, щоб повідомляв команду про те, що я їм зараз поза зоною досяжності. Надихався цим постом , але там тільки віджет, та до того ж він вимагає наявності статичного IP. Поки я на етапі планування. Початкова ціль — повідомляти в слаці, якщо в мене немає домашнього інтернету (бо я вже дванадцять років працюю з дому, до речі.)

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

В мене роутер ASUS, оснащений прошивкою Merlin. З таким роутером не потрібний компʼютер, щоб подавати сигнали — скрипт виконуватиме сам роутер. Звісно, середовище скриптів на роутері обмежене, і так само обмежене місце (хоча можна й флешку під’єднати.)

Тепер, куди відправляти сигнал? Та головне — як це зробити безплатно? Я беру звичний AWS, а саме AWS S3. На S3 можна відправити до 2000 безплатних запитів на запис в місяць. Цього цілком вистачить для того, щоб сигналити щогодини. Писати на S3 нескладно, хоча з Bash я цього ще не робив.

Нарешті, для перевірки статусу візьму AWS Lambda - тут достатньо безплатних хвилин виконання. Лямбда-функція повинна запускатись раз на годину, дивитись таймстемп файлу на S3, та, якщо він перебільшує годину чи дві, повідомляти в Slack.

Slack, на відміну від GitHub, не має зручного механізму відправляти повідомлення зі скрипту — тож доведеться створити аплікацію, налаштувати, отримати адресу для вебхуків, і потім вже відправляти повідомлення туди.


01.12.2022

Cтворення великого контексту БД для тестів за допомогою пакетної вставки

🏭🚚🗄️ Сьогодні маленька порада для рубістів, а саме — як швидко створити багато записів в базі, особливо для тестів.

Якщо з локальною базою це може заощадити вам секунди, то з тестами на AWS Redshift - буквально хвилини. З Redshift доцільна така інтуїція: команда INSERT працюватиме однаково швидко для одного рядку та для багатьох — або краще сказати, однаково повільно. Хоча й на звичайній базі можна прискорити якісь аналітичні тести з купою записів.

Всі мають знати метод insert_all, який виконує ту саму команду INSERT для декількох рядків. Також варто знати, що, окрім того, він перевірятиме рядки на дублікати, а якщо цього робити не потрібно, то є метод “з наголошенням” insert_all!.

Багато хто також знає метод FactoryBot.create_list. Але він нічого особливого не робить, просто створює декілька записів в циклі.

Тож як подружити insert_all та FactoryBot? Якось так: Product.insert_all(FactoryBot.build_list(:product, 100).map(&:attributes)). Тобто, готуємо записи без зберігання, потім беремо від них атрибути й вставляємо однією командою.

Такий метод не створюватиме асоціацій, тому їх доведеться створювати окремою командою.


30.11.2022

Перші враження від PagerDuty

🚨⚠️⏰ Перші враження від PagerDuty: це не магічне рішення всім проблемам моніторингу та підтримки.

У нас моніторинг трохи більш тривожний, ніж потрібно. В ідеалі а) інциденти трапляються рідко та б) кожний дійсно вимагає уваги. Тобто якщо о четвертій годині ранку тобі дзвонить PagerDuty, це має значити тільки одне — треба продерти очі та бігти виправляти. Якщо ж порушене одне з цих правил, то інциденти втрачають нашу увагу, а без уваги PagerDuty - марна трата грошей.

Це автоматично значить, що PagerDuty не місце на стейджингу, хоча це здавалось хорошою ідеєю, бо стейджинги теж треба підтримувати живими.

Також, пряма інтеграція тривог AWS CloudWatch з PagerDuty погано спрацювала, бо тривог в нас багато, і не всі вони потребують термінового розвʼязання. Тут більше недолік CloudWatch - їх тривоги суто чорно-білі, немає ані “рівня попередження”, ані “не дуже важливих” тривог.

Коротше, PagerDuty ще треба налаштувати на ситуації “кинути всі справи та виправляти”, а за CloudWatch доведеться й далі спостерігати, але іншими способами.


29.11.2022

Як ефективно програмувати, коли немає звʼязку?

🌑🔦👩‍💻 Як ефективно програмувати, коли немає звʼязку? Головна проблема цих днів — відсутність швидкісного інтернету. Ноутбука вистачає на багато годин. Але ж звʼязок при відсутності електрики швидко псується. Дротовий інтернет не працює без роутерів, мобільні мережі перенавантажуються, бо всі разом перестрибують на них.

Головний інструмент програміста — редактор — не потребує інтернету. Тут нам вже пощастило, порівняно з маркетологами або аналітиками. Тож код можна набирати, доки ноутбук не розрядиться.

Далі, програми потрібно запускати. Звісно, типові проєкти цілком готові до локального запуску. Якщо ні, то саме час зайнятись цим технічним боргом, як зʼявиться вихід в інтернет.

Але деякі проєкти потребують інтеграції з тим чи іншим вебсервісом. Для багатьох сервісів є емуляція, наприклад, localstack для AWS, або набір емуляторів Firebase.

Хоча я розумію, що інколи емуляція не підходить. Тоді можна знайти альтернативну роботу — наприклад, написання тестів для коду, що вже існує (бо тести ж мають працювати без зовнішніх залежностей?). Або виправлення правил лінтера. Для Terraform є такі вичерпні лінтери на кшталт tfsec, що я впевнений, що ваша конфігурація їх ще не проходить. :)

Додатковий фактор — документація. Тут тяжко без інтернету, знаю. Базову документацію зручно тримати локально — я вже багато років користують Dash. Туди, до речі, можна завантажити й документацію до окремих пакетів. І навіть топові запитання StackOverflow, хоча це мені мало допомагало.

Також треба згадати, що на більшості сучасних мов ті пакети, що є залежностями, вже є завантаженими локально, і читати їх код можна без GitHub. В Ruby є зручна команда bundle open, але знайти місце розташування залежностей завжди можна вручну.

Ці навички також допоможуть нам також зручно працювати в подорожах, або й просто економити час — локальні ресурси завжди є і будуть швидше віддалених.