Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
- ActiveRecord
- AmazonRedshift
- API
- AppleScript
- AWS
- AWSLambda
- CGO
- Chezmoi
- CI
- Clojure
- Cloudflare
- CloudflarePages
- CssParser
- CтохастичнийТаймтрекер
- DNS
- Docker
- Dotfiles
- Fly.io
- GCP
- Git
- GitHub
- GitHubActions
- Go
- Golang
- GTD
- HomeAssistant
- Hugo
- I18next
- JavaScript
- JSON
- Kafka
- MacMiniВДорозі
- MacOS
- Markdown
- Mastodon
- Obsidian
- ObsidianCanvas
- OmniWOPE
- OpenSearch
- Oura
- Ping
- Plausible
- PostgreSQL
- ReactNative
- Redis
- RSS
- Ruby
- RubyOnRails
- Sintra
- SMTP
- SQL
- SQLite
- Svelte
- Swift
- SwiftData
- SwiftUI
- Telegram
- Terraform
- TLS
- TypeScript
- Vercel
- VPN
- WeightPlot
- WordPress
- XCode
- Адвент2024
- Бази Даних
- БДС
- Безпека
- Блокнот
- Вебтехнології
- ВолюІнформації
- Гаджети
- ДизайнМовПрограмування
- Ігри
- Інструменти
- ІнтеграційніТести
- Кава
- КеруваннняЗадачами
- Кодогенерація
- Криптографія
- Локалізація
- Маркетинг
- МетаПост
- МоїПроєкти
- Навігація
- Оптимізація
- ОсновиІнтернетБезпеки
- Помічник ШІ
- ПомічникШІ
- ПостПроПохід
- Програмування
- Продуктивність
- Проєкти
- Проза
- РДУГ
- Рівночасність
- РобочийКомп
- Розробка
- РозумнийБудинок
- СинПопросивПриготувати
- Сон
- СтохастичнийТаймтрекер
- Танці
- ХмарніТехнології
26.12.2025
Quake
В моїй уяві є архетип шутера, з яким я порівнюю всі інші — свідомо чи несвідомо. Це - Quake 1. Де в кого Doom - це перший “справжній шутер”, але я гадаю саме Quake набув справжньої сучасної форми. Не кажучи вже про те, що саме рушій Quake лежить в корні численних сучасних ігор.
Quake швидкий, стрибучий, тут немає укриттів та вся безпека в рухомості та агресії. Це, в цілому, та ж гра, що й Doom Eternal - тільки зведена до мінімалістично ідеальної формули.
Саме на Quake 1 я навчився WASD. Саме там був мій перший мультиплеєр — в школі, в той час, коли ми повинні були розвʼязувати олімпіадні задачі.
Потім на Quake я вивчав 3D-графіку, дізнавався, що таке BSP (бінарне розбиття простору), а також .bsp - формат файлів, в яких Quake зберігає рівні. А тепер можна взагалі код його вивчати.
Ще двадцять з гаком років тому на Quake була сцена модів, деякі з них повністю змінювали суть гри, наприклад, перетворювали її на фентезі чи на військовий шутер. Але смішно, що моди не могли замінити скрипти поведінки, тому в ворогах завжди впізнавалися знайомі фігури (особливо той характерний людожер з бензопилою та гранатометом.)
Звісно ж, Quake живий й досі. Та досі чарує своєю простотою — це така гра, в яку легко встрибнути. Можу порадити рушій Quakespasm (навіть на мак можна!) та сайт Slipseer з модами. От відразу раджу Brutalist Jam.
25.12.2025
Надгробки в базах даних
ОК, ще одна повʼязана ідея, з якою мені чомусь постійно доводиться стикатися останнім часом.
Річ у тім, що видалення з бази даних практично ніколи не вивільняє місце запису. Натомість запис помічається як видалений — утворюється так званий надгробок (tombstone). І тільки пізніше, окремою операцією очищення бази це місце буде дійсно вивільнено. Інколи таке очищення відбувається лише вручну… або за певної архітектури взагалі не є можливою.
Те ж саме стосується й редагування. Бо найчастіше редагування відбувається через “видалення” попередньої версії та дописування нової. Тим самим у нас теж зʼявляється надгробок. На то є кілька причин — в транзакційній базі головна причина те, що нам все одно треба зберігати й стару версію теж. Так само і в розподіленій базі.
От якщо взяти PostgreSQL, то надгробки видаляються операцією VACUUM. Яка може виконуватися й автоматично. Може, а якщо це не налаштовано, то цілком реально опинитися з табличкою, де мертвих записів на порядок більше, ніж живих.
В ElasticSearch все складніше; найкращій та рекомендований варіант — це просто видаляти весь застарілий індекс. Бо інакше його доведеться принаймні заморожувати на запис. Тому навіть використовується такий підхід, що оновлені документи пишуться в нові індекси, а не в один.
Інколи надгробки є більш… матеріальними, от в CouchDB їх роблять заради синхронізації видалень між вузлами. Та й взагалі будь-де синхронізація вимагає надгробків.
А інколи ми робимо їх самі - додаємо поле deleted_at.
24.12.2025
Що ж воно таке за дерево той індекс?
ОК, давайте відразу виправлюсь: все ж індекси використовують Б-дерева, а не двійкові дерева. Але в чому різниця?
Двійкове дерево то є просто дерево, де в кожного вузла не більше двох дітей. Є двійкові дерева пошуку, де ці діти (піддерева) містять"елементи менші за поточний" та “більші”. Є збалансовані дерева, де піддерева мають рівний (чи приблизно рівний) розмір. (Бо наївна побудова дерева може дати зовсім не рівний та не ефективний результат.)
А Б-дерево — це як збалансоване двійкове дерево пошуку, тільки замість того щоб тримати в кожному вузлі тільки один елемент, тепер їх стає N - та так само як у двійковому дереві, ці елементи ділять простір пошуку на піддерева — але їх вже не два, а N+1. Відповідно, дерево стає “щільнішим”, вузлів в ньому стає менше, як і глибини.
А чому, власне, взагалі для пошуку беруть дерева, а не щось інше? Бо за деревом можна не тільки швидко шукати, а й швидко вносити зміни. (Швидко — це зі складністю O(log N).) Б-дерева саме й винайшли для прискорення пошуку у великих файлах. Причому з такою вимогою, щоб можна було завантажувати в памʼять лише частину дерева.
Б-дерева настільки прижилися, що зустрічаються майже в будь-якій базі даних. Їх можна знайти й у звичайних структурах даних різних мов - JavaScript, Go, Rust тощо. Трохи кумедно, що вони здаються складнішою структурою, втім насправді ми користуємося ними постійно — за лаштунками простих абстракцій.
23.12.2025
Що взагалі таке індекс у базі даних?
От кажу я — індекс той, індекс цей, з тим допомагає, з тим не допомагає, а що взагалі є індекс?
Дані в базі ніколи не розташовані в порядку, оптимальному для їхнього пошуку. Почнемо з того, що було б надто дорого впорядковувати дані після кожної зміни. А також, критеріїв пошуку може бути багато, а впорядкуємо ми лише під один. Та й це взагалі має сенс лише якщо записи мають рівний розмір… Одним словом, так ніхто (майже) не робить.
Натомість ми робимо індекси. Індекс — це структура даних, оптимізована для певного пошуку. Нічого магічного тут немає. 99% всіх індексів — двійкові дерева. Бо в них добре шукати за точним збігом та за порівнянням. Ключами в цьому дереві є значення, за якими ми індексуємо, а значеннями — певна фізична адреса відповідного запису.
(Тобто так, в кожного запису дійсно є адреса, за якою можна швидко його знайти без всякого індексу. Але вона нам ніяк не корисна.)
Окрім двійкових індексів, є й більш спеціалізовані — наприклад, геопросторові індекси, за якими можна швидко знайти місця за географічними координатами. Чи повнотекстовий індекс. Але це все суто винятки.
Або я писав про триграми - вони будуть у двійковому дереві, тільки побудованому за шматочками значень, а не цілими значеннями. Але все одно, інтуїція така, що індекс — це двійкове дерево за певним полем. (І тут стає питання, а що таке двійкове дерево?)
22.12.2025
Домашня панель
За вихідні (насправді, ранок неділі) навайбкодив собі домашню панель, як і збирався цього тижня. “Навайбкодив” в цьому разі значить — не писав код самостійно. Та навіть майже не перевіряв його. Чесно, на більше немає часу, а панель потрібна — зокрема, щоб розуміти, чи електрика йде з мережі або з резерву.
Отже, який в мене зараз підхід. Спочатку я десь параграфом пояснюю, що я взагалі хочу. Здійснюю невеличкий мозковий шторм. Та в кінці пишу - “зроби мені plan.md”. Агент генерує дуже довгий та детальний план, в якому, зокрема, будуть можливі питання або рішення. Відповідаю на них. Для того виділяю питання у файлі, надсилаю в чат, та коментую. Агент заміняє питання на відповіді.
Зрештою план доповнюється всілякими подробицями — які API використовувати, які вимоги до надійності, як робити UI тощо. Як план буде мене задовольняти — відкриваю новий чат та кажу “роби за plan.md”. Воно робить з першого разу вже дуже непогано.
Ну, а потім сиджу та послідовно покращую те, що бачу. Це для мене дуже нагадує роботу в парі: я кажу, що робити, а LLM робить. На кожну нову тему створюю новий чат.
В цьому проєкті відкрив пару нових для себе режимів роботи з агентом. В одній з інтеграцій для HomeAssistant був критичний для мене баг. Пощастило, що вже є PR з виправленням. Тож кидаю агенту адресу того PRу та кажу - “застосуй його до мого HomeAssistant!” Агент зміг підʼєднатися за SSH до машини з HA, знайти відповідні файли та застосувати зміни. І це суто вбудованими можливостями Cursor, без всяких MCP.
Другий випадок схожий: ця панель розгортується на локальну машину, де стоїть сервер Lighttpd. Я в ньому не знаюся зовсім. Тож доручив агенту згенерувати скрипт, а потім ще й розібратися, чому скрипт не працює. Він також за SSH зміг виявити, що в мого Lighttpd вимкнений mod_rewrite та увімкнути. А я дивлюся та розумію: я б тільки на цю проблему вбив вечір.
А ще ця панель і вебсокетами користується, і відновлює звʼязок після відключення, і має маленьку сторінку налаштувань. У проєктах-хобі, завдяки ШІ мрії здійснюються, та я цьому не припиняю радіти.
19.12.2025
Надсилання SMS через API: ось, що я дізнався
Для проєкту сповіщень про тривоги обрав сповіщення саме через SMS. По-перше, це не покладається на інтернет, якого частіше може не бути. По-друге, в айфоні можна зробити SMS з конкретного номера такими, що будуть давати сигнал навіть в тихому режимі. (Радий буду почути й ваші аргументи.)
Але я ніколи не займався надсиланням SMS серйозно, тож які тут знайшов можливості? Вимоги в мене трохи специфічні, бо я не планую надсилати понад 500 SMS на місяць, причому лише на 2-3 номери. Більшість сервісів орієнтовані на розсилки.
Пішов до найвідомішої компанії спочатку, тобто Twilio. (Це ті, кому належить Sendgrid, але починали вони з SMS.) Кредит їм вніс. Та тут виявилося, що SMS на українські номери тут коштує близько 50 грн. Ну якось забагато для хобі, що вам сказати. До того ж українських номерів вони не дають, хоча то вже справа друга, аби надсилали. Зате в Twilio є Go SDK.
Коли побачив ті ціни, знайшов українську альтернативу - TurboSMS. Тут вже близько 1 грн за SMS. Є HTTP API. В цілому, воно працює! Але: тут надсилання йде не з телефонного номера, а з іменованого відправника. Імена ці проходять реєстрацію в Національному реєстрі, то ж це ціла довга історія, яка мало зрозуміла для мого проєкту.
Щоб не реєструвати імʼя, можна скористатися одним з вбудованих: наприклад, InfoClub. (Це пояснює, чому я часто бачу сервісні SMS від різних сервісів, але з одного відправника. З 2FA так часто буває.) В цілому, робоче рішення, але зʼявилася інша проблема: айфон не дозволяє додати іменованого відправника в контакт. А значить, налаштувати завжди гучні сповіщення для нього не вийде.
Після того як зрозумів обмеження іменованого відправника, пішов шукати сервіси віртуальних телефонів. Такого теж багато! Поки опинився на Zadarma. Тут ти обираєш звичайний номер — як коли купуєш сімкартку. Потім цей номер стає доступним для отримання та здійснення дзвінків та SMS. Тут теж є HTTP API. Проте теж — перевірка документів перед тим, як віддадуть номер. Сподіваюся, за кілька днів відзвітую про остаточний успіх.
PS: а ще надсилання SMS всюди вимагає підтвердження особи — певно, щоб запобігти спаму.
18.12.2025
Redis - що воно таке?
Одним реченням: Redis - це сервіс оперативної памʼяті. Почекай, скажеш ти, а навіщо нам цілий сервіс для памʼяті? В нас вже є памʼять вдома.
Головною перевагою Redis над просто памʼяттю процесу є те, що це памʼять спільна, та тривала. Наприклад, вона переживе перезапуск вашої програми. Тобто дозволить уникнути холодного старту. А також заощадити, якщо всі процеси мають якийсь спільний стан. Звісно, насамперед Redis використовується для кешу.
Головною перевагою Redis над базою даних є те, що в Redis всі дані завжди знаходяться в оперативній памʼяті. Це дозволяє надати чіткі гарантії швидкості. Можна бути впевненим, що поки упрешся в навантаження, запити будуть завжди швидкими. Звісно, ця особливість також значить, що розмір Redis обмежується розміром памʼяті машини, тому Redis не універсальна база даних.
Очевидно, що доступ до Redis буде помітно повільніше за звичайну памʼять. Тому там є просто величезний API. Тут можна не просто читати та записувати значення, а брати готові рішення. Навіть для геоданих чи часових послідовностей. Та й вище згаданий кеш покладається на можливість встановити час спливу значень. (Це, мабуть, найперше, чим користуються.)
Якщо й всіх API мало, всередині Redis навіть можна виконувати скрипти на Lua! Та таким чином обійти ті обмеження повільного доступу — вибудувати з низькорівневих операцій власну бізнес-логіку.
Також Redis вміє зберігати власний стан на диск та навіть вести журнал для надійності. Головне памʼятати, що дані все одно повинні влазити в памʼять — це фундаментальна особливість.
Redis одна з моїх улюблених баз. Вона зрозуміла, швидка, та надійна. Та, принаймні у веброзробці — завжди десь поруч.
17.12.2025
Redis як спільна памʼять
Типово я звик бачити Redis як кеш чогось, ну або як нішеву базу даних (бо, знаєте, хоч Redis і тримає все в памʼяті, там є можливість зберігати зміст на диск.)
Але хочу звернути увагу на інше бачення: Redis є спільною оперативною памʼяттю між багатьма вашими процесами чи машинами.
Якось оця тема спільної памʼяті мало використовується. Ну так, в класичних вебзастосунках стану немає, а отже і в такій памʼяті потреби немає. Але на вебзастосунках світ не закінчується. Може ви гру пишете, чи чат, чи ще щось багатокористувацьке. Чи бота для месенджера.
Але й у вебзастосунках є стан. Класичний приклад: обмеження частоти запитів. В межах однієї машини його робити нема сенсу, зате лічильник можна покласти в Redis. Є навіть офіційний посібник.
Redis достатньо швидкий: лише на 1-2 порядки повільніше за звичайну оперативку, та, наприклад, на порядок швидше ніж локальний SSD. (Єдина порада - не складати в один запис надто багато. Краще, коли це буде окремий примітив чи невеличкий обʼєкт.)
Redis вже містить захист від рівночасного доступу, бо всі команди виконуються послідовно. Єдине, що має сенс поєднувати повʼязані команди у транзакцію (чи взагалі написати скрипт, бо й таке тут є.)
Може, у вас є сервіс, який спирається на внутрішній стан, та через це його ніяк не виходить масштабувати - або хоча б тримати в двох екземплярах для надійності. Redis прийде на допомогу.
16.12.2025
Як пошук LIKE взагалі може бути швидким?
Дивись, є в тебе запит: SELECT timestamp FROM logs WHERE message LIKE *failed*. Як можна реалізувати його в базі? (Повнотекстовий пошук поки взагалі забудемо, бо він ще складніший.)
Звичайні індекси за полем нам не допоможуть. Вони є деревом пошуку, та щоб пересуватися в цьому дереві, ми мусимо знати початок рядка. Тож якщо на початку зірочка, то база просто не знає, де до того індексу підступитися.
Та дійсно, навіть за наявністю індексу базі доведеться попросту перебирати всі значення. Звісно, що це буде… повільно. Втім, на допомогу нам прийде індекс за триграмами. (Ну, або N-грамами, узагальнено.)
Триграма — це шматочок тексту довжиною до 3 символів. Наше поле розрізаєaться на всі можливі шматочки:
request failed => r, re, req, e, eq, equ, ... led, ed, d
(Шматочки з одним та двома символами потрібні для коротких запитів. Хоча, скільки разів ти бачив “Для пошуку введіть хоча б 3 символи?” Тепер знаєш, чому.)
Тепер ми будуємо таке саме “традиційне” дерево пошуку, але вже для кожної триграми. Потім, пошуковий запит теж розрізається:
failed => fai, ail, ile, led
Ми шукаємо записи для кожної триграми окремо, а потім перетинаємо результати. Залишається тільки зробити зачистку, щоб прибрати небажані результати, наприклад, fai ail ile led - цей перебір займає вже зовсім трохи часу.
Такий механізм є не у всіх базах; його можна реалізувати й вручну, але тут багато залежить від того, як впорається база з поєднанням всіх цих результатів в один.
Зокрема, в ElasticSearch, де є надшвидкий пошук за багатьма критеріями, це взагалі працює чудово. Особливо якщо то поле має високу кардинальність, наприклад, як база імен — тоді замість довжелезного словника за іменем, де майже кожному імені відповідає лише один документ, буде компактний та ефективний словник за триграмами.
15.12.2025
Плани на решту грудня
Збираюся підготувати для сімʼї певну інформаційну панель. Хочу показувати графік відключень, стан резервного живлення, стан повітряних тривог. Все це у зручному вигляді.
Як екран використаю старий айпад. Взагалі старі планшети та телефони чудово служать інфопанелями — достатньо відкрити там браузер та завантажити свій зміст. Та, їх можна задешево знайти на eBay, якщо є така потреба.
Як технічну базу та сховище планую мати HomeAssistant. Він вже має певні готові інтеграції, а також історію, можливість надіслати сповіщення. Далі можу або написати власну інтеграцію — чого ніколи не робив — або може просто використовувати API
А тепер, найцікавіше. Інформація про розклад відключень та подробиці про тривоги публікується у вільному форматі — для людей. Є, наприклад, ось така сторінка справжнього графіка відключень. Яка, підозрюю, є джерелом істини. З тривогами ще цікавіше — моніторити канали щодо загроз вручну забирає час та вимотує.
Отже, моя ідея — залучити тут LLM. Наприклад, LLM легко здатна прочитати вище згадану сторінку та побудувати структурований в JSON чи iCal графік відключень для заданої групи. Повірте, я за своє життя не раз намагався зробити схожий парсер вручну — це нереально зробити повністю та важко зробити хоч якось. Це саме та задача, для яких існують нейронні мережі.
Ось так. Радий буду почути, якщо хтось вже робив щось схоже.

