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

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

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

14.11.2023

Неочевидні блокери

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

Але є підступніші блокери — такі, які не повʼязані напряму з предметом роботи.

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


13.11.2023

Виправлення випадкових помилок в інтеграційних тестах на Go

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

Очікування. Коли має справу з одночасним процесом, найбанальніша причина помилки — це те, що він не встиг доробити до очікуваного стану. Причому, як всі знають, в 99% випадків він, може, встигає, а на сотий раз — гальмує та валить CI. Щоб чекати, взяли модуль backoff - він трохи складніше ніж потрібно, але вже був в проєкті для інших потреб. Код попросту повторює перевірку, поки вона не справдиться.

🔍 Розуміння логіки. З одним з очікувань була інша проблема — ми чекали, поки не залишиться записів в проміжному стані. Інколи таке очікування не призводило до результату. Уважне вивчення документації виявило, що є інші проміжні стани, які ми не рахували (якщо просто, то перевіряли стан “активний”, але не стан “очікування”.)

🤹‍♂️ Перегони даних. Є в тестах такий сервер, який приймає посилання та складає в масив. Все б добре, але запис у масив не є безпечною одночасною операцією. Тож в рідкісному випадку, коли два посилання надходило одночасно, масив втрачав одне з них. Додаємо мьютекс та проблема зникає.

🐳 Залежності Docker. Нарешті, траплялось ще таке, що контейнер з сервером запускався раніше за Redis, намагався підʼєднатись та тут же ж виходив з помилкою. Звісно, траплялось рідко та зазвичай на CI. Не вистачало параметра depends_on.


12.11.2023

Альтернативи для QR-кодів

Чи можна ділитися посиланням якось окрім QR-коду?

Графічних кодів є багато різних, але вони всі мають один недолік: потрібний спеціальний додаток або інший читач. Я знайшов навіть таке дивне рішення під назвою SnapTag: сфотографувати код та надіслати світлину по СМС. Зрозуміло, така технологія не прижилась (а ще, зі Snapchat вони не мають ніякого звʼязку). Бо з нестандартних кодів, мабуть, найбільш відомий — це як раз коди Снапчату Snapcode. Але для поширення звичайного посилання вони не підійдуть.

А от справжня альтернатива - NFC-мітки. Це наліпка розміром десь від 20 мм з мікросхемкою всередині. Всі їх бачили на дорогих товарах в крамницях. Але в таку само мітку можна закодувати URL - місткість більш ніж достатня (100 символів та більше). Читаються NFC-мітки всіма сучасними смартфонами. Причому для читання достатньо піднести телефон на 10 см до мітки — не потрібно шукати вірний кут чи гарне освітлення. Якщо в мітці закодоване посилання, телефон його відкриє.

Щоправда, так люди робити ще не звикли. Можна спонукати їх інструкцією (або навіть наліпити зверху муляж QR-коду.) Та інша проблема — мітки треба програмувати. Програматор наразі коштує близько 1000 грн, а одна мітка — від 10 грн. Оскільки сама мітка малесенька, можна поєднувати її зі звичайною графічною наліпкою… або замовити друк наліпок з мітками, якщо знайти де.

Та інша сучасна альтернатива, до якої теж ще не всі звикли: просто надрукувати коротке посилання текстом. Сучасні смартфони здатні розпізнати текст камерою та відкрити посилання так само як і з QR-коду. (За досвідом, айфон хоч написаний від руки номер телефону зрозуміє.) Таке рішення мені подобається понад усе.


11.11.2023

QR коди: про зміст

Щоб вже закрити тему про QR коди: чи можемо ми впливати та, як зміст коду перетворюється на пікселі, тобто згенерувати інші пікселі?

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

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

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

Є цікава наукова робота про QR коди з напівтонами. Виглядають вони ефектно. Проте тут напівтони утворюються розбиттям клітин коду на пікселі — та для кожної клітини обирається найкращий рисунок. Такий підхід це майже те саме, що перетворити вхідне зображення на напівтон та додати до нього “центральні крапки”, про які я писав вчора. Я не впевнений, що складний алгоритм зі статті — який закінчується розвʼязком Марковського випадкового поля — щось додає.

Ще є коди-рамки, про які пише Вікіпедія. Це правильне, стандартне розв’язання задачі поєднання коду з графікою. Але їх не підтримують типові читачі. Хоча Frame QR існує вже девʼять років. Ну, сам QR код існує двадцять девʼять, так що колись підтримка зʼявиться.


10.11.2023

QR коди з зображенням на тлі

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

Чомусь по генерації QR класні бібліотеки написані на Python. Є qrcode, а є amazing-qr. Є ще CuteR, який краще поєднує код з зображення.


09.11.2023

Docker - це не система збірки

…Взагалі, вчорашні відкриття наштовхнули мене на наступний хід міркувань.

Раніше я дивився на Docker як на верхній рівень скриптів збірки. Тобто, щоб ми запускали docker build або docker compose, а все інше витікало звідти. А якщо так не виходить, то це погано, та треба докладати зусиль, щоб затягти всі аспекти збірки всередину Dockerfile. Наприклад, використовувати проміжні контейнери, монтування кешу, як я вчора писав, та інші засоби.

Але насправді, Dockerfile та docker buld не є гарною реалізацією системи збірки, тобто аналогом make, rake, чи просто скриптів оболонки.

Одним словом, відтепер буду використовувати Dockerfile тільки для створення образу з вже готових артефактів. Та нічого страшного, якщо docker build буде лише частиною більшого скрипту збірки.


08.11.2023

Пришвидшення збірки Go+Docker з 10 до 3 хвилин

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

Що не давало результатів: перенесення контейнерів баз даних з docker-compose в сервіси GitHub Actions: запуск триває однаково. Також кешування шарів Докера: щось на CI воно не гарно виходить.

А далі я помітив, що більшу частину збірки займала компіляція додатків на Go. Яка відбувалася як крок в Dockerfile. Зазвичай Go компілює досить швидко — але то завдяки кешу. Бо Go це така мова, де всі залежності збираються з коду під час кожної компіляції — а тимчасові результати зберігаються в кеш. Є кеш — тоді Go може обмежитись тільки файлами, що були змінені. Немає кешу — та всі наші залежності підлягають компіляції. Щоб зрозуміти обсяг роботи: кеш для нашого проєкту займає 600 Мб!

Проблема глибше: Dockerfile не має доступу ні до якого сталого кешу. Тобто є RUN –mount=type=cache, але такий кеш збережеться тільки між збірками на одній машині. Для CI це не допоможе. Втім, для локальної роботи вже добре.

Остаточним рішенням було винести компіляцію з Dockerfile та запускати окремою командою. Тобто спочатку make, потім docker compose up. Результати компіляції тепер просто монтуються до контейнерів.

З таким підходом компіляція використовує кеш, який легко переноситься між запусками CI. Насправді навіть стандартна дія actions/setup-go кешує (між запусками) кеш компіляції — тож робити її власноруч не потрібно. Єдина різниця, що трохи ускладнився скрипт запуску.


07.11.2023

Експорт даних з Reeder, та бази даних Realm

Мав задачу вивантажити зміст Reeder, в якому розташований мій список читання, а також закладки (а точніше, записи з “зірочками”). Вбудованої такої можливості немає — можна тільки експортувати список підписок в OPML, але це зовсім не те що мені потрібно. Отже, знайшов спосіб отримати доступ до бази даних програми, як вона є.

То виявилось несподівано просто, бо Reeder використовує базу даних Realm. У Realm є пакет NPM, тож мені залишилось тільки відкрити файл з базою, прочитати зміст та зберегти в JSON. Задача на пʼять хвилин. Ще є Realm Studio, але він дозволяє експорт тільки в форматі звʼязаного списку, що потребувало б подальшого перетворення.

Взагалі Realm - цікава база, яку я знаю доволі давно. Це одна з тих баз даних, які дозволяють зберігати дані локально, а вже потім синхронізувати. Тобто одна з можливих основ мобільного додатку, де важливе локальне зберігання. Цікаво, але в мене в macOS знайшлося тільки два додатки, які використовують Realm: це Reeder та… додаток Нової Пошти. Можливо, на телефоні їх знайшлося б більше, але взагалі не найпопулярніша технологія

Що знайшов зараз, чого раніше не бачив — це бібліотека IceCream для синхронізації Realm через CloudKit, тобто без впровадження додаткового сервісу синхронізації на платформах Apple.


06.11.2023

Як не дати AWS Cloudwatch себе пограбувати

Давно вже не писав про Cloudwatch, хоча продовжую ним користуватись принаймні щотижня. Попри наявність “брендових” альтернатив, мені до вподоби те, що пропонує AWS у своєму рішенні для збору журналів та метрик. Є тільки один нюанс: можна швидко влетіти на багато грошей. Як і з усім в AWS.

Найризиковішим, як на мене, є утворення власних метрик. У метрик є “виміри” (dimension) - щоб під одним імʼям збирати показники по різних ресурсах. Кожне значення виміру власної метрики сплачується як окрема метрика. А це вже відчутні $0.30 на місяць. Якщо обрати такий вимір, у якого багато значень — наприклад, ID акаунта в нашій системі — то недовго почати витрачати сотні доларів на таку нібито тривіальну потребу.

Окремо підступний вимір - ID задачі ECS, або її ж IP адреса: вони не є сталими, тож за місяць перезапусків та деплоїв можна теж назбирати вагомий рахунок. Якщо вже збирати статистику за задачами, потрібно спочатку винайти сталий ідентифікатор.

Зазначу, що вбудовані метрики AWS нічого не коштують. Це ті, які неможливо відключити. Бо трапляються ще “розширені” метрики — вони рахуються як власні.

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

Зате потім зайшов на сторінку цін DataDog та зрозумів, що в AWS не найбільш заплутана цінова політика.


05.11.2023

Amnesia: The Bunker та жанр "дослідницький хорор"

Закінчив на вихідних гру Amnesia: The Bunker, що вийшла цього року. Вона нагадала мені одну з моїх улюблених ігор - Subnautica. Я б сказав, що ці гри належать до піджанру жахів, який я називаю дослідницький хорор.

Ключовим аспектом дослідницького хорору є опанування оточення. Якщо в класичному хорорі метою є обхід рівня, пошук розвʼязка та просування далі, то в дослідницькому хорорі світ гри не змінюється від початку до кінця. Що змінюється, то це уявлення гравця про оточення, ризики та власні можливості.

Мета гри ставиться максимально широко — наприклад, “втекти”. Ігровий цикл являє собою експедицію - 1) спланувати вилазку з безпечного місця, 2) виконати вилазку, 3) повернутись в безпечне місце з результатами (ресурсами та знанням) та планувати знову. Замість звичайних для хорора “установок” (set piece), тут джерелом страху є постійно присутня загроза та особливо загроза втратити прогрес, бо збереження доступне тільки в безпечному місці.

🤿 Subnautica - це гра, що прикидається класичною пісочницею, але насправді є справжнім хорором, де головний противник — удушення. Бо весь процес гри відбувається під водою, де невпинно вибігає лічильник кисню. А ще є глибина та тиск та неприязна фауна… Якщо такий жанр цікавить, радив би зануритись у Subnautica без спойлерів та подарувати собі просто унікальний досвід дослідження морського світу від сонячного шельфу до тьмяних глибин.

Є ще продовження, Subnautica: Below Zero, але краще почати з першої, бо тут очевидно є припущення, що гравець вже знає що до чого та тому пропущений етап поступового знайомства з механізмами.

🪖 Amnesia: The Bunker так само складається з дослідження лабіринту темних підземних коридорів. Загроза тут банальніше — це бабай, який тебе зʼїсть… але реагує той бабай на галас, тобто ми вимушені бути якомога тихіше. Що не так просто, якщо навіть ліхтарик не світить без брязкучої динамо-машинки. Отже, доведеться балансувати між світлом, темрявою, тишею, гуркотом, та купою перешкод. Окремо мені подобається, що розробники рандомізують зміст, та навіть включили режим де ключові предмети розташовані випадково. Бо типова гра на дослідження — одноразова… далі хіба спідрани.

Які ще ігри з дослідницького хорору я знаю? В Minecraft можна так грати. В режимі виживання точно є ігровий цикл з експедиції за ресурсами вдень та відбудови бази вночі. Ще Dark Souls (перша частина) нагадує, оскільки там світ щільно повʼязаний, без телепортації по ньому доведеться багато разів побігати, а ціль ставиться туманно та її потрібно ще відшукати. (Та й перше проходження DS - неабиякий хорор.)