Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
22.10.2023
Як НЕ користуватись Докером для розробки
Як писав, розробка в Docker мене все ще не влаштовує. Втім, я перейшов на macOS саме для того, щоб працювала більшість потрібних для роботи програм (бо до того колись дуже давно був Windows+VirtualBox.) Та й дійсно, в більшості випадків потреби в Docker в мене немає. Ізолювати оточення проєктів та керувати флотом процесів допомагають наступні інструменти:
-
direnv - налаштовує оточення термінала в залежності від поточного розташування. Абсолютно незамінна річ. Є схожі рішення, які будуть вбудовані в додатки (dotenv одне з популярних), але
direnvпрацює на рівні оболонки, тому його оточення підхоплюється всіма можливими інструментами (навіть для VSCode є доповнення). Рекомендую звернути увагу на функції PATH_add та layout. -
asdf - універсальний менеджер версій — дозволяє мати декілька версій інтерпретатора та перемикатися між ними. Давно замінив для мене rvm, rbenv, nvm, і так далі. Бо має плагіни практично на всі інтерпретатори, компілятори та інші програми. Наприклад, Hugo, Golangci-lint, та Terraform. Це вкрай важливо, коли працюєш з багатьма проєктами.
-
Foreman - дозволяє запустити декілька сервісів однією командою та в одному терміналі. Тобто це такий “бюджетний аналог” Docker Compose. Підійде, вам потрібно запускати одночасно додаток, чергу задач, вебпак, базу даних і все інше. До речі, я б радив замість Foreman встановити Goreman - клон на Go - бо він не потребує Ruby. Обидві утиліти доступні через Homebrew.
-
Як щодо баз даних та інших сервісів, до яких не потрібно постійно доторкатись, то я б насправді радив запускати їх в Docker. Хоча для базового функціонала є Postgres.app, а Redis або MongoDB або ще щось інше можна встановити з Homebrew, та ще й зробити сервісом, який запущений завжди.
21.10.2023
Як працює механізм прихованої копії BCC
Механізм “прихованої копії” є найбільш неочевидним з усіх стандартних поштових функцій. Та заголовок Bcc: дійсно є стандартним, бо він визначений ще в стандарті поштових повідомлень RFC 822. Ба більше, він був згаданий ще у RFC 680 1975 року. Всі їм користувались, але як воно працює? Як лист опиняється у прихованого отримувача, коли в листі немає про нього ніяких згадок?
Тут важливо розуміти, що лист доставляється за протоколом SMTP, а протокол SMTP взагалі не цікавиться змістом листа, зокрема його заголовками. Для доставлення пошти є адреси конверта, про які я вже писав. Технічно, вони можуть і не сходитися з адресами в заголовках, та це дійсно трапляється на практиці (наприклад, якщо сервер будує зворотну адресу для сервісної комунікації.)
Коли ти відправляєш листа по SMTP, то ніякого Bcc: взагалі не потрібно, бо можна просто вказати потрібну адресу (чи декілька) в команді SMTP RCPT TO. (До речі, протокол SMTP був вперше стандартизований у RFC 788 у 1981, тобто вже після того, як придумали заголовки та Bcc:.)
Тому Bcc: обробляється ще до надсилання повідомлення, на рівні поштового клієнта. Фактично, так само як і заголовки To: та Cc:, він містить інструкції для поштового клієнта, а саме, ті адреси, які потраплять на початковий “конверт”, тобто в команди RCPT TO, які клієнт надішле на SMTP сервер.
Відповідно, коли лист надходить на будь-який сервер SMTP, наприклад, у Мейлтрап, або будь-який інший сервер, навіть якщо це локальний Mailcatcher, то ніякого заголовка Bcc: в листі вже не має бути, а якщо є — це помилка клієнта. Натомість в Mailtrap можна буде побачити адресу Bcc в розділі “SMTP Transaction Info”. Так можна перевірити, що доставлення прихованої копії відбулося.
20.10.2023
Формат поштових відправлень (message/rfc822)
Останнім часом доводиться складати чимало поштових повідомлень вручну. Чому вручну? Бо так можна досягти більш компактного, мінімального змісту, порівняно з автоматичними засобами (наприклад, чудовим пакетом для Ruby mail.)
Цікаво, що цей формат, так само як HTTP, був очевидно розроблений для можливості ручного авторства, але згодом нашарування абстракцій витіснило його з колективної свідомості. Хоча, формат повідомлень SMTP та HTTP суттєво простіше, ніж, наприклад, HTML. Навіть коли доходить до повідомлень з декількома частинами (multipart).
Перше, що треба знати: повідомлення складається з заголовків та тіла. Між ними завжди стоїть порожній рядок. Заголовки в форматі Header-Name: value, мабуть, найбільш відома частина повідомлення. Менш відомо, що заголовок може містити декілька рядків; додаткові рядки значення починаються просто з табуляції.
Тіло повідомлення складається просто з тексту. На цей час текст може містити будь-які символи, в тому числі UTF, з цим проблем немає. Але якщо тіло двійкове — воно обовʼязково кодується, зазвичай в Base64. Це на відміну від HTTP, де в тілі дозволено відправляти двійкові дані.
Зокрема це потрібно тому, що двійкові дані зазвичай не будуть всім тілом повідомлення, а лише його частиною. Текст тіла в такому випадку можна прочитати як декілька частин — отже, ніяких двійкових даних всередині бути не може. Частини розділяються спеціальними рядками та також мають закінчуватись трохи іншим рядком. Кожна частина має свої заголовки та своє тіло… яке в деяких випадках може теж складатись з частин.
Ось мінімальний, але повний приклад повідомлення з двома частинами:
Content-Type: multipart/mixed;
boundary=demo
--demo
Content-Type: text/plain
Hello, Text!
--demo
Content-Type: text/html
<p>Hello, HTML!</p>
--demo--
Як бачите, ніякої магії, якщо розібратись.
19.10.2023
One Sec - програма для припинення відволікань
Як я колись писав, особливо підступними є рефлекторні відволікання. Тобто такі, що виникають несвідомо в той час, коли ти маєш займатись чимось іншим.
Знайшов по рекомендації програму One Sec. Вона блокує відволікання особливо винахідливим чином. А саме, запрошує почекати декілька секунд перед відкриттям тих ресурсів, які ти відзначиш як відволікання.
Для мене це ефективніше ніж повне блокування тому, що багато ресурсів не є однозначно поганими - Reddit, YouTube, Twitter є корисними джерелами інформації, але в той час є й засобом відволікань. Наявність паузи дозволяє зупинитись та усвідомити свою дію.
Працює One Sec на iOS та на macOS, для додатків та для сайтів. Як можна здогадатись, механізм переривання не завжди реагує ідеально. На iOS він використовує Shortcuts та деколи має затримку на пару секунд. На macOS зʼявляється окреме вікно блокувальника, яке я декілька разів ненавмисно закривав; тоді One Sec просто припиняв роботу. (Лайфхак: через BetterTouchTool можна призначити комбінації Cmd+Q порожню дію в межах цього додатка, тоді його не можна буде закрити.)
Проте насправді задачу свою One Sec виконує повністю, попри ці перешкоди. Смішно помічати за собою несвідомі реакції; в перший день використання я навіть встиг зазирнути в телефон та побачити екран паузи, поки чекав, щоб минули ті пʼять секунд на компʼютері. І сміх, і гріх. Приємно звільнятись від таких рефлексів.
One Sec наразі ще й безплатна “бо настав час думскролінга”, як пише автор.
18.10.2023
Профілювання проблемної ситуації з Go
Поступила скарга: наш сервіс на Go, локально запущений в Докері, призводить до постійного споживання CPU, навіть коли нічого не робить. Що сталося? Чи це Докер винний? Така задача розвʼязується профайлером.
По-перше, сам Docker командою docker top вкаже, що CPU споживає нібито сам процес сервісу. Та й пояснення від найпростішого вказує туди ж.
Щоб зрозуміти, що робить сервіс, підключаємо профайлер. В такій ситуації — на всю програму разом. Для цього в Go достатньо додати три рядки на початок функції main():
f, _ := os.Create("/mnt/tmp/service.prof")
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
Це автоматично покриє весь код, включаючи горутіни. Компілюємо, запускаємо контейнер з сервісом, чекаємо пару хвилин та зупиняємо. Це згенерує профіль та збереже його в файл (в Докері зручно буде, якщо файл помістити в директорію, що примонтована — бо тоді відразу можна з тим файлом працювати.)
Далі можна слідувати офіційному посібнику. Я раджу не блукати в консольних командах профайлера, а відкривати вебверсію (команда web). Відразу бачу, що більшість часу програма витрачає на компонент, який оновлює деякий кеш. Ну трохи дивно, але має сенс, бо він це робить за графіком, а не “ліниво”.
Дивлюся на період оновлення… він береться з конфігураційного файлу та локально дорівнює 10000000. З першого погляду взагалі схоже на налаштування “ніколи не оновлювати”. Але то зважаючи на те, в яких це одиницях. По коду виходить, що це значення читається як time.Duration, а Duration вимірюється не в мілі- та не в мікро-, а в наносекундах. Тож цей астрономічний на вигляд період насправді дорівнює лише одній сотій секунди! Виходить, що цей компонент практично не припиняв працювати — звідси й витрати CPU.
От заради таких ситуацій треба бути готовим взяти в руки профайлер.
17.10.2023
Нова система. Homebrew Cask. Dev containers
Сьогодні налаштовував новий компʼютер для роботи. Це мій перший компʼютер “тільки для роботи” років за… пʼятнадцять, напевно. Як писав, це для того, щоб на роботі було менше відволікань, а з іншого боку — можна було фізично припинити працювати та все ж не залишитись без компʼютера як засобу для спілкування, хобі та розваг. (Мініогляд: обрав Mac Mini, бо давно було цікаво, але ніколи раніше не було підстави його мати. Це найнудніший з маків — просто коробка з macOS. Він більше та важче, ніж я уявляв — майже з Macbook Air завширшки. Зате блоку живлення немає — тільки тонесенький кабель. Ось… більше немає що про нього казати.)
Вперше спробував Homebrew Cask та я в захваті. Це доповнення для встановлення звичайних додатків через Homebrew. Без перебільшень, всі програми, які мені були потрібні, вдалося там знайти. Тобто замість пошуків на сайтах, завантаження і так далі можна просто зробити brew install visual-studio-code firefox setapp і так далі. Ба більше, так само можна встановити й шрифти. Єдине, що я встановлював не через Cask - це додатки з Setapp (в ідеалі вони б теж могли мати CLI, але поки не бачу.)
Для того, щоб почати використовувати Homebrew Cask, не потрібно перевстановлювати систему, тож раджу випробувати — воно того варте.
Друге, що випробував — це Development containers, відносно новий механізм для розробки прямо в Докері. Пропозиція така: не потрібно буде нічого встановлювати локально, тільки Docker та Visual Studio Code. Все інше — в контейнері. Причому робоча частина VSCode теж працюватиме з контейнера та матиме доступ до всіх інструментів.
Так розвʼязуються дві задачі. Перша — уникнути складного налаштування середовища на локальній машині (але це більш актуально для Windows.) Друга — надати можливість поділитися середовищем з командою. Тут допоможуть такі функції, як Features - типу “пакети” з утилітами, та можливість вказати, які доповнення VSCode встановити в контейнері. В теорії, все це значить, що від клонування репозиторію до повноцінної розробки у нового члена команди буде достатньо відкрити VSCode та почекати, поки все розгорнеться.
Зазначу, що dev container - це не те ж саме, що конфігурація docker compose для локального запуску додатка. Dev container утворює середовище для запуску будь-яких команд в проєкті — від сервера чи тестів до лінтерів, Git та, звісно, самого VSCode. Dev container спирається на Docker Compose, наприклад, щоб створити бази даних та інші потрібні сервіси.
Це все добре, але насправді девконтейнер в мене не прижився через відсутність інтеграції з 1Password CLI. Так, технічно встановити CLI в контейнер можна. Але з точки зору 1Password це буде окремий компʼютер. Нормального способу передавати секрети в контейнер я не знайшов. (Наприклад, передавати в змінних оточення на весь час існування контейнера мене не влаштовує.) Можливо, якісь обхідні шляхи можна було знайти, але не настільки ті девконтейнери мені зараз потрібні.
16.10.2023
Глибший погляд в метаданні файлів в Obsidian
Таке тут знайшов… Дивився на зміст структури CachedMetadata заради frontmatter, щоб знайти там jiraQuery. А знайшов, що Obsidian надає доступ до структурного змісту документів.
Виходить, що вся моя праця з парсером Markdown була зайвою. Бо Obsidian і сам знаходить всі пункти списків, які є в документі, а також маркер задачі, якщо пункт такий має. І дані по вкладеності. А також всі заголовки та внутрішні посилання.
Для кожного з елементів зберігається діапазон, який він займає в тексті. Так можна не тільки отримати зміст елемента, а й вхопити відповідність між елементами різних типів — бо синтаксичного дерева тут як раз немає; є тільки перелік елементів кожного типу. Наприклад, за вкладеністю діапазонів можна зрозуміти, під яким заголовком знаходиться задача. Або, перевірити, чи є в тексті задачі посилання на інший документ - щоб вкласти його.
Мабуть, деякий розбір все ж доведеться робити (наприклад, Obsidian нічого не знає про мої маркери дат.) Але тут можна або обійтися регулярними виразами, або принаймні розбирати Markdown в межах тексту конкретної задачі.
Одним словом, якщо хочеться зробити плагін для Obsidian, який буде робити щось цікаве зі структурою документа, то це може виявитись простіше, ніж ти думаєш.
15.10.2023
Глибоке прибирання в Jira
Як я писав, Jira рідкісний комбайн у світі менеджерів задач. Та, якщо взяти за аксіому, що ніхто не любить програми для організації задач, то принаймні Jira дає потужні механізми для їх впорядкування.
Сьогодні накрутив базовий механізм відображення задач з Jira в Obsidian. Як і планував, запит до Jira у вигляді JQL сидить в метаданих до документа. Це надає можливість будувати не один, а скільки потрібно списків задач. Окрім банального списку поточних задач, через JQL можна побудувати списки проблемних задач, які потребують уваги. Наприклад: задачі, які мають змерджений PR, але чомусь не були закриті:
(assignee=currentUser() or creator=currentUser()) and development[pullrequests].all>0 and development[pullrequests].open=0 and status not in (closed, cancelled)
Мабуть, в кожного свій перелік проблем, тому й зручно мати JQL, який можна підстроїти під себе. З екрана пошуку через JQL можна відразу перейти до масового редагування, щоб, наприклад, перевести всі готові задачі в правильний стан.
Робити пакетні зміни через Obsidian немає сенсу, а от пакетне створення задач, мабуть, так. Мене завжди дратує вносити багато задач в Jira - до кожної доводиться вказувати ті самі атрибути (власника, наприклад). Приємніше підготувати список задач в Markdown, а потім імпортувати (причому проставити автоматично проставити однакові атрибути). Зокрема, так поки плануєш список, можна повертатись до попередніх задач, якщо несподівано змінюється розуміння. Прямо в Jira переробляти вже створені задачі завжди біль.
Так що наступним чином спробую зробити імпортувальник нових задач з Obsidian в Jira.
14.10.2023
Інтеграція Jira в Obsidian
Не любити Jira - це таке кліше, що навіть не знаю, чи є люди, котрим вона подобається. На мою думку, тут немає провини конкретно Джіри. Проблема, в моїх очах, в тому, що це інструмент для комунікації, а не організації особистих задач. Jira має бути всім для всіх, та через це безповоротно втрачає простоту та прямолінійність, особливо для посади розробника, якому від Джіри потрібний тільки список особистих задач.
Відповідь в тому, щоб робити цей список задач поза межами Джіри (або іншого командного тасктрекера). Я, власне, так і роблю, але синхронізація власноруч не розвʼязує задачу повноцінно та головне, вчасно. В минулому я намагався побороти Джіру через її інтеграцію в VS Code, проте чого там не вистачало — це простого додавання та редагування задач.
Проте, якщо потрібно тільки створити список задач на основі Джіри, то можу порадити доповнення Obsidian Agile Task Notes. Тільки мені того не вистачає (та чи здатний я обминути нагоду зробити інтеграцію власноруч?) Тому роблю своє. Хочу на 95% працювати з Jira тільки через Obsidian - в тому числі редагувати.
Поки розповім про дизайн. По-перше, весь сенс існування такого інструменту — це зведення Jira до мінімального потрібного інтерфейсу. Власне витягнути список задач та відобразити його у Markdown - зрозуміло як. З обовʼязкових полів — тільки код задачі — але також, мабуть, треба бачити назву та статус. Причому статус має передаватись як маркер списку, а значить, необхідно спочатку задати переклад статусів з Jira в маркери — бо в кожному проєкті статуси свої.
Звідки задачі брати? На моєму досвіді, краще залишити це на волю користувача та запросити вказати запит JQL для отримання списку. Списків буде більше одного — як я це робив у VS Code. Тому напевно цей запит має бути в метаданих документа; тоді можна скористатись API Obsidian для пошуку всіх документів, в яких встановлений потрібний ключ метаданих, щоб оновлювати в них списки задач.
Як створювати задачі? Логічно, що якщо додаєш в список в Obsidian новий пункт, то він має зʼявитись в Jira. Створити задачу просто, якщо знаєш всі її атрибути (це не тільки назва, але й принаймні проєкт, епік, власник). Що робити, щоб не питати все це кожного разу (окрім, зрозуміло, назви?) Можна прямо в тих самих метаданих поруч з запитом для наповнення списку вказувати набір атрибутів, що будуть призначені новим задачам.
Як редагувати задачі? Тут головна функція — це зміна статусу; далі редагування назви та нотаток. (При проєктуванні треба памʼятати, що для менш частих задач завжди можна скористатися Джірою напряму; а нам важливо не перевантажити інтерфейс.) Зміна статусу — знов через маркери задачі. Редагування назви — хочеться вірити, що вийде (бо щоб отримати назву, доведеться очистити рядок задачі в Markdown від номера задачі та інших атрибутів.) Нотатки — треба дивитись; можливо, вийде розташовувати нотатки як вкладений в задачу зміст Markdown, але це не точно.
Далі буде.
13.10.2023
Огляд навушників JLab JBuds Mini
Отримав навушники JLab JBuds Mini. Їх фішка в тому, що вони надзвичайно малі. Як то кажуть, якби були менші, то митниця б не пропустила як шпигунський інструмент (жартую). Анонс JBuds Mini я побачив в новинах ще минулого року, та вони настільки мені сподобались, що я навіть встановив Google Alert, щоб не пропустити їх випуск.
Як бачите, кейс навушників має розмір та форму великого волоського горіха. Довга сторона приблизно як в кейсу AirPods Pro коротка. А в мене до того були Beats Fit Pro, в яких кейс взагалі дуже великий. (Мікроогляд: BFP це спортивна версія AirPods Pro з ідентичною начинкою, тільки краще сидять та мають фізичну кнопку. Але, наскільки я знаю, в них гірші мікрофони.) JBuds Mini брав саме тому, що їх легше таскати з собою всюди.
Самі навушники теж надзвичайно малі та повністю ховаються в вусі. Мають кнопки — сенсорні, тобто вони не натискаються. Що не дуже зручно, особливо через розмір. Проте функції кнопок повністю налаштовуються. Взагалі, розмір JBuds Mini робить їх менш зручними, бо вхопитися за них не так легко, і відкривати кейс так само. Ну, тут що хотів, то й отримав — нарікань немає. Заряд тримають добре, видно що вистачить на декілька годин. Пластик приємний.
Базова якість звука десь на рівні Beats Fit Pro, тобто цілком непогано для навушників-затичок, особливо при ціні в $40. Звісно, немає тут ніякого обʼємного звуку, шумозаглушення, голосового виклику Siri, а підключення до пристроїв має форму звичайного Bluetooth Multipoint.
Окремо виділю, що функція “прозорості” є; працює вона трохи дурніше, ніж у BFP, бо утворює більше білого шуму — що помітно, якщо в навушниках нічого не грає. Втім, підійде, щоб поговорити з баристою чи бути уважним на вулиці.
Хороші навушники, щоб носити на ключах або не прибирати з рюкзака.

