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

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

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

10.07.2025

Спроби закинути зміст з macOS на iOS

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

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

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

Швидкий пошук знайшов програму Any Text. Вона вміє те, що я хочу: текст входить на ноутбуці, виходить на телефоні. Якщо вставляти текст вручну. Але як це робити з коду? На жаль, можливості немає — бо єдиний спосіб автоматизації тут це Shortcuts, а вони не доступні програмно. Було б краще, якби був AppleScript, але то зараз не модно впроваджувати.

Так само й Drafts все вміють, окрім отримати текст. Drafts мають дуже багато функцій для вивантаження тексту — аж навіть скрипти на TypeScript можна писати — але не дають програмно оновити зміст нотатки. Тобто це “віяло назовні”, а не “віяло всередину”.

Є ще Apple Notes… тут можна оновити зміст нотатки через AppleScript! (До речі, для того у Swift є фреймворк NSAppleScript.) Майже перемога! Наступний квест: стикнувся, що мій застосунок не може просто керувати іншим застосунком — на то потрібний дозвіл. Дозвіл буде запитано автоматично… проте тільки якщо вірно заповнити Info.plist та entitlements. Оце коли всі ці секрети доробив, то нарешті отримав оновлену нотатку. Успіх!

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


09.07.2025

GitHub API з GitHub Actions

Є у нас ситуація, де на GA треба обчислити diff між двома комітами. Причому вони можуть бути на абсолютно різних гілках. Як це було зробити ефективно?

Зазвичай на GitHub Actions всі використовують actions/checkout, щоб витягнути зміст репозиторію. Втім, нормально ця дія витягує тільки останній коміт (тобто глибину 1.) Бо це рятує дорогоцінні секунди. Втім, з такою глибиною цей diff ніяк не зробиш.

Можна витягнути й весь зміст — якщо передати в actions/checkout параметр fetch-depth: 0. Це задачу розвʼязує, але ціною… наразі 15 секунд очікувань. Чи можна зробити якось швидше?

Звісно. можна! Згадаймо, що в GitHub є API. А в ньому, зокрема, є й порівняння комітів. Ми користуємось цією можливістю кожен раз, як створюємо PR - але так само можна зробити й зі скрипту на CI.

Щодо доступу: в задачі GitHub Actions завжди є токен для API - він сидить в secrets.GITHUB_TOKEN. Ось тут більше про його права, але на перегляд репозиторію права точно будуть.

Отже, замість операцій з Git роблю виклик GitHub API, та отримую на виході JSON, в якому зокрема є ключ .files, де перелічені всі файли зі змінами. Та ще на відміну від Git, не треба парсити ніякі цікаві формати. Береш jq та готуєш такий результат, який потрібний.

В результаті — замість 15 секунд ну може 1-2. Дрібниця, але важлива.


08.07.2025

Очищення жорсткого диска

Знаєте як, скільки б не був диск, завжди забивається. Особливо коли на ньому є XCode, бо там не встигнеш озирнутися як в тебе вже 5 версій симулятора по 10 Гб кожна.

CleanMyMac мені серйозно не подобається за агресивний маркетинг (підписатися на розсилку? пане, я й так вже його завантажив через ваш же ж Setapp.) Але справу видалення зайвих файлів він виконує дійсно вправно. Зокрема, вичистити всі непотрібні версії XCode можна одним натиском кнопки, а вручну це ціла історія. Також і файли журналів, і різні кеші, які в розробників завжди накопичуються — не кеш браузера, а кеш Yarn, наприклад.

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

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

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

Купа старих версій мов, встановлених з asdf - класика. Бо кожна версія ще ж зберігає всі бібліотеки наново.

Величезні файли нейронних мереж — проблема сучасності, якщо ти запускаєш щось таке локально.

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


07.07.2025

Вашій системі Мабуть/Колись потрібний огляд

Оце рівно рік тому писав, що вам потрібна система “мабуть/колись” - місце, куди можна спокійно відвантажувати всі справи, які зараз немає можливості або сенсу робити.

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

Система огляду дуже проста. Мої мабуть/колись це купа файлів-нотаток, десь близько 50. Я зробив список для огляду, де кожен файл треба помітити галочкою. Оце й все.

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

(Та так, в мене “Мабуть/колись” умовно поділяється за тематикою. Важливо уникати надто великих скупчень, бо в них потім загубишся. Як бачу, що таке назріває, ділю нотатку далі.)

А в кількох файлах знайшлося й те, що на часі! Та пішло в проєкти. Нарешті замкнулося велике коло, та я можу впевнено перекладати поточні проєкти в “мабуть/колись”, бо дійсно матиму шанс побачити їх в майбутньому.

Є й досвід повного перегляду деяких нотаток. Наприклад, я збираю покращення для житла в файли покімнатно. От був момент, коли я відкрив умовно “кухня”, перебрав все, що там є (може з 40 пунктів), розставив пріоритети та дещо поставив в роботу. Тут багато залежить від теми та завантаженості.

Так що все ще раджу завести такий каталог майбутніх справ, це й на роботі й вдома велика допомога.


06.07.2025

Ітеративна розробка свого проєкту з ШІ

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

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

Мій рівень комфорту з агентами — це короткі інструкції, результат яких я можу легко перевірити. приблизно на такому ж рівні, якби сидів в парі з людиною:

# перший запит, на модель
let's add an "Areas of Focus" class to the model

an  Area of Focus has id, name, notes, creation date
a Project  should belong to an area of focus (non required for now)

# наступний - вже на доповнення UI

the project row view should have a select box to choose its area of focus, below notes
it should only be visible if project row is focused (similar to notes field)

# та третій - інше місце в UI

in the projects list, projects should be displayed by section; section = area name
in the end, all projects with no area under "Unfocused" section

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

the remainingSomedayMaybeForReviewCount method seems to duplicate somedayMaybeFilesForReview and scanSomedayMaybeFolder

let's have only one method to list files from the directory, and normalize their filenames

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


05.07.2025

Bose Ultra Open Earbuds - можливо, мої ідеальні навушники

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

Та нарешті, після кількох невдалих спроб (Sony LinkBuds - бррр, жахливо), нарешті знайшов те, що треба - Bose Ultra Open. Такі навушники потребували певного кроку в невідомість, бо це очевидно щось поза категорією: замість того, щоб вставлятися у вуха, ці вдягаються на вушну раковину. (Хоча насправді ні, зараз навушників-кафів не так мало, ось з іменитих є ще Huawei Freeclip.)

Отже, Bose Ultra Open мають форму кафа, половина його тверда, а половина мʼяка силіконова. Тверда частина йде вперед, в ній динамік. Мʼяка закінчується циліндриком з батареєю, він йде за вухо. Вдягається ця штука не складніше та не довше, ніж звичайні затички. Сидить в нижній частині вуха. Вони дуже легкі та практично не помітні, що мені особливо подобається. Бо на відміну від затичок чи вкладишів такий навушник абсолютно не заважає слуху. Хоч цілий день його носи.

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

По програмній частині: є multipoint, тобто між айфоном та маком перемикаються самі собою. Навіть є можливість, якої немає в AirPods - можна натисканням кнопки навушників перемикатися на інший пристрій. (Так, і, до речі, тут є справжня механічна кнопка!) Зате немає автопаузи. Що мене абсолютно не турбує, бо на відміну від AirPods, ці навушники не потрібно знімати. Натиснув на кнопку, поставив на паузу, поговорив та увімкнув далі.

З мінусів: мікрофони тут чиста формальність. Ну й ніякої ізоляції чи тим паче шумодаву не буде, очевидно. На гучній вулиці чи під перфоратор погано чутно. Футляр більш-менш зручний, але петля слабенька. До речі, як і самі навушники — не знаю, на скільки вистачить цього силіконового місточка. Втім, всі сучасні навушники живуть стільки, скільки батарея, тож може це й не проблема.

(Ще розглядав кісткові навушники, як-от Shokz. Але ті заважатимуть окулярам. Також звук кісткових навушників - це цікаво, але на мій досвід гірше за звичайні.)

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


04.07.2025

Elixir - єдина мова. від якої я відскочив

Пару днів тому згадав про мову Elixir - перший раз за майже 3 роки існування каналу. Певно, це вже достатньо говорить про те, наскільки вона мені не зайшла, хоча я професійно писав на Elixir принаймні кілька місяців. Було це десь у 2017-2019. Тож може за цей час багато змінилося. Он, виявляється, по версії Stack Overflow це друга за привабливістю мова. Але то таке — хочуть, але не вчать чомусь?

Elixir - це чисто функціональна мова на основі віртуальної машини Erlang. ЇЇ створили як швидкісну мову для проєктів на Ruby… як я з нею й познайомився. Синтаксис Elixir багато в чому нагадує Ruby, та й підходи та ідіоми теж. Наприклад, тут є інтерактивна оболонка, гнучкість DSL, символи та блоки.

З усім тим, Elixir працює зовсім не так, як Ruby. Наприклад, в головному фреймворку Phoenix операції з базою відбуваються через функціональну структуру changeset. Бо в функціональній мові дані течуть за програмою, а не зберігаються у змінних. Це не те щоб погано, але для рубістів тут криється багато сюрпризів.

Зокрема, мені було незручно через Erlang. Erlang - це цілий світ, з власною віртуальною машиною, дивною моделлю рівночасності, та незнайомими підходами в цілому. Причому принаймні у 2019 ці підходи лізли з кожної помилки в Elixir, тож їх не можна було ігнорувати. (Я все ще хотів би вивчити колись Erlang, але навіщо, поки не знайшов.)

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

Отже, як я пішов з того проєкту, більше ніколи за Elixir братися не хотілось. Залишилося пару PRів в проєкт до якого, певно, так само втратили інтерес.

А що, може є тут діючи еліксирісти? Як воно вам? Є прогрес в мови за останні 5 років?


03.07.2025

Як зробити власний, незалежний блог

Поступив запит: “як та на чому зробити власний блог”. В мене такий вже… понад двадцять років? Тож можу поділитися. Інструкція задумана для (не-веб) програмістів, тож передбачає певний компʼютерний хист.

Домен. Власність в інтернеті починається з домену. Бо домен — це те, як тебе знаходять люди. Поки в тебе є домен — все інше можна підлаштувати. (Володіти доменом, звісно, не вийде — ти тільки його орендуєш. Але це найбільш стійка власність в усьому Інтернеті.) Домен реєструється в одного з реєстраторів — наразі я рекомендую Namecheap. Реєстратор — це не навічно, потім можна перенести за потребою.

(Та, домен коштує грошей — зазвичай близько $10 на рік. Але сьогодні дізнався, що у нас в Україні є безплатна зона pp.ua. Щось знаєте про неї?)

Чисто технічно, домен можна привʼязати до будь-якого конструктора сайтів — хай то WordPress чи SquareSpace, чи Wix - та вже мати власний сайт. А потім — спокійно переїхати на інше рішення. Але ж ми тут говоримо про “власний” блог, то нумо рухатись далі.

Зміст сайту. Хоч ми проживаємо час вебзастосунків, але стара добра модель “сайт — це колекція файлів HTML” теж жива-здорова. Це називається статичний сайт. Можна взяти та написати цей HTML вручну (або ще й зберегти з Ворду!) Але типове сучасне рішення для блогів — це генератор статичних сайтів.

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

Розміщення. Нарешті, щоб його побачили люди, сайт треба розмістити в інтернеті. (Можна хоч вдома — але це не для початківців.) Хостинг — річ утилітарна, тому не варто довго на ній зациклюватися. Його також легко замінити пізніше. Моїм улюбленим рішенням залишається Firebase, який ще багато чого вміє, але нам потрібний мінімум. Головне, що з Hugo розгорнути в Firebase можна однією командою: hugo && firebase deploy. Але спочатку не забудь привʼязати до Firebase свій домен.

Якщо робити все за інструкціями 1 2 та не хапатися відразу за нюанси, то зробити власний, на 100% особливий блог цілком можливо за вихідний. А розваг потім — на роки вперед. 😉


02.07.2025

Mise = ASDF + direnv + make

Коли я писав, що ASDF - не наймодніша штука, то мав на увазі насамперед Mise. Вона зібрала в себе й керування версіями, й встановлення змінних оточення, й словничок скриптів — тобто повсякденні потреби кожного проєкту. Я поки не перейшов на Mise повністю, бо в мене вже є готові рішення та купа багажу — але якщо починати з нуля, то, певно, має сенс.

Порівняно з ASDF, тут є одна величезна відмінність (та багато дрібних.) Mise не має теки з прокладками! Натомість вона збирає $PATH зі шляхів до кожної обраної версії. Такий підхід багато кому знайомий, до менеджерів версій я саме так і робив би. Тобто, якщо ми обрали Ruby 3.2.2, то в шляху буде ~/.mise/ruby-3.2.2/bin.

Завдяки такому підходу запуск інструменту не потребує звернення до менеджера для визначення потрібної версії (як це робить ASDF.) Вся робота менеджера відбувається під час переходу в нову директорію (а точніше, під час зміни обраних версій.)

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

Щодо заміни для direnv та make поки нічого не можу сказати, бо не користувався. Взагалі в команді такі зміни важко впроваджувати. Гарно що хоч що Mise, що ASDF можуть читати “ідіоматичні” файли версій, як, наприклад, .ruby-version, тож не потрібно всіх відразу примушувати до зміни менеджеру.


01.07.2025

ASDF - універсальний менеджер версій

Раз вже тема піднята, розповім про ASDF. Я з цією утилітою вже скоро років 10, та вона вже навіть не наймодніше, що є, але то не привід нею не користуватися.

Якщо ти працюєш з Ruby, Node.js, чи Python, то точно знаєш про rbenv, nvm та pyenv. Всі ці утиліти дозволяють мати кілька версій мови та перемикатися на потрібну для кожного проєкту. Бо в кожній версії є маленькі та великі відмінності та нам важливо зафіксувати, яка версія використовується в проєкті — та переконатися, що як на сервері, так і в кожного розробника встановлена саме вона. В професійній розробці ніяк не вистачає apt-get install ruby.

…А якщо ти працюєш відразу з кількома мовами, то підтримувати цілий зоопарк менеджерів версій стає витратно. Для того й існує ASDF - вона заміняє відразу всі вище згадані утиліти, та підтримує ще багато інших мов та пакетів. Завдяки підтримці плагінів ASDF покриває сотні інструментів. От навіть XCode. Також постійно використовую для Go та Terraform. А почалося використання ASDF в мене, здається, з Elixir, для якого аналогу rbenv просто не було.

Працює ASDF дуже просто — він генерує теку shims зі скриптами-“прокладками”; наприклад, там є скрипт ruby, який прочитає з оточення поточну версію Ruby та запустить відповідну програму. Прокладки створюються не тільки для програм з самого пакету мови (gem, irb тощо), але й для тих, які належать встановленим бібліотекам (terminal-notifier).

Причому якщо у мови є власний формат файлу версії, то ASDF здатний його читати. Наприклад, .nvmrc. Тому на нього можна переїхати тихенько, не треба вмовляти всю команду. Хоча… згодом можна й вмовити та перейти на спеціальний для ASDF .tool-versions.

В мене ASDF - один з незамінних інструментів, та й вам раджу спробувати.