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

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

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

22.07.2025

Три речі, які варто знати про LLM, щоб не робити дурниць

Щось останніми днями триває буря драми навколо LLM, від трагічної історії, як Replit не стримав обіцянки до “відкриттів” про небезпеку MCP. Я часто дивлюся і думаю: ну якщо хоч би базові речі розуміли, то багато питань відпадають самі собою.

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

Друге: LLM є незмінними. Сучасна архітектура не може навчатися в процесі роботи. Ба більше, для навчання LLM потрібна велика кількість прикладів. Ви не можете навчити LLM ні-чо-му. Єдиний спосіб вплинути на вихід LLM - змінити вхідний текст. Тому всі наші правила, а також “памʼять” та інші контекстні дані всі заходять з тим самим текстом (хоч і неявно для користувача.) LLM не “памʼятає”, що ви просили не видаляти базу — вона тільки бачить інструкцію на вході. Разом з епічною кількістю інших інструкцій — сотнями кілобайтів.

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

Ось так. До того ж LLM є серцем (чи мозком?) всіх сучасних “ШІ”. На такому етапі розвитку ми знаходимось. Масштабуванням тут нічого не змінити. Так що поки не почуєте, що зʼявилося щось на заміну LLM - будемо жити з цими обмеженнями.


21.07.2025

Керування проєктами для розробника-одинака

Потроху намагаюся щось влаштувати, бо одним натхненням чи навіть зусиллям волі успіху не досягнеш.

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

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

Мій улюблений особистий GTD теж мало допомагає в розробці, бо планування програмних продуктів — річ особлива, в ній завершення проєкту не є чітко визначеним. Я пробував додавати в GTD проєкти на кшталт “Ping - наступна версія”, але вони виходять примарними, тож і мало успішними. (А успішними були б проєкти-задачі на кшталт “Додати редагування декількох записів одночасно”, до яких ще треба дійти, про що я й кажу.)

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

Проблема в тому, що я Agile знаю на рівні “спринти та стендапи”, от може книжку треба прочитати та все зрозумію. Поки залишу вас з 10 принципом:

Необхідною є простота — мистецтво залишати незробленою якнайбільше роботи.

Поезія!


20.07.2025

Atomfall: британський не-Сталкер

⚛️ Atomfall - гра, в 40 разів менш популярна за Сталкер 2, та й не є ААА, втім уваги варта. Призвістко “Сталкер в Британії” вона отримала, бо відбувається в карантинній зоні навколо АЕС після якоїсь катастрофи. Але насправді схожість на цьому практично закінчується. (Ну, ще, як я зрозумів, Atomfall зробили британці з такою ж любовʼю до своєї країни, як Сталкер — українці, але я не дуже в цьому знаюся.)

🔎 Насамперед Atomfall гра зовсім іншого жанру. Якщо Сталкер схиляється до симуляції та лінійного сюжету, то Atomfall - гра про дослідження. І мені вона цим дуже сподобалася. Тобі практично нічого не пояснюють. Гра починається з наймінімальнішої мети: втекти! Ну, та спочатку зрозуміти, що взагалі відбувається. Без спойлерів: на то гра дає кілька інтерпретацій та нуль конкретики. Я ще до кінця не дійшов, та досі маю свої версії.

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

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

🔑 Прогрес складається з проникнення дедалі глибше в ландшафт та в таємницю. На шляху стоять перешкоди. Замки, до яких доведеться шукати ключі. Інколи є підказка, де ключ, інколи просто доведеться чекати, поки не натрапиш на нього. Та противники: флора, фауна, суспільство.

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

💙 Природа, фантастика, загадки. Для мене такі ігри — як для кота валерʼянка.


19.07.2025

Лимонад

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

🍋 Класичний рецепт - 1 чашка лимонного соку та 1 чашка цукру на 1-1.5 л води. Чашка соку — це приблизно 500 г лимонів, але краще брати з запасом. Зауважу, 1-1.5 л води це на вході, а не на виході. Хоча взагалі завжди можна розбавити більше до свого смаку.

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

Щоб везти на природу, простіше за все купити велику (на 3-5-6 літрів) пляшку води, частину відлити та замінити смачненьким. Можна прямо в ній й мішати, тоді не треба шукати другий великий посуд. Можна мішати й з газованою водою, хоча газу залишається небагато. Або, якщо є можливість, і з льодом.

🫚 Оце, наприклад сьогодні робив 6 літрів лимон + малина + імбир. На цей обʼєм - 2 кг лимонів, 200 г імбиру, чашка малини та 3 чашки цукру.

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


18.07.2025

Приватний ключ як сервіс

Є такий цікавий сервіс, як AWS Key Management Service або аналогічний від Google, ну і так далі. Зазвичай з ними стикаються, коли треба щось десь зашифрувати — наприклад, відро (хахаха) у S3 чи зміст однієї з баз. Тому з першого погляду може виглядати так, що цей сервіс — внутрішня абстракція, та на цьому його користь закінчується.

Але насправді той AWS KMS - це сховище звичайних криптографічних ключів. Тільки в цьому випадку, нам доступні тільки публічні ключі, а приватні — приховані за API. Таким чином ми можемо створити собі криптографічну пару, ніколи не знаючи приватного ключа, а потім шифрувати, дешифрувати, або підписувати через відповідні API.

На що таке потрібно? Ну, як, по-перше, то з KMS легко керувати дозволами на ключі, бо права задаються звичайним IAM. Можна кому завгодно дати можливість підпису, та не перейматися про те, що вони втечуть з приватним ключем. Це насправді величезна перевага.

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

До речі, а як щодо сертифікатів? Тут треба згадати, що сертифікат - це лише публічний ключ із додатковою інформацією. Хоч в KMS не можна зберігати сертифікати, але й потреби не має — достатньо підписати Certificate Signing Request ключем з KMS, та у вас буде сертифікат, яким можна підписувати теж через KMS. (Бо технічно, підписують ключем, а не сертифікатом.)

З недоліків, звісно, те, що зі звичайними інструментами KMS не працює. Тобто публічний ключ отримати легко та весь код, якому потрібний він, можна залишати без змін. А ось код підпису (чи шифрування) доведеться переписати з використанням API. Хоча оце тільки що дізнався, що для сховища ключів є стандартний інтерфейс PCKS 11, та існують реалізації його для KMS - тобто не все так погано.


17.07.2025

Мови програмування та їхні узбіччя

Обговорення попереднього поста про jsdate.wtf нагадало мені чомусь старі гоночні ігри. Є серед них такі, де як тільки зʼїжджаєш з дороги, починаєш їхати повільніше та повільніше, аж поки не “завʼязнеш” десь в багнюці. А є NFS: Underground, де межа дороги є стінкою, по якій навіть можна досить успішно ковзати.

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

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

Те, що мова динамічна, ще не робить її маріокартом. Наприклад, в Ruby немає неявного перетворення типів, та й парсер дат суворіший. Хоча, певно, всі динамічні мови схильні “увʼязати”. А статичні теж є різні: схильність Swift викинути помилку “цей код надто складний, щоб я міг його перевірити” ще і як дозволяє завʼязнути.

Як протилежний приклад (з мені знайомих): в Go незалучена змінна вважається помилкою. Хочеш ти або не хочеш, але зайвої змінної мати не будеш. Мова за тебе про це попіклується. Навіть коли ти не дуже гарно знаєш, куди рухатись, “стінки” мови тебе спрямують.

Хоч звучить що стінки — це завжди гарно, але є й третій варіант, коли замість стінок ти падаєш з траси. Таку асоціацію навіюють помилки C++ чи Clojure. Багато коли краще вже “проскочити по узбіччю”, ніж ретельно уникати всіх помилок.


16.07.2025

Реєстр сервісів AWS Cloud Map

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

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

Тобто можна у сервісі ECS вказати область імен AWS Cloud Map, та він буде там реєструвати кожну нову задачу. А взагалі AWS Cloud Map підтримує практично всі різновиди сервісів в AWS - від EC2 до Lambda.

На виході отримуємо локальне імʼя вузла (myservice.local), яке можна через локальний DNS розвʼязати у список активних копій. Ну є ще API DiscoverInstances, але мені ним не доводилося користатися.

Бо виявлення копій через DNS це доволі типовий сценарій, тоді достатньо вказати в конфігурації то локальне імʼя та решту сервіс робить самостійно. І не треба ніяких редісів, куди ми пишемо під час запуску, а потім ще й переклик робимо, щоб не було зомбі.

Все це трохи нагадує домашній mDNS, але не дуже. Бо хоч Cloud Map так само надає можливість перелічити сервіси, та відбувається це через центральний сервіс. Інакше в хмарі складно було б уявити.


15.07.2025

Віддалений робочий стіл з Mac на Mac

Можна сказати, що в той день, як я завів окремий Mac Mini для роботи, було передбачено навчитися працювати з ним віддалено. Бо звичайно для Mac Mini потрібний монітор, що привʼязує до робочого місця — а я час від часу маю потребу бути в розʼїздах. Кинути в валізу Mac Mini легко, та й Macbook завжди з собою… тільки як їх поєднати?

З наївних рішень: використовувати Macbook буквально як монітор не вийде. А було б гарно.

Тому перша задача: поєднати в мережу. Якщо є локальна мережа чи знайомий Wi-Fi, то достатньо один раз налаштувати на Mac Mini. Але в сценарії готелю так не вийде. Якщо є кабель Thunderbolt (виглядає як USB-C, а коштує від 40 доларів), то можна ним зʼєднати, тоді маки створять мінімережу. А якщо натомість є більш корисний адаптер Ethernet (за ті ж гроші!), то можна зʼєднати макбук з макміні звичайним мережевим кабелем. Так в них теж зʼявиться локальна мережа. (А адаптер Ethernet для макбука взагалі річ незамінна.)

Тепер найпростіше — роздати з ноутбука інтернет (бо ноутбук буде на готельному Wi-Fi, чи може на телефонному, а на макміні все це налаштовувати це зайве.) Для того в налаштуваннях макбуку General -> Sharing -> Internet Sharing, та дозволяємо роздавати на наш адаптер Ethernet.

Залишається підʼєднатися до робочого столу Mac Mini. Для того є вбудований Screen Sharing, який заздалегідь потрібно увімкнути на Mac Mini (General -> Sharing -> Screen Sharing.) Тут ніяких додаткових дозволів не потрібно; тепер з макбука заходимо в Finder -> Network, обираємо наш макміні та натискаємо кнопку “Screen Share”.

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

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

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


14.07.2025

Чому в JavaScript такий хаотичний парсер дат?

Поділилися на роботі тестом “на знання парсера дат JavaScript” jsdate.wtf. Так, там багато дичини, так, я навіть на 50% не вгадав, але це всі й так знають. Краще з’ясуймо, чому?

Спочатку можна зайти в специфікацію ECMAScript. Тут все цілком притомно: є один-єдиний формат YYYY-MM-DDTHH:mm:ss.sssZ з невеличкими варіаціями. Ну й хіба те, що аргумент обовʼязково перетворюється в рядок. Все решта… на розсуд реалізації.

Тепер до реалізації. Тест написаний для Node.js. Втім, варто знати, що Node.js побудований на рушії V8, який також використовується в Chrome (та інших місцях.) Тож шукати подробиці будемо в коді V8, який, до речі, написаний на C++. Знаходимо там метод ParseDateTimeString, а з нього - DateParser::Parse. Тут з першого ж погляду бачимо коментар, який пояснює наявність “legacy dates”. В ньому перелічені чи не всі приклади з jsdate.wtf, хоча, на жаль, нема пояснень, звідки саме взялася спадщина.

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

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

У власних проєктах я б радив уникати таких вбудованих методів та використовувати бібліотеку, як-от dayjs, де ви самі контролюєте версію та формат. Та точно не використовувати Date.parse() для валідації! А від хиб на кшталт Date.parse(-[]) захистить, як завжди, TypeScript.

Так що, як бачите, річ не у тім, що парсер погано написаний, та не в тому, що специфікація погана. Спадщина — ось найбільший тягар JavaScript.


13.07.2025

Ретроемуляція

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

Спочатку, про програмну частину. Мене цікавлять консолі десь з NES до PS2. Емуляція консолей до покоління Sony Playstation включаючи — розвʼязана задача та була такою ще 15 років тому. На неї здатні зараз навіть недорогі кишенькові пристрої, як-от в мене Anbernic RG353M. А ось на покоління PS2 здатні тільки повноцінні компʼютери (мій Macbook Air M2 чудово впорався), а не ніякі Raspberry Pi тощо. Як мінімум можна знайти NUC з пасивним охолодженням.

(Якщо цікаво зануритися в емуляцію, то раджу подивитися на RetroArch та цілий дистрибутив Linux Batocera.)

Але підʼєднати сучасний компʼютер до CRT значно складніше. Я спочатку надіявся на композитний вихід в Raspberry Pi, тобто наче все сходилося. Але як виявилося, по-перше, в RPi 5 його вже немає, а по-друге, це ніяк не “plug and play”.

Той композитний вихід підтримував деякі екрани в деяких режимах, в першу чергу - як я зрозумів - CRT монітори, а не телевізори. Бо монітори краще пристосовані до компʼютерного сигналу.

Якщо коротко, то CRT технологічно повністю відрізняються від сучасних матричних екранів. Картинка будується струменем електронів, які накидаються рядками на екран. Тут немає, немає ніяких пікселів та сіток. Все, що робить компʼютер, це модулює цей струмінь. Це аналоговий сигнал — так само як і звук, тільки вимоги до синхронізації вище. Отже, для перекладу з цифрового виходу як-от HDMI у щось, що зрозуміє CRT, потрібний цілий цифро-аналоговий перетворювач (ЦАП). І нормальні такі ЦАПи не дешеві, бо вони повинні покривати різні режими входу та виходу. Рекомендований HDFury X4 коштує $289. Та це практично ще один компʼютер!

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

Отже, який тут я зробив висновок. Якщо в тебе є консоль аналогового покоління, то можна до неї знайти відповідний телевізор та мати принаймні автентичну систему. Але якщо ти вже емулюєш, то може кращого успіху отримаєш від гарної емуляції CRT шейдерами на OLED 4K. А зі справжніми консолями я звʼязуватися не буду, оці всі “подуй на картридж” та “потри диск на щастя” згадувати не хочеться.