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

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

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

06.08.2025

JSON Canvas Tools

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

Що я сьогодні й зробив: результат тут. Для початку переклав на Go. Бо ділитися скриптом на Ruby має сенс тільки серед рубістів, а от скомпільованою утилітою може скористатися будь-хто. Причому на Go я легко зроблю версії під всі платформи — на то є GoReleaser.

Знайшовся вже готовий пакет supersonicpineapple/go-jsoncanvas для роботи з JSON Canvas… ну як роботи — головне, що він схему описує, щоб мені цього не робити.

В принципі, можна вже зараз забрати інструмент та користуватися. Але наразі стикнувся з проблемою підписів. MacOS взагалі відмовляється запускати файл без підпису. Такий саме що я тільки що скомпілював — дає. А якщо його ж завантажити з GitHub - вже не можна. На Windows проблеми схожі, але ми можемо скасувати перевірку.

Причому якщо на MacOS в мене і дійсний сертифікат є (він, якщо що, коштує $100 на рік), то на Windows немає та я навіть не знаю що там за процедура поки. Доведеться розібратися.


05.08.2025

Канбан та нащо він гідний

Канбан “з першоджерела” майже повністю змінив зміст. Бо коли його винайшли — на фабриці Тойоти — то це була система замовлень запчастин; дещо схоже на корутини чи генератори в програмуванні. Коли у відділу Б закінчувалися запчастини з відділу А, вони вішали на дошку відділу А картку; коли картки сягали визначеної кількості, відділ А запускав виробництво.

Це мені нагадує сімейний список покупок: коли закінчилася гречка, її записують в список (у нас для цього стіна — майже канбан!) Коли в списку достатньо пунктів, час піти за покупками.

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

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

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

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

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


04.08.2025

Наш світ побудований маркетологами

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

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

(Звісно, не всі захоплення треба продавати, тим більше масштабувати. Але якби так було з усім, не було б сумних історій про те, як “я старався, а ніхто не прийшов”. Та якщо в тебе така є — справа не в продукті, а в тому, що його недостатньо продавали.)

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

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


03.08.2025

Перший погляд на Nushell

Оскільки вже кілька людей радили подивитися на Nushell, вирішив все ж випробувати.

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

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

(Для порівняння, Fish теж не повністю перетинається з POSIX Shell, але принаймні структура викликів однакова, а різниця зазвичай суто синтаксична. Зі скриптами все складніше, але я нею скрипти й не пишу.)

Тобто Nushell - це, фактично, абсолютно окрема мова програмування, в якої є інтерпретатор командного рядка. Що відносить її до категорії Ruby. (Та інших мов з інтерпретаторами, але для мене Ruby це рідне, та й інтерпретатор в неї зразковий.) Технічно, я б і Ruby міг би використовувати як “оболонку”… з ще меншим успіхом. Але як щодо Nushell для програмування?

Найбільш помітним в Nushell є використання конвеєрів | для обробки структурованих даних. Для мов оболонки це інновація, але для Ruby (чи будь-якої сучасної мови програмування) нічого особливо нового. Гарно, що вбудована візуалізація для таблиць, Гарно, що є підтримка різних форматів даних. Не просто JSON, а, наприклад, Excel - що натякає (спойлер), що може я - не цільова аудиторія.

Також про типізацію. Nushell є типізованою мовою, то є так. Головне, що на відміну від більшості оболонок, значення в Nushell мають тип та мова не дозволить виконувати операції, несумісні з типом. Хоч порівняно з Ruby, тут ще є перевірка типів у момент запуску, але це стосується тільки значень з коду, а типи вхідних даних не перевіряються.

Одним словом, Nushell для мене знаходиться в дивному місці посередині, та не спокушає замінити ані Fish, ані Ruby.

Але зате з позитивного: що Nushell піклується про гарну підтримку Windows. Тому, гадаю, якщо в когось потреба працювати і на *nix, і на Windows - то це дійсно гарний варіант оболонки. Та заміна знайомих утіліт командами оболонки просто рятує - бо у Windows зовсім інший набір. (Між Linux та macOS різниця незначна та стосується лише окремих опцій, які ти здебільшого просто уникаєш або обходиш псевдонімами.)


02.08.2025

Три навички, які потрібні інженеру для росту

Вміння ставити питання. Це абсолютно найважливіша навичка, яка розвʼязує купу складнощів. Прояснити задачу, а не залишатися безпорадним. Зрозуміти архітектуру проєкту. Знайти відповіді в інтернеті. Особливо коли ти тільки починаєш карʼєру, в тебе повинно бути багато запитань, та недосвідчена людина, яка не ставить питання — миттєвий тривожний дзвіночок.

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

Інколи люди соромляться задавати “дурні питання”. Не треба цього боятися. Якщо в тебе залишається нерозвʼязане питання, навіть якщо воно наївне, в майбутньому це тільки створить більшу перешкоду. (Та, якщо так мислити, більше сорому.) Тому треба все питати. Єдине дурне питання — те, яке повторюється без змісту багато разів. Тож вміння ставити питання містить і вміння записувати відповіді.

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

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

Вміння доводити справи до кінця. Одна з найчастіших скарг — через не до кінця зроблену задачу. Від банального “було 5 пунктів, зробили тільки два” до менш тривіальних “не підчистили / не дорефакторили” чи “не продумали всі випадки”. Відповідальність на це лежить на виконавцеві — в програмуванні часто ніхто, окрім тебе, і не знає всі подробиці, а “хвости” вилазять тільки пізніше, коли вже і ти про них забув. Тому ми, виконавці, повинні оглянути роботу критичним оком та закрити всі недоробки. Або принаймні задокументувати на майбутнє, хоча це завжди ризикований вихід.

Як бонус — вміння побачити кінець та не йти далі. На цьому все.


01.08.2025

Асимптотична оптимізація

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

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

Для того є просте правило. Поки пишеш код, потрібно мати на увазі та враховувати, скільки циклів та рекурсивних викликів він робить. Бо це впливає на асимптотичну оцінку складності — чи буде програма O(N), O(N²) тощо. Від цієї оцінки дійсно залежить, чи буде наша програма літати або лежати.

Звісно, нюанс перший в тому, що більшість складності прихована в коді, часто чужому. Тому досвідчений програміст памʼятатиме, що пошук в невідсортованому масиві має складність O(N), сортування - O(NlogN) тощо. А ще складність може сидіти в базі даних.

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

Тому я б не дуже переймався таємними знаннями на кшталт “якщо переставити ці два аргументи місцями, операція буде на 20% швидше”. Та тим паче не поспішав впроваджувати в код. Краще вивчити О-складність — спочатку базових алгоритмів, а потім на конкретних структурах даних у вашій мові та СУБД.

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


31.07.2025

Плагіни для застосунків на Swift (та macOS)

Я тут колись писав, як мій застосунок для ведення справ вміє створювати проєктну документацію в Obsidian. Це дійсно зручно та я досі користуюся цією звʼязкою. Насправді інтеграція з Obsidian тільки збільшилась — бо тепер я також автоматично підчищаю файли завершених проєктів. Та ще зберігаю для кожного файлу “мабуть/колись” дату останнього перегляду.

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

Я точно не буду робити базу знань власноруч: ані сил немає, ані сенсу. Навіть мені самому зручніше працювати в Obsidian. Але привʼязуватись до Obsidian жорстко теж сенсу немає, тим паче навіть в Obsidian в кожної людини свої підходи. Простий вихід — це прибрати інтеграцію, залишити тільки можливість вставляти посилання (яка вже й так є): посилання на файл в Obsidian, сторінку вебзастосунка тощо.

Але також подивляюся в бік плагінів. Не мав великого досвіду з плагінами, отже, гадав, що там все складно — треба тягнути якийсь інтерпретатор, обирати мову, і таке інше. Виявилося, що в macOS є система динамічного завантаження бібліотек — приблизно так само, як .so в Linux чи DLL в Windows, тут є Bundle.

Причому користуватися ними на Swift дуже приємно. Спочатку оголосити протокол, який виконуватимуть плагіни. (Протокол звичайний свіфтівський.) Ну й, звісно, його реалізувати та скомпілювати. Далі залишається завантажити Bundle, викликати в нього метод principalClass - яким вже можна користуватися як звичайним кодом.

На iOS, звісно, завантаження динамічних бібліотек заборонено, але мені поки, припустимо, і не потрібно.


30.07.2025

Якою мовою писати одноразовий скрипт?

Я раніше гадав, що відповідь очевидна, але виявляється, що ні.

Відразу першим кандидатом буде Bash. Мабуть, тому, що в Bash прямий доступ до інструментів командного рядка. Та якщо рішення збирається саме з таких інструментів, то чому і не писати його на баші. До речі, хоч є й інші мови оболонок — для мене насамперед Fish, але скрипти я майже завжди пишу для Bash.

Втім, як тільки виникає потреба в розгалуженнях, або ще краще — в циклах, або в обробці тексту, зручність Bash різко спадає, та я беруся за Ruby. Окрім того, що це мені звична мова, у Ruby багатий набір бібліотек на всі випадки життя. Та й викликати щось стороннє тільки трішечки складніше, ніж в Bash.

На цьому можна було б підсумувати, що скрипти пишуться скриптовою, тобто динамічною мовою, до якої ти звик, та закінчити. Але є винятки. Про один я колись писав - скрипти, що обробляють великі обʼєми даних, варто відразу писати ефективнішою мовою (яка в мене Go).

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

До речі, ще одна перевага “скриптів” на Go - вони самодостатні: не тільки бібліотеки, а й потрібні файли можна зашити в вихідний файл. Та й кроскомпілювати немає проблем. Так що, виходить, Go гарна скриптова мова!


29.07.2025

В пошуках сенсу

В GTD є модель горизонтів фокуса. Це шість перспектив, з яких можна дивитися на своє життя: починаючи з нульового рівня наступних дій, та закінчуючи пʼятим рівнем мети життя та життєвих принципів.

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

Мені було важко почати, бо не хотілося писати зовсім загальні речі штибу “бути чесним”. Справа зрушилася, коли я пройшовся по списку проєктів з питанням “навіщо я це роблю?” Так набирався список тверджень як-от “допомагати близьким” чи “підтримувати форму”. Головне, щоб таке твердження вже давало відгук: так, це воно! Бо, власне, вправа не на вигадування, а на пошук в собі.

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

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

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

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


28.07.2025

Моніторинг для одинаків: постмортем та роздуми

Вчора в мене відбувся подвійний удар відмов RSS: спочатку стрічка Hacker News виявилася порожньою, а потім стрічка рецептів з блогу, а з нею — як виявилося — всі стрічки на сайті.

Про Hacker News досі не зрозумів. Вона є, тільки порожня. Але, коли запускаю скрипт вручну, то вона наповнюється, але після запланованого запуску знову зникає. Це пахне обмеженнями для ботів, що буде прикро, але в будь-якому разі спочатку треба зрозуміти. Накидав туди логів стільки, скільки влізло, та буду читати.

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

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

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

Тут подивився на n8n, але це такий комбайн, що не схоже, що мені сподобається його підтримувати. Ще знайшов Uptime Kuma - наче непогане рішення, self-hosted, для перевірки ресурсів. Навіть вміє завантажити RSS та подивитися, чи є там тег item. Можна було б його закинути на домашній сервер та нехай собі тестує. Поки ясного рішення немає — хоч здається, на наш час воно повинно бути простим.