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

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

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

14.08.2023

Kafka проти черг: події проти задач

Як цікаво: з першого погляду Kafka майже не відрізняється від черг, таких як SQS або RabbitMQ. Проте відмінності, на мою думку, починаються з того, як кожна система дивиться на повідомлення всередині.

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

Подія в Кафці — це запис про зміну стану. Подій може бути астрономічно багато — якщо це показники акселерометра з флоту автівок. З подій ми збираємо картину світу. Події нам потрібні всі відразу, або принаймні якнайбільшими пачками — бо логістичні витрати на пачку менше. Одинична подія для нас нічого не значить — нас цікавить остаточний стан.

Така різниця інформує API Кафки: воно розроблене, щоб якнайшвидше отримувати події, яких буде багато. Реально багато — хоч мільйон на секунду. Коли отримали та обробили, відмічаємо події як оброблені. Не кожну окремо (бо кому то цікаво робити з мільйоном записів), а всі разом — за зсувом.

Отже, Кафку має сенс ставити там, де вам потрібно обробляти значний обсяг подій та продукувати стан, або якось реагувати на зміни стану. А про Кафку як чергу гарно написали на StackOverflow.


13.08.2023

Емоції дороги

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


12.08.2023

Мʼякість TypeScript

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

Якщо ти з типізованих мов бачив тільки TypeScript, то навпаки, може скластися враження, що це стандартна система. Але ні: практично всі типізовані мови, що я знаю, не погодяться компілювати код без повністю вірних типів. (Не кажу про RBS для Ruby, бо він для мене надто сирий. Головним чином, аналог DefinitelyTyped поки не виріс.) Тож TypeScript являє особливу, “мʼяку” екосистему.

Мʼякість — це не тільки можливість виконати код без правильних типів. Це й розширення типів, про яке я писав вчора. І підхід типізації “за зразком” - тобто, замість жорстко заданих класів тип об’єкта перевіряється за наявними атрибутами.

Багато кому JavaScript не подобається саме через ту мʼякість, але на мою думку TypeScript ідеально доповнює ту систему підходів, яка вже існувала, та іншої такої вдалої мови я не знаю. Добре, що вона доступна майже в будь-якому сучасному середовищі.


11.08.2023

Розширення модуля в TypeScript

Я люблю TypeScript за те, як вона вдало розвʼязала питання інтеграції з кодом, що вже існує — а саме, з JavaScript. Завдяки можливості впровадити типи для будь-якої бібліотеки, TypeScript чудово інтегрувався з екосистемою та майже не обмежує вибір залежностей. Ну, багато ідіом JavaScript просто погано типізуються, але про це розмова окрема.

Напевно, кожний знає про проєкт DefinitelyTyped, тобто про пакети @types/*, які й додають типи до бібліотек на JavaScript. Але чи задавалися ви тим, як воно працює? Видається, дуже просто — вони містять так звані шаблони модулів. Власне, щоб TypeScript “побачив” модуль, він має або бути написаний на TypeScript (логічно), або мати шаблон.

Менш відома можливість — розширення модулів. Насправді не обовʼязково мати весь шаблон в одному місці. Цілком можливо розбити оголошення на дві частини. Більш за те, додаткові оголошення можуть бути зовсім в іншому файлі та навіть пакеті. Якщо TypeScript підвантажує в проєкт файл, в якому містяться оголошення, то він їх використає.

Причому розширяти можна й оголошення чужих модулів. Це як раз покриває ту незручну ідіому JavaScript, коли додатковий функціонал надається у вигляді плагіну. Як приклад: типи до Day.js. Або, ви можете виправити незручні типи залежностей прямо в додатку.

А якщо плагін — це окремий пакет, то треба памʼятати одну незручну річ: вкладені залежності. Бо той пакет, типи якого ви розширюєте, має не бути такою. Взагалі, при розробці пакетів-плагінів краще не створювати явних залежностей, а використовувати peerDependencies, або навіть devDependencies, та нехай споживачі самі знають, який головний пакет їм ставити.


10.08.2023

Логічна реплікація в PostgreSQL

Логічна реплікація (на відміну від фізичної) - це відносно новий (з 2018) та цікавий спосіб перенесення даних з однієї бази PostgreSQL в іншу. Оскільки зазвичай люди звикли до реплікації як відтворення копії цілої бази, зазначу, що логічна реплікація — це зовсім інша технологія. Працює інакше, вирішує інші завдання.

А саме, логічна реплікація створює копію не всієї бази, а однієї або декількох таблиць. Це корисно там, де треба мати одні й ті самі дані в декількох базах. Наприклад: замість центрального сервісу авторизації можна реплікувати користувачів до баз окремих підсистем, або навіть регіонів. Або: логічною реплікацією можна збирати частину даних в головну базу для генерації звітів та аналітики. Тобто в цілому, корисна технологія, яка працює майже без зусиль.

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

Є декілька нюансів, про які треба памʼятати. Головне, таблиця-отримувач має бути сумісною з таблицею-джерелом за структурою. Найчастіше натрапляємо на те, що коли додаєш стовпчик в джерело, то перед цим треба було вже додати в отримувача. Але також пильнувати треба за індексами та іншим.

Бо якщо PostgreSQL не може застосувати чергову зміну у таблицю, то він просто призупиняє реплікацію. Хороші новини — вона відновиться автоматично, як тільки зміни стануть можливими. Погані — при паузі реплікації на стороні джерела накопичується журнал, причому стрімко. Якщо цього не помітити, можна заповнити журналом все місце на диску, від чого база лягає ще серйозніше.

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

Але важливіше те, що логічна реплікація не гарантує рівності таблиць. Тобто, гарантує, але якщо нічого не трапилось, та поки реплікація ніколи не зупинялась повністю. Хоч завжди можна скопіювати всю таблицю наново…

Одним словом, проблеми в логічної реплікації є, але якщо порівнювати з іншими рішеннями, то вона вельми надійна та легка в налаштуванні.


09.08.2023

Машини AWS Burstable (T-class)

Сьогодні моє уявлення про мінімальний масштаб сервісів було доповнене ще одним критерієм. Йдеться про так звані burstable (тобто “імпульсні”) машини AWS.

Коли бачиш в категорії машини літеру T - то це ті самі імпульсні машини. Їх можна помітити не тільки в EC2, але й в RDS, ElastiCache, та будь-якому іншому сервісі. Коштують вони дешевше, тож виглядають як гарний вибір за відсутністю конкретних вимог. Проте зі швидкодією T-класу є нюанс: вони не здатні працювати на зазначених показниках постійно. Натомість машини класу T накопичують кредити, поки не мають навантаження, а під час навантаження навпаки, ці кредити витрачають.

Що буде, коли кредити закінчаться? Машина буде обмежена до так званої базової швидкодії, що може значить від 5% до 40% від зазначених показників — в залежності від розмірів машини. Причому буде обмежений як CPU, так і дискова активність. Та до того ж щоб помітити цю ситуацію, треба стежити за балансом кредитів, бо за графіком CPU її не помітиш. Наприклад, графік буде показувати, що машина витрачає безпечні 20% CPU, в той час, як вона задихається від навантаження.

Одним словом, в продакшн машини T-класу брати не можна. Бо опинишся в неприємній ситуації, та, скоріше, посеред важкої задачі, яка через обмеження триватиме ще довше. Хоча ще такий Unlimited mode, коли робота поза вичерпанням кредитів можлива, тільки за додаткові гроші.


08.08.2023

Пригоди з оновленням Ruby

Сьогодні вирішив оновити на проєкті Ruby з 3.1 на 3.2. Якщо не знаєте, то нова мінорна версія Ruby виходить щороку на Різдво — тобто давно пора оновлюватись.

Але вийшло, що Rails 6.1 - які, до речі, вийшли в грудні 2020 - припинили отримувати оновлення ще минулого вересня. Та з Ruby 3.2 не працюють. Проблеми зʼявляються навколо використання названих аргументів — а саме, якщо в Ruby 3.1 функцію з названими аргументами можна було викликати з хешем аргументів, то в 3.2 це вже дві різні конструкції та такий виклик призводить до помилки.

Значить, потрібно також оновитись до Rails 7 (які вийшли в грудні 2021 та являють собою останню мінорну версію на цей день.) Змін не так вже й багато. Цікаво, що Rubocop також включає декілька правил для Rails 7, наприклад, Rails/UniqueValidationWithoutIndex.

Але не все так просто — з Rails 7 припинив працювати Webpacker - бо він взагалі більше не підтримується. Є декілька альтернатив - jsbundling-rails та інші — проте найпростіша в переході бібліотека shakapacker. Назва дивакувата, зате Shakapacker є прямим нащадком Webpacker та без великих зусиль підтримує ту саму конфігурацію, що й Webpacker 6.0rc6, що я перевірив порівнянням результатам збірки. Конфігурація була дуже складна, тому й не став все переробляти на кардинально новий конвеєр — бо все, що я хотів, це оновити Ruby.


07.08.2023

Як кодувати міста в програмній системі?

Вправа: користувач має змогу обрати своє місто та країну, з автодоповненням. Далі адміністратор може побачити користувачів за обраним містом та країною. Як би я реалізував таку функціональність?

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


06.08.2023

Мова емоцій

Прочитав (або точніше, прослухав) книжку The Language of Emotions, дізнався про яку, як це не дивно, зі статті Кента Бека — творця Agile Programming. На мою думку, ця книга добре підходить для айтівців, оскільки надає аналіз та інтелектуальну інтерпретацію емоцій — тобто як їх розуміти “головою”. Таким чином, книга вчить інтелектуальну та емоціональну частину особистості співпрацювати, причому вчить досить прямим та дієвим підходом. Це дуже важливо, бо наша субкультура вимагає тверезого та аналітичного мислення та спілкування, де емоції ніби зайві — при тому, що, на мою думку, вони потрібні не тільки для чемного спілкування, а й для ефективної роботи (бо код, проєкти та сервіси теж викликають емоції, які теж варто розуміти.) На думку автора книги, емоції cлід не оцінювати як хороші чи погані, а слухати як сповіщення від несвідомої частини нашого розуму.

Напевно понад усе мені запамʼяталася глава про страх. Вона каже, що страх — це відчуття підвищеної уваги до нашого оточення. Я раніше думав, що страх — це коли відбувається щось загрозливе, а виходить, що страх починається раніше. В мене така аналогія: тривога — це коли ти збираєшся йти до лісу, де живуть ведмеді; страх — коли ти в лісі; а коли вже тікаєш від ведмедя — то паніка. З цього ракурсу я зміг зрозуміти, що значить, що українці живуть зі страхом; бо хоч в містах нашому життю рідко загрожує безпосередня небезпека, але ти завжди прислуховуєшся до звуків на вулиці, причому абсолютно автоматично. Це і є страх.

Ще приклад страху — коли дивишся код та отримуєш неприємне відчуття, що це місце спричинить проблеми в майбутньому. А тривога — коли пишеш код, але остаточного розуміння задачі немає. Моя історія про відволікання - це теж тривога та дизасоціація, яку вона спричиняє. Тож якщо навчитись краще помічати за собою такі емоції, то можна стати кращим розробником… ну як, продав вам “мʼякі навички”?


05.08.2023

CouchDB - база даних з крутою реплікацією

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

З першого погляду, CouchDB - документна СУБД з максимально простою структурою, яка, до речі, схожа з OpenSearch. Документи складаються в бази даних, бази даних живуть на серверах. Цікавий момент — баз даних може бути скільки завгодно, наприклад, по базі на користувача.

Але що насправді цікаво, це як вона працює з реплікацією. Модель реплікації CouchDB підтримує скільки завгодно вузлів, причому не обовʼязково постійно підключених. Тобто це ідеальна база для роботи офлайн. Наприклад, мобільний пристрій може працювати зі своєю локальною базою, попри стан підключення, а оновлювати коли це стає можливо.

Що робити з конфліктами? Власне, вирішати нам — в CloudFlare потужний механізм розвʼязання конфліктів. Можна робити це автоматично, за правилами переваги, а можна й написати код зі специфічною логікою.

А ще, реплікувати можна не всю базу, а частину документів за правилом. Наприклад, може ми хочемо завантажувати на сервер тільки опубліковані документи. А ще можна обмежити реплікацію тільки одним з напрямків. А ще реплікувати багато баз в одну або навпаки — одну в декілька…

Окрім самої CouchDB, є ще повноцінна реалізація на JavaScript - PouchDB. Її можна запускати в браузері або в React Native, та синхронізувати з сервером CouchDB.