uk
Feedback
Cіпласпластик

Cіпласпластик

Відкрити в Telegram

🇺🇦 Про айті та дотичні теми загалом, ну й трохи про C++. Усі думки тут відображають виключно мій особистий погляд. Мої емоджі: https://t.me/addemoji/AdaptiveDevIcons https://t.me/addemoji/VehicleBrands

Показати більше
672
Підписники
Немає даних24 години
+37 днів
+830 день
Залучення підписників
червень '26
червень '26
+5
в 0 каналах
травень '26
+63
в 1 каналах
Get PRO
квітень '26
+9
в 0 каналах
Get PRO
березень '26
+51
в 1 каналах
Get PRO
лютий '26
+4
в 0 каналах
Get PRO
січень '26
+7
в 0 каналах
Get PRO
грудень '25
+12
в 0 каналах
Get PRO
листопад '25
+11
в 1 каналах
Get PRO
жовтень '25
+15
в 0 каналах
Get PRO
вересень '25
+16
в 1 каналах
Get PRO
серпень '25
+9
в 0 каналах
Get PRO
липень '25
+18
в 0 каналах
Get PRO
червень '25
+54
в 1 каналах
Get PRO
травень '25
+58
в 2 каналах
Get PRO
квітень '25
+24
в 1 каналах
Get PRO
березень '25
+3
в 0 каналах
Get PRO
лютий '25
+6
в 0 каналах
Get PRO
січень '25
+16
в 0 каналах
Get PRO
грудень '24
+163
в 2 каналах
Get PRO
листопад '24
+13
в 0 каналах
Get PRO
жовтень '24
+21
в 1 каналах
Get PRO
вересень '24
+23
в 1 каналах
Get PRO
серпень '24
+25
в 1 каналах
Get PRO
липень '240
в 0 каналах
Get PRO
червень '240
в 0 каналах
Get PRO
травень '24
+72
в 0 каналах
Get PRO
квітень '240
в 1 каналах
Get PRO
березень '24
+76
в 1 каналах
Дата
Залучення підписників
Згадування
Канали
08 червня+1
07 червня0
06 червня0
05 червня0
04 червня0
03 червня+1
02 червня+3
01 червня0
Дописи каналу
Я доволі лояльно ставлюся до багатьох мов програмування. Багатьма з них користуюся, інші просто пробував і здебільшого всі поважаю. Але одне лишається незмінним: Я ненавиджу Bash 💻 усім своїм єством! Я ненавиджу його читати й ніколи не пишу. Того тижня попросив 🅿️ зробити собі тул для Nushell 🆕, і щойно він закінчив, я тут же заборонив йому використовувати вбудований Bash. Авжеж це не дуже допомогло 🙁 Усі моделі так надрочені на той клятий баш, що їм до сраки якийсь Nushell. Я прямо в системний промпт прописав, що це НЕ баш, що це навіть не POSIX-оболонка, написав відмінності, написав аналоги для типових шел-патернів — по барабану. Воно продовжує мене дрочити своїми 2>&1 і 2>/dev/null, комбінує команди через && та пише декілька ls у рядок, щоб подивитися вміст кількох директорій за один виклик. Nushell на це, звісно, скаржиться, або ж це просто дає не ті результати, і модель починає переписувати команди по пʼять разів, доки не вгадає синтаксис. Буквально «вгадає» — інакше це назвати не можна. Ось де чудово видно, що це аж ніяк не інтелект. Ну добре, біс із тим Pi. Запущу-но старий-добрий Claude Code 💻, подумав я. Не чіпав його місяць узагалі, може півтора. Здавалося б… місяць… це ж ніщо. У мене деякі пет-проєкти по 2 роки лежать, а я потім їх відкриваю й продовжую, наче останній коміт зробив учора. Такий собі анабіоз. Але не в цьому випадку! Відкрив claude, він наче на вигляд такий самий, але поводить себе інакше. Самі моделі реагують інакше, ярмо відчувається інакше! Тули Grep та Glob зникли, і ця хуйня тепер все ганяє через Bash. Я розумію, що вони зробили свій супер-пупер автоматичний «інтелектуальний» режим, де інша(?) модель оцінює, наскільки безпечно виконувати команди, і тепер це такий типу дефолт. Але я дід — мені таке не треба. Я люблю сам оцінити, що треба, а що не треба викликати. От тільки не коли воно мені висирає по 15 рядків на баші замість запустити два ґлоба та три ґрепа! Так, я міг би не вимахуватися, а бути читати баш, як усі. Але ви ж розумієте, що річ не в ньому? Річ у виборі. Не стоїть вибір між «використовувати ШІ з Bash» та «використовувати ШІ з Nushell» — є вибір «використовувати ШІ з Bash» або «не використовувати ШІ», бо воно просто не працює інакше. А скільки разів ви вибирали саме TypeScript 🕸 чи Python 💻 для своїх чергових пет-проєктів, бо на них ШІ знається краще? Закладаюся, що були ліпші альтернативи за кількома параметрами, окрім хіба що швидкості розробки. І навіть тулзи вам не належать. Вони встановлені у вас локально на компі, ви не чіпаєте їх місяць, а потім гоп — а там усе інакше. Ваші звички, які ви формували, більше не актуальні; налаштування не працюють — читайте мануал знову, витрачайте свій час, бо хтось вирішив, що вашому ярму (гг) час оновитися. Єдине рішення, яке лишається вам: робити щось із використанням ШІ чи без. «Але ж, Сіпласпластик, — вигукнете ви, — якби не ШІ, то багато моїх ідей взагалі не матеріалізувалися б!» — і матимете в чомусь рацію. Хоча я все частіше розмірковую: а може воно було й на краще? Так чи інакше, щодо себе звернув днями увагу, що з появою ШІ я значно більше почав програмувати саме руками, ніж до того (бо раніше просто нічого не робив 😌). Цікавий ефект.

2
А непогано вийшло врешті!
А непогано вийшло врешті!
617
3
Колись купив собі ZigBee-адаптер SkyConnect (aka ZBT-1) від Home Assistant. Підʼєднав до ZHA, і якось воно працювало доти, до+1
Колись купив собі ZigBee-адаптер SkyConnect (aka ZBT-1) від Home Assistant. Підʼєднав до ZHA, і якось воно працювало доти, доки не перестало. А цими вихідними нарешті дійшли руки сісти й спробувати полагодити. Я переконаний, що проблема була саме в налаштуваннях 🍓 Raspberry Pi 3, на якому мій HA досі крутиться, але все одно вирішив з нього мігрувати, тож заразом і решті вирішив дати раду. І біс мене сплутав перешити бутлоадер на цьому ZigBee-адаптері (побачив, що версія застара 🤷‍♂️) через офіційну вебтулзу. Ну й звісно воно повисло в процесі саме на екрані з написом «не відʼєднуйте пристрій від компа», тож за пів години я зробив вольове рішення відʼєднати 😅 І все. Кінець. Більше тулза його не розпізнала. Пощастило, що комп його досі бачив, хоча нічого зробити з ним вже не міг. А в мене якраз валявся мікроконтролер на проці від Pico 2, та ще й з Debug-портом (SWD)! Зашив туди debugprobe і почав відновлювальні дії. Спершу треба було зібрати чистий бінарь прошивки бутлоадера для ZBT-1. На щастя все з відкритими сирцями, тож у докері чік-чік — і готово. Далі розкрив корпус адаптера, щоб глянути, що на платі. А там є маленькі пласкі контакти для даних (SWDIO), синхронізації (SWCLK) та землі (GND), а значить можна підʼєднатися програматором. Підколхозив якихось дротів, «програматор» підʼєднав до компа через USB, адаптер увімкнув у павербанк, щоб він отримував живлення, тримав руками оті всі контакти, щоб не паяти, а мізинчиком натиснув Enter на клавіатурі, щоб запустити прошивку через openocd, і вуаля — нічого не вийшло 😂 Щоб OpenOCD знав, як шити пристрій, у нього там конфіги якісь є. А під цей чип не було. Тому спробував pyOCD, який значно зручніший. Знову не вийшло. Пару разів дружина допомагала тримати контакти, але швидко знудилася, бо все одно безрезультатно. Наостанок спробував probe-rs. З ним нарешті пощастило! 🎉 Не з першого разу, але врешті 5 секунд (і години три до того) — і готово! Перемога раста 🤓 І коли бутлоадер ожив, далі вже через веб зафігачив туди прошивку для ZigBee. Є в мене друган, і в нього завжди серйозний такий підхід до всього: інфраструктура, віртуалки, high availability — по-дорослому, а я навпаки намагаюся завжди малою кровʼю обійтися. Якщо в мене Docker, то в нього Proxmox і Kubernetes, якщо в мене Synology, то в мене TrueNAS, у мене ZHA, у нього Zigbee2MQTT. І оце нещодавно я зауважив, що врешті я все-таки приходжу ближче до того, що в нього, тільки значно пізніше 😆 Короч, викинув я той ZHA і поставив Zigbee2MQTT — все працює тіп-топ! (Тепер думаю про TrueNAS гг). До речі, якщо не в темі про ZigBee, то в дружньому, але нині, на жаль, напівмертвому каналі пан Шевцов розповідав про цей та інші протоколи.
807
4
Отже, любі друзі, цей день настав. Ми підняли DC++! Половина з вас, певно, і не знає, що це таке, бо протокол майже мертвий.
Отже, любі друзі, цей день настав. Ми підняли DC++! Половина з вас, певно, і не знає, що це таке, бо протокол майже мертвий. Та десь після пʼяти розрядів деплоя інфраструктури ми побачили пульс! Як це все працює? Насправді DC++ — це назва клієнтської програми, а сам протокол називається ADC (Advanced Direct Connect). Це гібридний протокол: має бути щонайменше один хаб, до якого підʼєднуються клієнти. Хаб забезпечує фічі на кшталт текстового чату, пошуку файлів, моніторингу підʼєднаних клієнтів тощо. Для передачі файлів клієнти звʼязуються один з одним через P2P. Останні можуть працювати в активному або пасивному режимі. Для успішного обміну принаймні один клієнт має бути активним. Активні клієнти можуть приймати зʼєднання зовні, а пасивні можуть їх лише ініціювати. Та завдяки тому, що вони обидва підʼєднані до хабу, це не проблема. Якщо активний хоче щось стягнути з пасивного, то він каже про це хабу, той передає пасивному, а той вже сам ініціює зʼєднання, щоб з нього щось стягнули. Ще в ADC (порівняно з DC) додали хешування файлів + підтримку TLS. Для звʼязку самих мереж вирішили використовувати Tailscale. Проблема була в тому, що в моїй тейл-мережі вже 30+ вузлів, а у другана взагалі kubernetes-кластер зі своєю моташкою, і нікому з нас не хотілося надто це переналаштовувати чисто під цей випадок. Ми перебрали купу різних топологій, і щоразу впиралися то в якісь обмеження самого Tailscale, то ще в щось. (Думатимете, що питати на співбесідах по System Design, згадайте цей допис — кращого не знайдете, їй-богу). Врешті зупинилися на окремій спільній мережі з певними додатковими нюансами (якщо захочете, розповім детальніше) — запрацювало! Дві наші головні помилки: 1. Ми зробили низку припущень, на базі котрих ми кинулися щось будувати, бо «ну, звучить збс» і «та хулі там», але згодом припущення виявлялися хибними: врешті час вже витрачений, а токени спалені. Тож порада: не намагатися перестрибнути декілька кроків, а почати реально з найбазовіших штук і переконатися, що вони працюють. Ніби по декілька десятків років досвіду в кожного, а робили як новачки якісь 🤷‍♂️ 2. Своєрідне продовження попереднього пункту: ми за звичкою бахнули одразу ACL, де все закрутили, і полірнули файрволами — компи наче в одній мережі, але пакети не біжуть 🙁 Пішли від зворотного: тимчасово дозволили взагалі все, а далі почали закручувати. Тут допомогла можливість писати тести в тейлскейловому ACL — можна одразу прописати, хто до кого мусить ходити, а далі прибирати права. Що маємо в результаті: окрема повністю незалежна й закрита від зовнішнього світу мережа, в якій є лише наші DC-клієнти та хаб. Можемо обмінюватися файлами за пів тисячі кілометрів один від одного по шифрованому каналу. Можемо вибирати, які файли шарити і які качати з яким пріоритетом, з підтримкою дозавантаження. Можемо слати у вбудованому убогому чаті келих пива в ASCII. Єдина залежність на чужу інфраструктуру — це координатор Tailscale, який за бажання можна замінити на власний Headscale. А ваші сучасні технології так можуть? 😎
768
5
До слова про втрачені технології, які ми з друганом днями відродили з попелу. Треба було перекинути великі файли (в ідеалі навіть більш ніж один раз). Як це зробити в сучасному світі? Ну, можна залляти кудись у хмару й зашарити. Але це якось тупо, бо спочатку, виходить, один туди заливає, а потім інший стягує — довго, незручно, ще й потребує чужих серверів. Можна використати Syncthing, але ж він саме для синхронізації. Якщо один хоче поділитися терабайтною текою, а іншому зараз треба лише один файл звідти, то воно ж все одно все посінкає. Налаштовувати вибіркову синхронізацію головняково, доведеться якось по теках то все розпихувати, просити один одного — забагато роботи на рівному місці. Якщо взяти FTP, то він суперповільний і з кепським пошуком. Можна звісно файловий HTTP-сервер задеплоїти — якийсь copyparty абощо — та це зовсім неспортивно й нецікаво. А умовний IPFS навпаки — забагато присідань треба зробити, та й пошук теж не альо. AirDrop той же вимагає, щоб пристрої були фізично поруч. Аналоги на кшталт Taildrop існують, але воно в стані альфа вже роки, та й не надто стабільне — якщо звʼязок переривається, то потім тільки спочатку пересилати. Гіпотетично можна використати торенти, які проблему перерваного завантаження чудово вирішують. Але торенти не надто самостійна технологія, бо треба якийсь трекер, треба ті торенти туди публікувати тощо. Як це все убезпечити — окреме питання. Загальну ситуацію чудово підсумовує оця цитата невідомого автора: сукааа чим блядь зумери файли кидають, невже якимсь тіктоком нахуй Вочевидь це слушний момент, щоб згадати технології дідів… і мій дружбан згадав! Технологію, яка колись була популярніша за сам Інтернет! Технологію, що в декого викличе теплих почуттів не менше за виступ Лелеки. Не просто технологію — цілий культурний прошарок епохи розквіту локальних мереж в Україні…
551
6
Лайнофікацією вже нікого не здивуєш — всім і так очевидно, що все стає гірше з часом, інколи доволі швидко. Про продукти великих компаній навіть і говорити сенсу нема: там користувачі — це лише цифри на дашборді, менеджери воюють за владу, а команди розробників не розуміють, що вони роблять і в якому напрямі рухаються. У стартапах же або в маленьких продуктових компаніях головна мета завжди — набрати користувачів і продатися. Ну або не продатися й тягнути лямку самостійно. Та доволі швидко постає питання, як заробляти гроші. І якщо продукт спочатку був безплатний, то відповідь на нього рідко кому вдається знайти, не змінюючи продукт, яким вони завоювали собі всіх тих користувачів. Згадайте Dropbox. Це була геніальна ідея: є одна тека, ви кладете в неї будь-що — і воно відразу зʼявляється на інших пристроях. А ще в ній була підтека Public, яка автоматично роздавалася в інтернет. Можна було покласти туди index.html, і вуаля — у вас власний статичний сайт. Потім шарінг з друзями спаплюжили, Public прибрали, якісь гуглодоки власні накрутили — складно, незручно, незрозуміло, глючно. Лайно, отже. Шо там зараз, не знаю навіть — певно, ШІ. Або був (і є) такий колись прикольний сервіс Pushbullet. Геніальна й проста ідея: можна перекидати посилання між пристроями. З одного надіслав — на іншому пуш прийшов. Натискаєш — автоматично відкривається в бравзері. На настільних компах тоді не було нормальних сповіщень (та й досі нема), тож там одразу відкривалося. Зручно. Потім звісно згівнили то все: додали якісь контакти з чатами, синхронізацію буфера обміну, файли й ще бозна-що. Може вже теж ШІ, хз. Такі приклади я можу пів дня наводити: TeamViewer, Hamachi, μTorrent, Skype, CCleaner, Nero Burning ROM, Docker Desktop, Plex, Opera… — список можна продовжувати нескінченно. Ви більшість з цих назв навіть не знаєте вже, бо це лайно нікому не потрібне. Цікаво інше: деяким з них ніхто не прийшов на заміну. Нє, ну альтернативи звісно були і є, але отак щоб прям зробити мінімально й зручно, як «оригінал» — то ні. Чому? Тільки не треба радити Syncthing замість дропбокса або замість пушбулета через телеграм посилання перекидати, бо воно ж у рази менш зручне. Короч, міленіали вже все просрали — може зумери за 10 років здогадаються щось таке перевинайти. Чи ні?
784
7
Всі нині показилися з агентними ШІ-системами. Звісно, цим всім добром треба якось керувати, тож є всілякі Claude Code, Codex, Gemini CLI, Copilot CLI, OpenCode, Pi, Crush, Hermes тощо. Зазвичай всі ці штуки називають загальним словом harness. І мені прям око різало оце харнес, харнес… усюди. But fear no more! Зараз ми позбудемося цього мерзенного англіцизму раз і назавжди. Пропоную вашій увазі питомий український термін — ярмо! Схвалено верховним комітетом ШБТ 💙, лаконічне, усім знайоме, передає суть ідеально — кращого слова годі й шукати. Лишилося зробити його загальновживаним у цьому контексті, тому використовуйте, поширюйте. Я, до речі, різні ярма спробував і наразі потихеньку пробую перелізати на 🅿️, бо з ним здається, ніби зможу досягти саме того, що мені треба (і не доведеться все писати з нуля).
1 244
8
Після перегляду доповіді Гіккі натрапив на ще одну статтю про вибір мови в часи повсюдного використання ВММ для програмування. Чувак там, звісно, втоплює теж за Clojure 💻, але аргументи наводить обґрунтовані. Зокрема посилається на… кхм… «коричневу межу» (мій довільний переклад brownfield barrier) з іншої статті — емпіричну величину, що являє собою кількість рядків коду, після якої ШІ-агенти починають тупити. Каже, мовляв, після 100 тис. LOC — уже шо зря. Ми не так давно маленькою командою накидали проєкт на понад 80 тисяч рядків на Python, і ніби ознак такої проблеми не зауважили. Але в нас цикломатична складність мізерна — у районі 0,06 на рядок коду, — бо по-перше, запарилися все норм структурувати й модуляризувати, а по-друге, сам прототип не надто складний окрім декількох місць. Хоча складна частина там в SQL-запитах радше. Попри це в певну мить вносити нові зміни в проєкт стало доволі боляче, особливо в режимі, коли всі активно навалюють код в одні й ті ж файли. Коли потім там чувак сам залишився, то навів ладу. Але повернімося до кложі. Автор оце стверджує, що цією мовою банально складніше досягти коричневої межі, адже змістовність в ній значно вища. Нагадую, що сам-то я на кложі не пишу, хоча трошечки кодив на Janet; плюс я шанувальник Red і REBOL, а вони в цьому сенсі від ліспа не відстають — і я цьому твердженню про щільність значущого охоче вірю! Ще там є посилання на цікаве дослідження з використання токенів різними мовами, і початково кложа була на першому місці, доки її не скинула звідти J. Остання, до речі, — це ASCII-діалект 🍏, тоді як сам APL пролетів через неефективну токенізацію. Ну, а C++ там звісно пасе задніх і лише трохи краще за C, хоча для кого це секрет. У статті підіймаються й недоліки теж. Наприклад, той факт, що ВММ-ки гублять в ліспах дужки 😆 Я сам був очевидцем цього десь рік тому, та може відтоді щось помінялося на краще. Короч хз, висновків якихось не буде — я просто отримав задоволення від статті й вирішив поділитися. Почитайте, бо вона значно глибша, ніж я оце переказав, до того ж спирається на вельми свіжі дані.
1 171
9
За свою карʼєру я чомусь обійшов стороною два трактати: «The Design and Evolution of C++» пана Страуструпа та «Simple Made Easy» пана Гіккі. І якщо стосовно першого в мене навіть в думках не було це читати, то друге вочевидь було прикрою помилкою, яку я вчора взявся виправити: з подачі пана Соловйова сів і подивився. До деяких постулатів я останніми роками й сам дійшов, а до деяких поки ще ні. А міг просто глянути відос 15 років тому й одразу бути мудрим ще відтоді! Раптом хто не в темі: цей типок є автором мови Clojure 💻 — найприємнішого LISPʼа сучасності (яким надихаються зокрема Janet 👩‍🦰 та jank 💻 — десь вище згадував, пошукайте), але в доповіді про цю мову не йдеться. Ще там днями документалка вийшла про Річа та кложу на кшталт тієї, що кілька місяців тому була про Гвідо ван Россума та пайтон. ЇЇ теж глянув, але не сильно надихнувся на щось — мабуть, для фанатів робили, щоб ті на старі дріжджі впали.
0
10
Коли мова заходить про використання генеративного ШІ в проєкті на роботі (особливо у великих компаніях), серед основних переп
Коли мова заходить про використання генеративного ШІ в проєкті на роботі (особливо у великих компаніях), серед основних перепонів є завжди такі: 1. Лячно надсилати дані на чужі сервери всіляких Anthropic чи OpenAI (особливо якщо проєкт для замовника). 2. Згенерований код може бути підозріло схожий на чийсь ще, бо всі ВММ навчалися переважно на чужих відкритих сирцях. З другим нічого не можу порадити. А стосовно першого… Річ у тім, що ШІ допомагає не лише код писати, але й аналізувати: знайти, що, де і як використовується, побудувати ментальну модель, пояснити звʼязки тощо. Тому доки ваша компанія розбирається, як хостити нормальну модель у власній хмарі, вам на допомогу приходять локальні моделі. Жодне спілкування в чаті з надто загальними описами проблеми та копіпастою повідомлень про помилки не буде настільки ж ефективним, як використання агентної системи, яка може досліджувати код самостійно. Для прикладу: я днями намагався зібрати Xmakeʼом 💻-проєкт під WASM — нічого не виходило. Декілька годин спілкування з Perplexity коту під хвіст. Наступного дня дав копайлоту 💻 подивитися: він повивчав CMake-файли з самого кьюта, подивився на те лайно, що написане в Xmake, і врешті згенерував мені повністю робоче правило трохи менше ніж за годину. Як повторити те саме з локальною моделлю? Ну, спершу треба… «запустити» модель. Я використовую LM Studio, бо є нормальний GUI та за потреби вміє працювати й у headless-моді. Одна з найтоповіших моделей нині — Gemma 4 від ґуґла. Я вибрав Gemma 4 26B A4B з 8-бітним квантуванням. Тут правило просте: беріть те, що влізає на ваше залізо. E2B та E4B — для слабших пристроїв, A4B з так званим Mixture-of-Experts для макбука, 31B без додаткових приписок — не бачу сенсу. Якщо у вас macOS, то постає ще вибір між MLX та GGUF. За моїми особистими відчуттями MLX завантажується в памʼять значно швидше. Але пишуть, що швидкість генерації починає відчутно падати з ростом контексту. А нам якраз доведеться працювати з великим контекстом, тому, певно, краще одразу брати GGUF. Отже, стягнули модель, завантажили в памʼять. Можна прямо в LM Studio поспілкуватися в чатику, та сенсу в цьому мало. Натомість беремо OpenCode і додаємо цю модель туди (~/.config/opencode/opencode.jsonc): { "$schema": "https://opencode.ai/config.json", "provider": { "lmstudio": { "npm": "@ai-sdk/openai-compatible", "name": "LM Studio (local)", "options": { "baseURL": "http://127.0.0.1:1234/v1" }, "models": { "google/gemma-4-26b-a4b": { "name": "Gemma 4 26B A4B" } } } } } Далі запускаємо: opencode -m google/gemma-4-26b-a4b Ну, або просто opencode і вже всередині вибрати через /model. І вуаля — тепер у вас особистий локальний майже клод код 💻. Так, це вочевидь не Opus і, мабуть, навіть не Haiku, але для багатьох задач і цього достатньо! Пробуйте.
0
11
Все ж приємно бачити, що 💻 потроху позбувається класичних способів поцілити собі в ногу. Наприклад, усі ми знаємо, що C++ не ініціалізує змінні, і тому там може опинитися сміття, прочитавши яке можна піти за чужими адресами абощо. Ну, вгадайте шо? Більше ні! Точніше так, але є «але». void foo() { int d; // не ініціалізуємо bar(d); // хоба! — не UB } Раніше цей код призводив до так званої невизначеної поведінки (UB — undefined behavior), а нині вона вельми визначена: відтепер це нова категорія — помилкова поведінка (erroneous behavior). Утім це не значить, що ваші змінні почнуть раптом занулятися чи робити щось притомне. Натомість змінна отримає «невизначений» стан (такий собі undefined, який не можна перевірити). Стандарт ніби не описує, що саме там має бути, тож усі компілятори робитимуть на свій розсуд. Але тепер вони принаймні зобовʼязані написати помилку при спробі це значення використати (не обовʼязково під час компіляції — може бути і в рантаймі). А якщо дуже-дуже хочеться повернути UB, то можна використати новий атрибут 😆 void foo() { int d [[indeterminate]]; bar(d); // Фух, старий-добрий UB :) } З інших приколів: прибрали порівняння масивів. Раніше можна було писати так: int arr1[5]; int arr2[5]; bool same = arr1 == arr2; // тепер помилка Не те щоб хтось дійсно таке писав, окрім джунів на співбесідах. Та й компілятори на це скаржилися з 2019 року. Але новачків це все одно плутає, бо arr1 та arr2 — це просто вказівники на початок масивів, і такий код порівнює їхні адреси, а не вміст. Добре, що позбулися. Хоча знов-таки… Якщо дуже хочеться, то можна повернути стару поведінку, наприклад, через хак з приведенням типу до звичайного вказівника унарним плюсом 😅 int arr1[5]; int arr2[5]; bool same = arr1 == +arr2; // працює Отже, C++ стає дедалі суворішою мовою стосовно таких дрібниць, що в більшості випадків є хибним кодом, і водночас не позбавляє свободи. Може в цьому й полягає секрет, чого вона так довго тримається на плаву?
0
12
Тупий телеграм десь загубив мою превʼюшку посилання, і я не зміг її повернути )
0
13
Памʼятаєте, я колись розповідав, що Pebble воскрес? Так ось вони там конкурс програм запустили, і я нашвидку (за 16 годин плюс-мінус ще стільки ж) накарлякав прогу. Починав писати на 🕸, але якось так тяжко пішло, ще й ШІ-шка не допомагала, а радила маячню. Тому перемкнувся на 💻 — і одразу стало легше дихати. Накидав скінченний автомат, декілька візуальних шарів, збереження стану в постійне сховище, вивід з фонового виконання. До речі програмувати було значно легше, аніж дизайнити. Лише тільки для іконки, яка показується на годиннику в головному меню, довелося трохи спітніти. Хотів спочатку змусити ШІ-шку згенерувати мені SVG, але вийшло лайно. Тому завантажив її у Figma 💻, перемалював векторний path руками, експортнув — теж не сподобалося через відсутність піксельного вирівнювання. Далі зібрав із сирців Aseprite, завантажив туди експортовану PNG та попіксельно намалював руками. З анімаціями ще складніше. На Pebble викориcтовується власний векторний формат PDC (фактично прото бінарний опис команд для малювання), який підтримує лише path, circle та precise_path — навіть без кривих! Path від precise path відрізняються типом координат: у першого викориcтовуються uint16, а в другого — fixed point integer 13.3 (13 бітів на цілу частину та 3 біта на дріб). Існує якийсь скрипт 11-річної давнини svg2pdc.py на Python 2, але він працює вельми кепсько: підтримує лише SVG Tiny 1.2, до того ж згенеровані анімації були з артефактами. Щоб розібратися, написав парсер PDC на Kaitai Struct 🏗, а також посидів в ImHex. ШІ-шка мені нагенерила переглядач під бравзер. Скрипт урешті викинув — довелося написати власний. Самі анімації зробив у Figma покадрово й екпортнув кожний кадр як SVG. Прогнав скриптом — ніби норм. При публікації ще виявилося, що екран годинника зʼїдає кропаль пікселів на краях, тому додав відступ і переробив лейаут. Загалом задоволений: SDK доволі простий і прикольний, сішку не люблю, хоча цього разу зайшло норм, емулятор зручний, результат подобається. Тепер справа за вами! Якщо не западло, підіть накидайте мені лайків ❤️ там — дуже хочеться виграти собі годинник на дурняк 😂
0
14
Думав написати про це ще минулої середи, але ви мені тоді точно не повірили би 😄 Отже, в C++ тепер є новий різновид циклів — template for 🙂 Хочемо, ми, наприклад, написати функцію зі змінною кількістю аргументів, яка виводитиме значення в консоль: template <typename... Ts> void print_all(Ts... elems); print_all("foo", 42, 'p', 3.14); // використання Раніше довелось би писати щось отаке: template <typename... Ts> void print_all(Ts... elems) { (std::println("{}", elems), ...); } Ніби й зрозуміло, що elems розпаковуються в пачку виразів, кожний з яких — це println, але читається не дуже. Тому знавці використовували би, мабуть, 🐝 Boost.Hana. А в C++11 взагалі колись писали отак: void print_all() {} template <typename T, typename... Ts> void print_all(T first, Ts... rest) { std::cout << first << std::endl; print_all(rest...); } Тобто типовий ФП-підхід, де список ділиться на head:[tail] й обходиться рекурсивно, доки не дійде до порожнього. А тепер можна буде писати отак: template <typename... Ts> void print_all(Ts... elems) { template for (auto elem : {elems...}) { std::println("{}", elem); } } Усе це розгортається під час компіляції в щось на кшталт: template <typename... Ts> void print_all(Ts... elems) { { { auto elem = elems...[0]; // така індексація, // до речі, також // нова фіча std::println("{}", elem); } { auto elem = elems...[1]; std::println("{}", elem); } { auto elem = elems...[2]; std::println("{}", elem); } } } Працює template for не лише з пачками типів, але й з будь-чим. Наприклад, звичайними масивами. Так void f() { template for (constexpr int I : std::array{1, 2, 3}) { static_assert(I < 4); } } перетворюється на void f() { { constexpr auto&& __range = std::array{1, 2, 3}; constexpr auto __begin = __range.begin(); constexpr auto __expansion_size = __range.end() - __begin; // 3 { constexpr int I = *(__begin + 0); static_assert(I < 4); } { constexpr int I = *(__begin + 1); static_assert(I < 4); } { constexpr int I = *(__begin + 2); static_assert(I < 4); } } } Ну й ще багато чого можна робити звісно. Проте найкраще ця штука себе показує з новою рефлексією, про котру ще згодом напишу.
0
15
Перезавантажив увечері комп, що я роблю вкрай рідко, запускаю зранку бекенд через Docker Compose… а останній висить і ніц не робить! Взагалі. Я вже і кеші почистив, і докер перестановив — не допомагає. Хоча просто docker чомусь норм 🤔 Покрутив ще туди-сюди, docker compose --help принаймні повідомлення показує, а docker compose config лише порожнечу й тишу. Нарешті промайнула думка спробувати з іншим compose.yaml: створив новий майже порожній з Alpine, і о диво — спрацювало! Чого ж з моїм не працює? Поміркував, що могло піти не так, і погляд упав на .env. Виявляється, що після ребуту 1Password не змонтував цей файл, як я очікував. Тож на диску лежить unix pipe, з якого Compose першим же ділом намагається читати, а туди ніхто не пише! Ну він і чекає 😐 Отже, здобув +5 XP. Наступив на ці граблі, набив собі гулю — аби вам не довелося.
0
16
Там позавчора нарешті затвердили новий стандарт C++26, тож усіх вітаю. Тепер звісно доведеться почекати ще років 3–5–7, доки його імплементують у компіляторах, і все ж. Саттер каже, мовляв, це найпотужніший стандарт з часів C++11, тож дивитимуся потихеньку, що там цікавого додали. Сьогодні про одну з таких фічей мова. Мені завжди подобалося, як в 💻 (точніше SPARK) можна описувати перед- та постумови для функцій (приклад поцупив звідси): procedure Set_Speed (S : in out Speed_Knots; New_Value : Speed_Knots) with Pre => New_Value >= 0.0 and New_Value <= 1000.0, Post => S = New_Value; Віднині в 💻 теж можна буде так робити! Має бути щось на кшталт отакого: void set_speed(speed_knots & s, speed_knots new_value) pre(new_value >= 0.0 && new_value <= 1000.0) post(s == new_value); Ну або уявімо, що треба перевірити значення, яке повертається, то буде щось отаке: auto calculate(auto && val) post(r: is_valid(r)); Таким чином кількість того, що в C++ можна писати між блоком параметрів функції та її тілом, небезпечно наближається до Ada 🙂 Фіча зветься контрактами, якщо шо, і там окрім pre та post ще додали так званий contract_assert. На вигляд наче звичайний assert, як і був, тільки тепер не сішний макрос, а прям інструкція самої мови. Можна користуватися всередині функцій, щоб додати обрисів очікуванням від коду. Отже, загалом корисно на вигляд. Хоча спершу варто почитати правила, за якими ця фіча взаємодіє з іншими 😉 На закуску тримайте приклад, як це виглядає в трохи реальнішому коді. Тут вам і концепти, і контракти, і constexpr, і trailing return type, і structured binding. template <std::floating_point T> constexpr auto normalize(std::array<T, 3> vector) noexcept -> std::array<T, 3> pre(is_normalizable(vector)) post(vector: is_normalized(vector)) { auto& [x, y, z]{vector}; const auto norm{std::hypot(x, y, z)}; x /= norm, y /= norm, z /= norm; return vector; }
0
17
Пишу останні пару місяців на TypeScript. Доволі цікаво, як ця мова розвивалася. Якщо в тому ж Dart сіли й зробили нормальну й «звичну» типізацію, то в TS взяли JavaScript, який забагато всього дозволяє, і спробували це типізувати. Зокрема, типізація там структурна. Тобто на відміну від C++ не треба наслідуватися від якихось конкретних типів — достатньо переконатися, що всі поля і їхні типи збігаються. Тому type Foo = { a: string; b: number }; type Bar = { a: string; b: number }; const foo: Foo = { a: '42', b: 42 }; const bar: Bar = foo; працює без проблем. Ну й воно вміє там ті типи звужувати за потреби та ще багато чого робити. Відповідно, щоб типізувати принаймні стандартну лібу 💻, типочкам довелося добряче спітніти. Проблема лише в тому, що відносно легко всі ці перевірки типів обійти: стратегічно розставлені ШІ-шкою any та unknown ріжуть то все під корінь 😂 Але я поки по-дідівськи цією мовою кодю — руками. І робив оце функцію (React-компонент) для малювання певних даних у комірці таблиці. Вона очікує на вхід обʼєкт (рядок таблиці), з якого потім дістає ті дані з певних полів. Єдина проблема, що тип рядків може бути різним, бо воно до API підвʼязане. Дані там ті точно є, але поля не завжди називаються так, як треба. Вирішив зробити мапінг з одних на інші, щоб можна було писати щось типу: type Params = { fieldA: number; fieldB: number } // те, шо мені треба type Whatever = { megaFieldA: number; megaFieldB: number }; // якийсь інший тип func(whateverObj, { fieldA: 'megaFieldA', fieldB: 'megaFieldB' }); і тоді всередині я очікую fieldA і fieldB, але діставатиму їх за іншими іменами. «Але було б прикольно це типізувати, щоб не відстрелити собі ногу» — подумав я (бо після C++ ніг не так щоб багато лишилося). І це дійсно можна там зробити! type MyKeyMap<SourceType> = Partial<{ [K in keyof Params]: keyof SourceType; }>; Тобто ми тут буквально пишемо, що маємо обʼєкт, ключі якого мають бути ключами Params (з яким працює мій компонент), а значеннями — ключами SourceType (пофіг якого, бо це дженерік). Ну й Partial на всяк, щоб не обовʼязково було всі поля мапити, якщо імена збігаються. І компілятор такий чік-чік — перевірив. Тобто отой 'megaFieldA' вгорі може й виглядає як текстовий рядок, але по факту компілятор знає, що це назва поля в обʼєкті. Прикольно! До речі, C++-програмістам, які JS ніколи не вчили, а просто почали його використовувати в якомусь QML, запис з квадратними дужками на місті ключів здаватиметься дивним. Але насправді це звичайна фіча JS, коли треба зробити обʼєкт з ключем, який представлений не рядковим літералом, а виразом. Тобто замість: let foo = {}; foo[someVal + 1] = 'blabla'; можна написати просто const foo = { [someVal + 1]: 'blabla' }; Тому я завжди раджу книжки читати, навіть якщо здається, що мова не «основна». Ну а щодо 🕸 не дивно, що він здобув таку популярність врешті, бо писати React на чистому JS просто неможливо. Це повна дупа була б.
0
18
Сьогодні про корисне й актуальне. З усіма цими вашими ШІ-агентами штибу клода й копайлота яка проблема? Вони полюбляють позапускати мутних команд у процесі дослідження або написання коду, і далеко не всі з них безпечні. Тож ви або сидите й кожну з них затверджуєте, або дозволяєте йому робити що завгодно (звісно ні). Ну, або треба щось думати про ізоляцію. От якби закинути все потрібне в пісочницю, то можна було б не надто хвилюватися, що він там запускає — принаймні домашню теку вам не знесе. Як сказав тут один мій товариш: «сендбоксити ж не складно» 🧐 І якщо ви такі ж, як він, то шо я можу сказати… Вітаю! Я ось ніколи цього не робив, і мені складно. На щастя, не так давно дізнався про існування docker sandbox — і це штука, яка спрощує життя! Замість claude просто запускаєте у своєму сховищі docker sandbox run claude і вуаля! Воно підіймає мікровіртуалку (так, не контейнер), монтує теку вашого проєкту за тим же шляхом(❗️) і навіть прописує 💻 git config! Ну й запускає сам Claude Code звісно, причому в режимі вседозволеності. (Щоправда, на початку автентифікуватися просить, тому щоб руками це не робити, краще передавайте ключ через змінні оточення перед запуском). Там, до речі, не тільки Claude Code є: той же OpenCode також присутній. А то й можна навіть кастомне щось собі зібрати. Не бачу тільки згадок про підтримку лінукса 🤔 Наче лише macOS 🍏 та Windows 🪟.
0
19
Засмутили ви мене того тижня — жодного коментаря 😢 Шо, ніхто не відстежує час, витрачений на проєкти? Ну то таке… Сьогодні х
Засмутили ви мене того тижня — жодного коментаря 😢 Шо, ніхто не відстежує час, витрачений на проєкти? Ну то таке… Сьогодні хотів знову зачепити тему роботи з «секретами» при розробці проєктів, а саме: з паролями, API-ключами, токенами тощо. Мені особисто дуже муляє око, коли вони у відкритому вигляді на диску лежать, навіть якщо цей файл не потрапляє в ґіт. Ну, власне, тому я їх відкрито вже давно й не тримаю. Колись уже розповідав, як використовую 1Password для підписування комітів та роботи з Ansible 💻. А сьогодні хотів трохи написати про .env-файли. Проблема з ними якраз і полягає в тому, що вони в ґіті не зберігаються. Тобто щоразу, як зробив чистий клон проєкту, треба цей файл руками створювати. Звісно, можна покласти .env.example, в якому принаймні назви всіх змінних будуть, але спробуй ще згадай, де і як ти ті ключі та токени отримував. У мене їх десятки, всі з різними правами й скоупами, і я швидко починав у цьому губитися. Тому нині мої .env на вигляд зазвичай приблизно отакі: GITHUB_TOKEN="op://Work/repo-name/wrxqfrltnqlzgako6zx6fjak6m/GITHUB_TOKEN" TF_VAR_github_app_private_key="op://Work/repo-name/private key" TF_VAR_crowdin_token="op://Work/repo-name/CROWDIN_PERSONAL_TOKEN/value" TF_VAR_discord_webhook="op://Work/repo-name/DISCORD_WEBHOOK_URL/value" TF_VAR_rclone_config="op://Work/repo-name/RCLONE_CONFIG/value" Вочевидь, тут нема жодних секретів, які не можна було б зберігати в системі контролю версій, бо значення змінних — це просто посилання на конкретні записи 1Password. До того ж не треба взагалі нічого міняти: зробив клон — і все одразу працює. Єдиний мінус полягає в тому, що тепер замість умовного terraform apply доводиться писати op run --env-file=".env" -- terraform apply Я, звісно, махав це щоразу руками друкувати, тому використовую just, про який теж неодноразово вже згадував. А нещодавно дізнався про ще одну нову альтернативну фічу 1Password (наразі бета). Тепер вони дозволяють створювати різні оточення зі своїми наборами секретів прямо в їхній програмі. І потім такі оточення можна монтувати за певним шляхом як .env-файл. Але! Файлу насправді нема 🙂 Замість того, щоб записувати ці всі секрети відкрито на диск, вони просто створюють іменований жолоб (pipe по-вашому): щойно хтось намагається прочитати звідти дані, 1Password просить вас авторизувати цей запит і передає значення прямо в програму! Ніби нічого складного, але доволі креативний розвʼязок до проблеми. Переваги підходу в тому, що ви запускаєте всі свої тулзи як зазвичай — без жодних op run. А головний мінус для мене: наразі все ж не дуже зручно цим керувати. До того ж після клонування треба заходити й монтувати це оточення в потрібну теку. Тож для себе я вирішив лишитися на попередньому варіанті. Взагалі подобається, що 1Password не стоїть на місці й постійно розвивається. Але не подобається, що вони й так не дешеві, а скоро ще й піднімають вартість передплати 🥲
0