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

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

Підписатись на RSS · 📢 Канал в Telegram @stendap_sogodni

01.07.2024

Правильний формат адреси бази даних

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

postgresql://myhost.db:1234/mydb?pool=10

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

Інший раз бачу, параметр називається URL, а всередині пара host:port. Це небезпечно, бо така форма не є URL та призведе до помилки, якщо спробувати її розібрати. Інколи таку пару називають addr, бо вона позначає адресу TCP/IP… або позначала б, якщо замість імені хосту була IP-адреса. Ще є чудовий параметр-сюрприз endpoint. Ця назва взагалі нічого не каже про свій зміст.

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

Ще альтернатива: кожний елемент вказувати окремим параметром: host, port, username, password. Це може бути зручно, якщо хост приходить з Terraform, а пароль — зі сховища секретів. Але з інших боків зайві параметри тільки ускладнюють налаштування.


30.06.2024

Власні значки в стилях для Obsidian

В реалізації стилів для канви залишався недолік: для значків я був обмежений символами звичайного шрифту — що незручно ще до того, як згадати, що шрифт може змінюватись. Зміст значка в мене утворюється директивою CSS content. Пробував замінити його на SVG - не зміг редагувати колір того SVG (в межах CSS).

Сьогодні розвʼязав цю задачу остаточно. По-перше, знайомтеся, Nerd Fonts. Це шрифт, в якому зібрано 10 тисяч (!) значків з різних відкритих наборів. Шрифт мене влаштовує краще, ніж SVG, бо з ним можна працювати як зі звичайним текстом. Але тепер, як додати його прямо у CSS?

Виявляється, CSS вміє завантажувати шрифти з data URL. Може, то й очевидно, але я з data URL стикався тільки для зображень. А тут можна отак:

@font-face {
  font-family: "Nerd Fonts Symbols Embedded";
  src: url(data:application/font-woff2;base64,d09... ще мільйон символів);
}

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

Нарешті, останній момент: щоб використати той значок в CSS, треба писати щось на кшталт content: "\f128"; код символу береться з каталогу. (Або тягнути вбудований CSS Nerd Fonts, але мені то заради пʼяти значків занадто. До речі… сам шрифт пізніше теж можна було б підрізати точно під потребу.)


29.06.2024

Стохастичний таймтрекер та робота

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

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

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

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

В минулому я тегував час за субпродуктом та категорією активності (програмування, пошук помилки, комунікація, …) Категорія активності це корисно, субпродукт — не настільки; було б краще тегувати за епіком (навіть напряму — кодом задачі.) В наступному місяці спробую, бо повинно вийти дуже наочно. Також спробую розділяти активності за обовʼязками (наприклад, комунікація — це може бути допомога, чи навпаки пошук допомоги, чи дискусія тощо)

Цікаво побачити, скільки часу уходить на побічні активності; обовʼязки як перегляд PRів здаються такими що відбирають багато часу, але на практиці витрати мінімальні. Хоча це нічого не каже про ментальне навантаження — можливо, в майбутньому почну відстежувати і його рівень.


28.06.2024

Зачистка AWS Parameter Store (та магія jq)

Чудова пʼятнична забава: знайти неавтоматизовані параметри в AWS Parameter Store. В ідеалі, все повинно потрапляти туди через Terraform або іншу автоматику, але ж неодмінно деякі дані протікають вручну.

Очевидно, що вручну я того робити не буду: параметрів за тисячу, це просто нереально. Та також не потрібно. Список параметрів можна отримати через CLI:

aws ssm get-parameters-by-path --path '/' --recursive | jq -r '.Parameters[].Name | sort'

Тут окрім самого AWS CLI використовується утиліта jq. Вона виконує складні перетворення JSON в один рядок; тут ми беремо атрибут Parameters, який є масивом, а з його елементів беремо атрибут Name.

…Тепер за Terraform. Спочатку я хотів шукати кожне імʼя параметра вручну… проте це ще гірше, бо імʼя може конструюватися з відрізків, повторюватись і таке інше. Зате всі параметри сидять в стані. Тобто достатньо стягнути стан та (оскільки це теж JSON) забрати те, що потрібно:

terraform state pull | jq -r '.resources[] | select(.type=="aws_ssm_parameter") | .instances[].attributes.name | sort'

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

Залишається тільки порівняти дані командою diff та результат готовий! На жаль, не так легко з’ясувати, які з параметрів дійсно потрібні, а які зайві… зате потім можна згенерувати за шаблоном файл Terraform чи навіть вхідний файл 1Password для секретів.


27.06.2024

Split_tests - швидші збірки на CI

Є в мене стара, але досі корисна утиліта: split_tests. Вона, попросту, розбиває довжелезний запуск тестів на декілька паралельних потоків, за набором файлів. Так збірку довжиною в годину можна виконати навіть за 10 хвилин. (На жаль, підготовка до тестів теж займає час, тому є розумна межа на кількість потоків.)

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

(🦀 Як каже аксіома, до моєї реалізації на Go є реалізація з альтернативного всесвіту на Rust: split-test. Ні, серйозно!)

Колись давно я написав цю утиліту для CircleCI. А потім невдовзі там зʼявилася вбудована команда, яка робить те саме. Потім я опинився на GitHub Actions, та утиліта знову стала до нагоди — альтернатив тут немає, а ті що є, написані або на основі моєї утиліти, або схожих.

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

Або, можна знайти аномалії вручну та викликати їх окремо. Оце на мою думку оптимальний варіант. І технічно просто, і результат надійний. Зазвичай ті “аномалії” виявляються величезними інтеграційними тестами та їх в застосунку лише декілька.


26.06.2024

Статусні коди SMTP в порівнянні з HTTP

У SMTP, як і HTTP, сервер відповідає статусним рядком, який складається з коду та розшифровки. (Хоч на відміну від HTTP, SMTP - це діалоговий протокол, але діалог закінчується статусом.) Ніби все дуже красиво, багато цифр та взагалі все зрозуміло:

421 4.7.0 [TSS04] Messages from a.b.c.d temporarily deferred due to user complaints

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

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

Навіть на сторінці Вікіпедії про ці статуси наведені їхні приклади, а не перелік. Максимум, на що можна розраховувати — це те, що статус 4xx тимчасовий (тобто варто спробувати пізніше), а 5xx постійний. Але це не допоможе зрозуміти, чи нам потрібно відписати адресата, чи виправляти зміст листа, чи щось інше.

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

Але є й позитивна сторона: популярних серверів SMTP не так багато, тому цілком реально покрити їхні відповіді зі впевненістю. Навіть GMail один покриє десь третину всієї пошти. Виходить парадоксальна ситуація: хоч можливих статусів необмежено багато, але уваги потребує небагато (так, як статус TSS04 від Yahoo.)


25.06.2024

10 годин зачистки Jira

Весь день провів за зачисткою Jira. Це частина того, що потрібно було зробити для “чистоти думок” за GTD. (На роботі ще залишилися декілька PRів, які давно висять, та декілька десятків незавершених гілок — це в мене часта ситуація.)

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

Про місце для ідей команди я ще буду думати, але поки на особистому рівні я перебирав всі задачі, до яких маю відношення, та переносив у власну канву “мабуть/колись” з належним групуванням. Також багато задач було скасовано. А декілька навіть вдалося виконати “на ходу”, бо звісно ж задачі на 10 хвилин можуть роками сидіти в беклозі без уваги.

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

До речі, мені зрозуміло, що таку зачистку потрібно робити частіше, напевно, раз на ітерацію. Коли один раз все зачистив, далі можна додати до пошукового запиту обмеження на updated та передивлятися тільки нове. (До речі, Jira - це база даних, та знання пошукових запитів допомагає змусити її працювати на тебе.) Потім можна експортувати результати запиту в CSV та робити з ним вже все що завгодно. Я, наприклад, генерую список, розбитий по статусах.


24.06.2024

Перевірка "тільки один" в Rails

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

validates :default, uniqueness: { if: :default }

Ну, бо просто унікальність не дала б створити більш ніж один “звичайний” запис. А так все працює (та проходить тести, які я написав заздалегідь.) До речі, хоч ми користуємось Shoulda Matchers (давно вже не бачив проєкту без них), але в цьому разі писав перевірку без них. Бо Shoulda Matchers зазвичай повторюють означення валідатора, а я ще його не знав. Міг тільки описати поведінку. Тобто це такий класичний приклад для TDD: коли краще знаєш, що повинно вийти, а не що потрібно зробити.

Якщо поміркувати, таку валідацію можна перенести й в базу:

CREATE UNIQUE INDEX only_one_default WHERE default

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


23.06.2024

Вам потрібна надійна система "мабуть/колись"

В останній (та поки досить успішної) ітерації самоменеджменту в мене зʼявився новий елемент: надійна та зручна система для зберігання справ на майбутнє, тобто того, що в GTD називається “мабуть/колись”. В мене це Obsidian та канва, але міг би бути якийсь Notion або навіть кращі спеціалізовані рішення, як DEVONthink.

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

Наприклад: думка “зробить в шафці відділ для робота-пилосмока”. Це схоже на проєкт, та раніше всі такі ідеї в мене ставали проєктами. Принаймні, не загубиться. Але… насправді навіть шафки ще не існує, тому такий проєкт буде висіти без шляху розвʼязання. …А коли незрозумілих проєктів стане 100, система розчавиться під власною вагою.

З системою “мабуть/колись” така ідея йде в купу ідей навколо проєктування шафки. Потім, коли справа дійде до планування, всі такі ідеї можна зібрати до купи та перетворити на конкретний план дій. (Та вже на цьому етапі зрозуміти, чи той відділ взагалі потрібний, чи буде для нього місце і так далі.)

“Мабуть/колись” має фрактальний характер: більша ідея розкладається на менші (шафка сидить в купі ідей про кімнату, кімната — в купі про оселю). Десь я матиму уявлення до дрібних деталей, а в інших місцях тільки малюнок широкими штрихами. Наперед невідомо, якого рівня буде кожна ідея, тому зручно, якщо система організації підтримує таку фрактальність. Причому треба бути готовим записувати думки будь-якого рівня: щоб вони не сиділи в голові. Від “нам потрібна інша база даних” до “додати підказку до поля у формі.”

Також не можна звалювати все до купи: як-то список закладок або беклог в Jira. Ідеї повинні групуватися за змістом, щоб знайти їх в майбутньому. Це, напевно, головний аспект: коли ти додаєш думку в “мабуть/колись”, маєш бути впевненим, що повернешся до неї тоді, коли це буде актуально. Тоді можна дійсно розвантажити голову від гадок на майбутнє та сфокусуватися на поточних проєктах.


22.06.2024

Obsidian: канва у список

Зробив скриптець для перетворення канви Obsidian у список Markdown. На диво, готової альтернативи не знайшов.

Скрипт спирається на звʼязки між вузлами, щоб обійти граф та побудувати дерево від кореня: вузла, на який ніхто не посилається. (Або — коренів.) На виході отримуємо список в Markdown.

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

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