Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
01.09.2025
Підключення миші з Bluetooth до Mac... без миші!
Маленьке продовження історії з Mac Mini. Взяв з собою стару мишу, щоб не відʼєднувати свою основну. Та тут виявляється, що вона не спарена! А іншої миші немає. Що робити?
Я надіявся, що все працюватиме з клавіатури. Відкрити системні налаштування через Alfred тривіально. Далі намагаюся клавішею Tab
добратися до налаштувань Bluetooth… а вона не табулює! Точніше, табулює, але тільки між пошуком та переліком розділів. А у сам розділ, в головну панель не входить.
Я трохи часу побув в шоці. Спробував знайти команди термінала для Bluetooth, але не вийшло. Згадав, що є така штучка, як Mouse Keys
- керування мишею з клавіатури — але ж щоб її увімкнути треба так само зайти в налаштування. Хотів залучити AppleScript - та виявилося, що навіть у стандартному діалозі “Дозволити програмі керувати…” табуляція теж не працює!
А потім розшукав, що за замовчуванням на macOS табуляція не проходить по всіх елементах інтерфейсу, а тільки по деякім. На то є налаштування Keyboard navigation
… яке, о диво, можливо змінити через термінал! defaults write NSGlobalDomain AppleKeyboardUIMode -int 3
та нарешті я зміг дістатися до потрібних налаштувань та підʼєднати мишу.
Тепер раджу всім перевірити, що у вас цей режим увімкнений, бо хтозна-коли він може знадобитися.
(PS: а ще можна підʼєднатися до Mac Mini вже налаштованим віддаленим доступом з ноутбука чи навіть телефону та тамтешнею мишею зробити все необхідне. Але це вихід для слабаків.)
(PPS networksetup -setairportnetwork en1 SSID PASSWORD
, щоб з термінала підʼєднатися до незнайомої мережі. Хоч тут все прямолінійно!)
31.08.2025
Проблеми з i18next
Вчора в підтримку Сінтри надійшов лист про те, що у нас поламані листи підтвердження підписки. По-перше, дякую автору, бо небагато хто б потрудився це зробити. По-друге, чи це ще один випадок недостачі моніторингу та насамперед тестування в проєкті двох людей? Авжеж! Бо помилка сиділа роки з два. (І ні, це далеко не перша підписка за цей час.)
Помилка крилася в неправильному шаблоні для i18next. В нас там цікаве рішення для шаблонів листів. Технічно вони використовують “Handlebars”, але на практиці шаблони стають просто рядками перекладу для i18next.
Причин було відразу дві. Одна прямо зовсім проста — неправильний префікс ключа. Знаєте, в i18next можна написати підписка на $t(subscription_interval.{{interval}})
та підставити туди, наприклад, subscription_interval.monthly
. Дуже зручно. Але на це немає перевірок — якщо такого ключа немає в словнику, i18next підставить сам ключ. Що й відбулося, бо я банально переплутав subscription_interval
та subscription_period
.
Зате рівно тільки що дізнався, що є налаштування відсутніх ключів — в тому числі обробник missingKeyHandler
, який міг би кинути помилку.
Друга причина — в моєму форматувальнику дат формат читається з того ж словнику. Дуже зручно (та може варто окремої розповіді.) Але. Словник же ж потребує обраної мови! На фронтенді це працює зрозуміло: у нас є мова користувача, вона встановлена глобально. А на бекенді немає “глобально обраної мови”, бо бекенд надсилає пошту до всіх користувачів. Тому виходило так, що в пошті цей форматувальник не знав мови, використовував хибний формат (знову без помилки…) та видавав сміття.
Розвʼязалося все передачею мови параметром lng
: format = i18next.t(format_name, {lng: userLanguage})
.
Отак, наче нічого складного, але години дві витратив. До речі, дуже допомогло те, що в мене принаймні були скрипти для генерації тих листів.
30.08.2025
Сучасна спадщина Thief
Після минулого поста про Thief я загадався над питанням — чи є сучасні ігри, які її нагадують? Виявилося, що жанр thieflike практично відсутній. Зокрема виділю, що сучасні ігри дають гравцю або високу мобільність, або можливість битися. А весь смак Thief - в обмеженні й того, й іншого. Та рідко хто відтворює механіки як світла, так і звуку на такому ж рівні, як будь-який Thief.
Зате! (А може — через це!) Як виявилося, фанатська сцена для Thief жива й досі. Причому як мінімум у двох формах.
Є The Dark Mod - це фактично повна реалізація механік Thief на рушії Doom 3 (або id Tech 4, якщо педантично.) З відкритим кодом та абсолютно безплатна! Причому The Dark Mod знаходиться в активній розробці, остання версія вийшла березня цього року. Замість звичайного сюжету тут є можливість завантажувати місії з каталогу, де їх наразі майже 200.
Не впевнений, що без досвіду Thief воно гладко зайде концептуально, але в цілому The Dark Mod, мабуть, найкращий спосіб пограти “в сучасний Thief” з усіма механіками та сучасною графікою.
Але насправді мені в старих іграх заважає керування та зручності, а не власне графіка. Зі старою графікою я готовий жити. Та якщо тобі так само, то для Thief 1 є чудовий мод TFix, який прибирає всі вікові недоліки. Там і рушій оновлений, і широкий екран підтримується, і з керуванням проблем немає. (Аналогічно для Thief 2 є T2Fix. Це взагалі дві дуже схожі гри.)
Та що ще крутіше — на Thief 1 та 2 існує досі жива спільнота фанатських місій! Їхня кількість вражає — на Archive.org є архів у 40 Гб рівнів, що у 20 разів більше за розмір обох оригінальних ігор! Та з TFix їх достатньо закинути в одну теку та запускати спеціальною оболонкою. Взагалі найкращий ресурс для фанатських місій - це форум Through The Looking Glass, але він щось не дуже стабільно працює.
Виходить, Thief приєднується до родини старих ігор, що живі завдяки фанатам — як Quake чи Doom. Дуже приємно.
29.08.2025
Раптові витрати памʼяті та куди дивитися
Довелося цього тижня зʼясовувати, чому застосунок на Rails несподівано почав споживати на кілька гігабайтів памʼяті більше. Поверхнево причина була зрозуміла — бо в цей застосунок зайшла частина іншого застосунку, відбувається таке собі злиття. Та тут й крилася проблема: в проблемний реліз потрапила ціла пачка наче безпечних змін — загальним обсягом десь у 20 тисяч рядків. Ну й що з нею робити?
Перша теорія — що це сам код витрачає стільки памʼяті — мені відразу здалася неправдоподібною. Код взагалі не дуже споживає памʼять, навіть в інтерпретованій мові. Продукти виконання коду, тобто стан — можуть. Але тоді стає питання — де той стан зберігається, бо зазвичай у вебзастосунку весь стан відкидається по закінченню запиту.
Почав перевіряти нові константи та класові змінні — ну, знайшов кілька сотень регулярних виразів. Зробив швиденько скрипт, щоб просто завантажити ці вирази та подивитися витрати памʼяті — а вони мінімальні. Ну і якщо чесно, то прямо гігабайти стану це треба ще вигадати, ніхто такого в Ruby не робить. Втім, треба ж шукати причину…
А варто було з усіх змін відразу подивитися на зміни в залежностях. А тут — в проєкт підтягнувся славетний гем mini_racer - обгортка рушія V8 для Ruby. Відчуваєте вагу? V8 це вам не купка регулярок!
Отже, виявилося, що з деяких причин версія mini_racer
була старуватою, та мала проблеми із Ruby 3.4, або може з свіжим сервером Puma - в будь-якому разі, щось заважало цьому гему звільняти старі контексти V8, та вони й засмічували памʼять. Оновленням гему все розвʼязалося.
У таких випадках раптових змін завжди є конкретна причина, залишається її знайти.
28.08.2025
Розробка на iOS для себе
Може хтось хотів би почати розробляти для iOS - просто для себе щось зробити — але зупиняє знаменитий цінник в $99 на рік за програму розробників. Хотів би прояснити кілька питань — бо не все так погано.
Програма розробників потрібна для розповсюдження застосунків через App Store. Без неї не вийде навіть вивантажити в Test Flight - сервіс для бета-тестування. Це дійсно так.
Але, окрім того, є також встановлення ad hoc, та воно не потребує платної програми. Щоб встановити застосунок на свій iPhone, достатньо мати компʼютер з macOS, встановити на нього XCode (безплатно з App Store), та авторизуватися будь-яким обліковим записом. Потім підʼєднуєш до компʼютера айфон, дозволяєш доступ туди-сюди, і все — можна обирати запуск застосунку на iPhone. А запуск — то і є встановлення, бо після відʼєднання застосунок залишається.
Такий застосунок житиме тиждень. Точніше, тиждень — це термін профілю забезпечення, як профіль вибіжить — то застосунок стане недоступним. Щоб повернути його. достатньо ще раз запустити з XCode. (До речі, з платною підпискою цей термін збільшується до року.)
На одному айфоні можна встановити лише три застосунки. Це теж обмеження безплатної версії. Хоча, бачите, для того, щоб зробити застосунок для себе чи просто випробувати середовище цього більше ніж достатньо.
Також застосунки можна встановлювати й на чужі пристрої, якщо вони не проти погодитися “довірити дані цьому компʼютеру”. Не обовʼязково айфону та маку належати одному акаунту. Хоча, мабуть, більше обмеження — це те, що щотижня доведеться встановлювати наново. Але якщо є бажання зробити щось сімейне — то й це цілком можливо.
До речі, за таким принципом працює AltStore та кілька інших “альтернативних майданчиків” для застосунків. Та для них теж не потрібна платна підписка, якщо вище зазначені обмеження влаштовують.
Щоб все це перевірити, довелося встановити XCode дружині, бо в мене-то платна підписка є. Тепер вона теж трохи розробник. А от — для повноти — з дитячим обліковим записом встановлювати застосунки взагалі не дозволено.
27.08.2025
Як зробити проєкт на Go огидним, щоб ніколи більше не писати цією мовою
(Основане, на жаль, на справжньому досвіді.)
Звалити весь код в один пакет. Навіщо нам ці дивні імена з великої літери? Пакети відокремлюють вузли коду. Коли все в одному пакеті — дійсно виходить один великий вузол. І не треба відкладати розбиття на пакети на потім, краще починати новий пакет на кожну потребу, тоді не доведеться його розплутувати.
Використовувати рівночасність без потреби. Я чув, у Go ефективні горутіни — треба брати, щоб було швидше! Памʼятай, що які б вони не були ефективні — а розуміння коду ускладнюють так само. Тому впроваджувати горутіни варто тільки коли послідовне виконання обʼєктивно триває надто довго. Та намагатися відокремити їх від бізнес-логіки, щоб її можна було спокійно зрозуміти та протестувати.
Не писати тестів. В типізованій мові тести не потрібні. Згодний, що типи дозволяють не писати примітивних тестів на узгодженість. Але принаймні типи на рівні Go нічого не кажуть про логіку програми! Тому тести повинні перевіряти логіку виконання, а також — дуже важливо — її документувати.
Використовувати динамічні типи. Типи це чудово. Але я тут читаю JSON, розумієте, тож треба перевіряти кожне поле. Парсер за вас сам перевірить. Динамічні типи та рефлексія — це, певно, найскладніший код в Go, тому їх теж треба виносити в шар абстракції для конкретної потреби, далеко від загального коду. А скоріше — використовувати чужий. Та боже збав вас від “гнучких” методів з динамічними аргументами…
Не слідувати звичаям. Як (моя улюблена особливість JS, Ruby чи Java) робиться тут? Go - це мова з міцними переконаннями. Та це не та мова, яка дозволить вам вигадати власний стиль. Тим паче запозичити стиль з іншої мови, яку ти знаєш. Я не кажу, що звичаї Go найкращі, але принаймні їх доведеться прийняти, а не йти проти них. Думай про це так — без вагань над стилем в тебе буде більше часу на написання корисного коду. Бо це правда.
26.08.2025
Low Magic vs High Magic
Різниця між середовищами розробки не закінчується на типізації та керуванню памʼяттю. Важливою ознакою є те, наскільки багато “магії” - тобто коду, який працює “невідомо як”.
Розглянемо маршрутизацію для вебу. В Express.js чи Gin для Go звʼязок між маршрутами та обробниками очевидний - бо ми передаємо їх явно. Звісно, всередині маршрутизатора є багато коду, який ми не знаємо, але головне, що ми бачимо той наш код, який буде виконано. А значить, навіть людина, незнайома з таким фреймворком, зможе прочитати код застосунку та здогадатись, що відбувається.
В протилежність: маршрутизація в Ruby on Rails. Маршрути тут вказують на… щось? Після читання документації можна зрозуміти, як формується назва контролера та його метода, що буде виконано. Але це суцільна магія — нічого в коді на це не вказує. Така саме ситуація в Rails, наприклад, зі структурою моделей (яка взагалі читається прямо з бази наживу.)
Може така магія робить код красивим та зберігає від зайвої писанини. Проте також вона так ускладнює роботу IDE, що досі підказки по коду для Rails потребують спеціалізованого підкажчика, який “розуміє” Rails, а не просто читає код. Та й людям, очевидно, не так легко встрибнути.
Мене колись давно саме ця магія й відштовхнула від Rails - бо з першого погляду застосунок складається з купи неповʼязаних між собою класів. А цілісна картина зʼявляється тільки після читання документації. Після всієї цієї магії застосунок із Gin освіжує своєю прямолінійністю.
25.08.2025
Робота в незвичайних місцях
Ні, я не про роботу наодинці, бо з ноутбуком можна сісти де завгодно, це зрозуміло. Проте памʼятаю я кілька епізодів, де ми разом вилазили з офісу. Та не просто “говорили про роботу за обідом”, а дійсно працювали. Завжди це було гарно: зміна обставин надихає на творчі, сміливі ідеї.
🍃 Одного разу, дуже давно, ми з керівництвом просто вийшли в скверик неподалік, щоб обговорити майбутню архітектуру. Була весна, світило сонце, навколо все зелене. Чому так частіше не робити?
🍸 Другого разу, вже зовсім іншою командою, посеред дня зібралися та пішли до бару планувати проєкт. (Ще я там першого разу скуштував теплі оливки - звучить дивно, але насправді гарна закуска!) Бар - це якийсь особливий настрій для роботи. Навіть просто прийти з ноутбуком раджу спробувати. Тільки краще з чимсь таким, для чого потрібний політ фантазії, а не концентрація.
☕ Є в мене й проєкт, що повністю робився в кавʼярні, і це теж було чудово. Зустрічатися та працювати - завжди було продуктивніше, ніж робити теж саме віддалено.
🌚 А ще памʼятаю, як на офсайті лежали на шезлонгах біля басейну десь до пʼятої ранку та говорили за стратегію. На офсайтах це природніше виходить, звісно, бо люди всі разом. Але можна ж і частіше збиратися та я не знаю, виносити наради з офісу. Або самому виходити. Або - брати людей що вже поруч та з ними разом щось вигадувати?
🏘️ Розумію, зараз складно взагалі зібратися в одному приміщенні. Але коли вдається, не нехтуй тим творчим зарядом, який дає незвичайне місце. Бодай навіть наодинці.
24.08.2025
Надлишок проєктів за браком цілей
В мене довгий час була проблема (я про неї навіть писав), що я починаю надто багато проєктів, а потім не встигаю їх робити та як результат система розвалюється.
Та от нарешті зрозумів, що щоб такого не було, над проєктами повинні бути цілі. Ціль — це щось, чого ти хочеш досягнути протягом одного-двох років. Вони, гадаю, у всіх абсолютно є, але не завжди усвідомлені. Насправді якщо йти знизу догори та передивитися той же ж список проєктів, то цілі повинні промальовуватись.
Є проєкти, які очевидно належать цілі: наприклад, “обрати фарби” до цілі “закінчити ремонт”. Для таких проєктів я отримую додаткову мотивацію від розуміння, задля чого воно робиться.
Є такі, де ціль народжується в процесі. Я так знайшов у себе ціль “вибудувати режим” з наче неповʼязаних спочатку проєктів-спроб щось потрохи покращити. Тут наявність цілі відкриває творчий потенціал та можливість вичерпати всі напрямки.
Ну й нарешті багато з чим стає питання “щоб що?” Завжди є справи заради інтересу чи задоволення - то нормально. Проте це коли вони рухаються та не створюють проблем. А коли застрягли та висять - вдається спокійно скасувати без відчуття втрати.
Ставити собі цілі не так страшно, якщо прийняти, що вони в тебе вже є - залишилося тільки їх знайти.
23.08.2025
Кілька пакетів для Go, які я ймовірно приніс би у ваш проєкт
sqlc - генератор коду для запитів SQL. Я не прихильник ORM, принаймні на Go, а sqlc
робить доступ до бази рівно настільки безпроблемним, наскільки мені потрібно.
testfixtures - в продовження теми, без ORM не дуже налаштуєш стан бази для тестів, так от я люблю цей пакет. Причому, щоб не писати кілометрові фікстури, я б тестував тільки шар доступу до бази, а все що вище — із затичками поверх коду, згенерованого sqlc
.
mockery - а затички я б генерував цим інструментом, з ним мінімум ручної роботи. Менше роботи руками — більше якісних тестів.
testify - не всі використовують його для зручних тестів, та дарма. Тут є assert
- зручні перевірки на всі випадки. suite
- спрощення для спільного для тестів оточення. Та ті ж mock
- для затичок.
slog - з тої пори, як зʼявився вбудований пакет для структурного журналювання, ніякі інші мені не потрібні. Плюс він автоматично споживає й вихід зі звичайного log
, тобто не обовʼязково все переписувати, достатньо налаштувати.
lo - тут чимало зручних допоміжних функцій, зокрема для дженериків. Прямо все на нього переписувати не варто, але час від часу щось по типу Compact
гарно мати під рукою.
conc - абстракції для рівночасності, щоб не писати кожен раз свої. Знов-таки час від часу conc
робить рівночасну обробку чимсь невимушеним, таким що не потребує додаткової задачі та години роботи.
А у вас є такі пакети, які ходять з проєкту в проєкт, бо просто роблять життя краще?