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

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

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

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 - один з незамінних інструментів, та й вам раджу спробувати.


30.06.2025

Noasdf - скрипт для обходу asdf

Оце написав вчора та думаю: ASDF це дивовижний засіб для розробника, якому треба мати кілька версій оточення… особливо коли в тебе технологій цілий зоопарк. (Ну або mise, якщо ти на часі.) (Я трохи здивований, що ніколи про нього не писав окремо.)

Але користувачу він життя ускладнює. Бо з ASDF в тебе кожної мови півдесятка версій. На кожну версію — власні пакети та виконувані файли. Оновлення версій зі збереженням пакетів немає, є тільки встановлення нової версії.

Отже, якщо хочеш встановити собі якусь утиліту — наприклад, terminal-notifier - через gem або npm тощо — та так, щоб вона була доступна завжди — то ASDF в цьому тільки перешкоджає. В нього за призначенням ця утиліта буде доступною тільки поки ти не обереш локально іншу версію Ruby чи JS. Навіть якщо встановити її в “глобальну” версію, навіть якщо в системну — не допоможе.

А раз так, знайшов вихід, який поки працює: вимикати ASDF. Його механізм дії — додати свій шлях до $PATH. Підчистити шлях — та ASDF як не було:

noasdf() {
  shims_path="$HOME/.asdf/shims"
  clean_path=$(echo "$PATH" | tr ':' '\n' | grep -v "^$shims_path\$" | paste -sd ':' -)
  PATH="$clean_path" "$@"
}
# наприклад:
noasdf npx perplexport

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


29.06.2025

Perplexport

Як і збирався: yarn global add perplexport - утиліта для експорту діалогів з Perplexity. Я поки боюся, що з браузером будуть якісь складнощі, але подивимось. Є ще варіант з Puppeteer переїхати на Playwright.

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

В мене потреба повністю закрита: можу тепер додавати кожен діалог до Obsidian. Разом із Markdown зберігаю поруч вихідний JSON, про всяк випадок; до того ж JSON містить більше інформації, хоч вона поки здається мені зайвою (наприклад, перелік виконаних запитів.)

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

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

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

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


28.06.2025

Експорт з Perplexity - простіше, надійніше, краще

Минула версія скрипту для експорту з Perplexity трохи завʼязла через обмеження частоти запитів. До того ж експортований Markdown був досить неповноцінним та не містив, наприклад, знайдених зображень. А оце сьогодні вдалося зробити з усіх боків краще!

Сиджу та думаю: ну якщо я вже відкрив сторінку з діалогом, то навіщо мені ще експортувати — в такий “джерельний” формат, як Markdown - коли в теорії можна просто забрати зміст зі сторінки?

Подивився журнал запитів (вкладка “Мережа” в інструментах розробника корисна, як завжди.) Та дійсно — бачу смачний запит до API, який віддає зміст в усіх подробицях (/rest/thread, якщо будеш шукати для себе.) Там не тільки Markdown діалогу, а й перелік посилань, зображень, навіть розʼяснення плану пошуку. Абсолютно все.

Але найкраще навіть не це. У таких запитів майже немає обмежень! Бо це звичайний перегляд сторінки. Коли я зробив паузу між сторінками у 2 секунди, то успішно забрав всі свої 500 діалогів.

Я вирішив не робити ті запити до API напряму, а все ж взаємодіяти зі сторінками так, як це робить звичайний користувач. В Puppeteer дуже легко забирати будь-які запити, що відбуваються: достатньо зробити page.on('response'). А там вже фільтрувати за URL та зберігати в файли.

Єдине (хороше!) ускладнення — дані я отримую у JSON. Це чудово, бо можна так їх і зберігати та сподіватися, що це вичерпний експорт. Але документ Markdown з них ще потрібно збудувати. На щастя, кожна відповідь генерується вже в Markdown, тобто їх залишається просто склеїти. Найбільше проблем створили посилання на джерела: вони помічені просто як [1], а мені довелося будувати список посилань з внутрішніми якорями ^0-1, а потім на них посилатися: [[#^0-1]]. Ну то дрібниці.

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