Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
10.04.2023
Оновлення для go-global. Особливості рефлексії для типу map в Go.
Сьогодні зробив для go-global - нашого пакета для завантаження конфігурації з AWS Parameter Store - маленьку фічу. Пакет цей бере дані з Parameter Store. Там вони мають пласку форму “ключ-значення”, причому значення можуть бути тільки рядками. Але ми хочемо отримати їх у вигляді конфігураційної структури з вкладеністю та з типізацією. Для цього й існує go-global.
Але річ у тім, що він не підтримував тип map - тільки структури та, з недавнього часу, масиви. Структури це добре, коли всі ключі відомі. Але зʼявилася потреба завантажувати словник з невідомими ключами.
Здавалося б, закинути дані в map - це ще простіше, ніж у структуру. Навіть не треба шукати поле за тегом. Але насправді це невеличке розширення функціонала призвело до серйозного перероблення та переосмислення всього підходу.
Як воно взагалі все працює: через рефлексію. В першій версії бібліотеки я крок за кроком спускався по конфігураційній структурі, поки не знаходив reflect.Value, що відповідає місцю, куди треба записати параметр. А потім записував в нього значення. В принципі нічого складного там не було; найскладніше — це, мабуть, створення нових екземплярів обʼєктів, коли стикаєшся з нульовими вказівниками.
Але. Тип map, як виявилось, все це ламає. Бо він в Go особливий. Елементи map, не підлягають адресації. На них не можна зробити вказівника — це раз. Але також, як наслідок, при рефлексії неможливо отримати таке посилання на елемент, яке дозволяє запис. Елементи треба записувати спеціальною функцією SetMapIndex. Так що мій рекурсивний пошук місця призначення більш не підходив.
(Обурений екскурс. Ці приховані особливості всіляких типів — те, що я в Go понад усе не люблю. Абстракція “простих” типів тече. В нульовий слайс можна записувати, а в нульовий меп — ні. Оці проблеми з адресацією. І таке інше… Після того, як я нахвалюю Go, соромно початківцям про ці деталі розповідати.)
Спочатку хотів синтезувати якийсь замінник для “адреси” місця призначення. Може, повертати функцію-сеттер. Але так і не зміг розвинути цей підхід.
Натомість перегорнув весь алгоритм догори ногами. По-перше, тепер я спочатку будую з параметрів абстрактне дерево. Потім, замість пошуку кожного параметра окремо, я роблю обхід цього дерева в глибину, та наповнюю конфігурацію, починаючи з найглибших частин.
Що це дає: коли справа доходить до типу map, то ми спочатку повністю наповнюємо значення кожного елемента, а потім записуємо його в map функцією SetMapIndex. Якось так. В результаті вийшло навіть не дуже складно, хоча без повного переосмислення я б до такої версії не прийшов.
Та, до того ж тепер я відокремив всю цю складну логіку від конкретно AWS Parameter Store, та її можна досконало протестувати. А в майбутньому, може, й додати інші сховища; взагалі для цього є Viper, але в нього філософія відрізняється від нашої.
09.04.2023
Почав робити фотозвіт про походи
В рамках фреймворку “хочу — не хочу” взявся, нарешті, за звіти про подорожі. Річ у тім, що в мене лежать сотні красивих та цікавих світлин, з яких давно мрію збирати звіти, але, як це буває, ніяк не знайду часу.
Одним з аспектів прокрастинації є те, що хочеться відразу дуже технічно крутий підхід, на кшталт статей з New York Times з анімаціями, картами, крутою типографікою і так далі. Звісно, все це я не вмію робити. Тому, щоб зрушити справу, хочу почати з чогось простого На жаль, я не ідеальний, тому найпростіше рішення — пост зі світлинами — мене не задовольняє. Як не задовольняє і галерея без тексту.
Зі зробленого сьогодні: обрав похід (а це теж не так просто; треба було щось ізольоване, але цікаве); відфільтрував світлини від дублікатів та сміття; написав текст. Тепер залишилось зібрати все до купи та, напевно, видалити ще багато фотоматеріалу.
Для перегляду світлин обрав поки lightGallery. За задумом галерея має бути не одна, а по одній на кожний параграф, та ще й з цікавим макетом. Тож наступна технічна задача — організувати структуру документа з тексту та галерей. Та, в ідеалі, щоб все залишалось в Markdown.
Знайшов отакі рекомендації по розміру картинок від Shopify; виходить 2240x1260 пікселів як максимум. До речі, щоб підігнати картинки під розмір однією командою — беру ImageMagick - командою mogrify -resize 2240x1260 *.jpg. А для остаточної оптимізації розміру є утиліта ImageOptim, якою я теж постійно користуюсь.
Ще є корисний додаток PeakFinder, який підписує гори; причому він вміє це робити як по камері, так і по старій світлині. Та, він навіть працює на macOS, хоча і в версії для iPad.
(Якщо є готові, відкриті інструменти для створення матеріалів “як у Нью-Йорк Таймз”, буду дуже рад дізнатись.)
08.04.2023
Що робити з рефлекторними відволіканнями?
Отже, вчора я зʼясував, що головна перешкода в роботі — то рефлекторні відволікання, що виникають, коли натрапляєш на складне місце. Поставлю мету їх позбавитись. В ідеалі, робота над задачею має починатись, тривати безперервно, та закінчуватись. Або свідомо перериватись на відпочинок. Але не на спонтанну перевірку новин.
(О, до речі, всі активні відволікання — тобто повідомлення та інше — в мене давно вимкнені назавжди — окрім найкритичніших. Бо фокусуватися на роботі, коли булькають месенджери — це взагалі для мене неможливо.)
Як вже писав, спочатку треба зупинити себе. Поставити, так би мовити, breakpoint. В цьому допоможе Screen Time. Він потрібен не для того, щоб все заблокувати та викинути ключі — я доросла людина. Головна мета тут — побачити, коли відвертаюсь. Блокую ресурси — додатки чи сайти — на які заходжу частіше за все. (Список таких ресурсів треба неодмінно оновлювати за актуальністю.)
Тепер, наступного разу, як під час роботи побачу екран блокування, задам собі питання — чому відвернувся? Що стало причиною? Яке питання чи ускладнення? Його треба записати, щоб не загубити. Далі розвʼязую питання будь-яким доступним способом. (Можна тут згадати про “стратегії навскіс” - це набір “порад” для розблокування творчих задач.) Але взагалі, в типовій ситуації немає великої проблеми в тому щоб просуватися далі; головне це залишатися сфокусованим на роботі.
Звісно, всіх ситуацій Screen Time не покриє, і так само треба стежити, коли хочеться сходити за кавою, або перевірити телефон, або робити ще щось, окрім поставленої задачі.
Тобто моя нова стратегія така: помічаю, коли відвернув увагу від роботи — записую причину — розвʼязую — рухаюсь далі. Помітити — ключове, та записати — теж ключове. Спробую тиждень та розкажу.
07.04.2023
Відволікання
Сьогодні пост про відволікання. В контексті, звісно, програмування. Для мене відволікання - YouTube, перевірка стрічок, копання в інтернеті — безумовно є головним крадієм результатів та часу. Останнім часом я спостерігав за собою, бо хочеться покращити робочий процес.
Найпростіше — то коли опиняєшся в стані потоку, бо тоді абсолютно байдуже, що відбувається навколо, та вся увага зручно орієнтується на задачі. Проте з відволіканнями це мало допомагає, бо потік викликають творчі задачі на грані здібностей — такі зустрічаються не кожен день. Не думаю, що самі відволікання заважають увійти в стан потоку; хоча припускаю, що вони заважають тим, що не дають “розбігтися”.
Коли треба приділяти до задачі особливу увагу — наприклад, при складному дебазі — будь-які відволікання відразу дратують та хочеться опинитись в повній тиші та ізоляції. Але тут великої проблеми не має, бо відволікатися не хочеться.
Для простої роботи є фонове відволікання — слухове. Можна слухати шум кафе, музику, подкаст, ютубчик. Це не заважає, а допомагає сконцентруватись на роботі, коли вона не дуже складна, а особливо — якщо монотонна. Моя теорія в тому, що такий фон створює “барʼєр уваги”, та допомагає залишатись на задачі, а не уходити думкою далі. Тобто увага може комфортно перемикатися від роботи на фонові звуки, а головне — назад.
Але типова повсякденна робота не має постійний рівень складності. Найбільшу проблему для мене ставить рефлекторне відволікання. В піки підвищеної напруги — наприклад, коли треба прийняти рішення, або коли щось не сходиться — я переживаю, фактично, рефлекторне бажання перемикнутися на щось інше: перевірмо, що там в новинах?. Рефлекторним я його вважаю тому, що зазвичай спочатку відволікаюсь, а вже потім це помічаю. Ще гірше, коли це відбувається несвідомо; бо при повертанні до роботи опиняєшся в тому самому складному місці, і в зовсім найгіршому сценарію знову відскакуєш до відволікань — так реально можна марнувати цілі дні. Аж допоки задача не стане терміновою. Терміновість, безумовно, допомагає концентрації.
Щоб не очікувати, поки все горить, треба щось робити. Про це завтра.
06.04.2023
Транспайлери JavaScript та цільова версія мови
JavaScript - це, наскільки я знаю, єдина мова програмування, яка компілюється сама в себе. Це створює унікальні обставини. Ніхто вже багато років не хоче писати на тому JavaScript, який працюватиме в будь-якому браузері (хоча за останні десять років ця планка просто злетіла завдяки зникненню Internet Explorer.) Ні, ми пишемо сучасною мовою з усіма можливостями - async/await, null coalesce і так далі. А які середовища будемо підтримувати — залежить від нашого компілятора, точніше, транспайлера.
Зазвичай налаштування транспайлера за замовчуванням всіх влаштовують, але деколи доводиться робити зміни; так в сьогоднішній версії пакета mailtrap ми за недоглядом втратили підтримку старих версій Node.js.
В TypeScript є опція target, яка вказує, який саме стандарт JavaScript буде підтримувати скомпільований код. Який стандарт обрати — вгадайте сами. (Довідка радить ES6.) До того ж є окрема інструкція по вибору версії для Node.js - Node Target Mapping. От на неї ми й отримали проблеми, бо поміняли ціль з es5 на es2020 та втратили підтримку Node.js старіше за 14.
До речі, на сайті Node.js є сторінка з переліком версій, що ще підтримуються; підтримка версії 14 припиняється наприкінці цього місяця. Але, як бачите, це не заважає деяким командам продовжувати користуватись і старішими версіями.
А в Babel це налаштовується через @babel/preset-env. Це дуже зручно, бо дає вказати не тільки конкретні версії браузерів, які ми хочемо підтримувати, а й просто сказати: “99.9% ринку” чи щось схоже. Далі, чим старіше обрані браузери, тим більше нашого коду буде замінено на спрощений.
На останок, компіляція в іншу мову програмування — дуже поширений підхід. Так роблять майже всі компільовані мови програмування. А саме, компілюють вони в мову C, для якої вже є надійний та перевірений компілятор та пакет інструментів GCC. Генерація машинного коду — складна задача, та простіше перекласти її на GCC, ніж робити це наново.
05.04.2023
Заміна DNS на власний — коли це потрібно та як це зробити
Якщо ваша бізнес-логіка спирається на DNS, то цілком логічно мати тестове середовище, де DNS контрольований. Тоді можна перевірити різні випадки — який запис є, якого немає, що за значення повертає і так далі. Але, DNS здається таким глибоко системним сервісом, що торкатись його здається неможливо (хіба що /etc/hosts міняти, але то дуже обмежено.)
Насправді зробити свій DNS-сервер досить нескладно; принаймні на Go для цього є проста бібліотека, з якої можна зібрати свій простий сервер (ось приклад). Все, що вам потрібно — це приймати деякі DNS запити та відповідати на них; решту можна або не обробляти, або передавати іншому серверу (як 99.9% DNS серверів в інтернеті й роблять.)
Я колись давно робив сервер, що перекриває DNS записи за розкладом. Така була міра обмеження відволікань. Досить ефективно працює, до речі — особливо якщо не зробиш можливість вимкнути. Бо пізніше я перейшов на більш функціональний Pi-hole, так от там вже можна було припинити блокування через вебінтерфейс. А зараз взагалі цього не роблю.
Залишається, щоправда, останнє питання — як підʼєднати той сервер до вашої тестової системи? Тут проблема, бо системний клієнт DNS не дасть поміняти порт, до якого він буде звертатись — домен чи IP - будь ласка, а порт тільки системний. Я так розумію, що то заради безпеки, хоча хтозна. В інших клієнтах можна вказати порт — наприклад, dig -p 5353, або якщо клієнт на Ruby.
Якщо ж треба саме замінити саме системний DNS, то заміну доведеться розташувати в Докері; тоді можна відкрити стандартний DNS порт (а це 53, до речі). Взагалі я б такі тести тільки в Докері й робив би; створюєш собі docker-compose на всі сервіси та тестуєш в повній ізоляції.
04.04.2023
Замість списку задач краще вже зробити те, що треба
Останнім часом мені здається, що накопичення задач — це спосіб прокрастинації. Прокрастинація тут в тому, що за великою кількістю задач ховаються ті самі страшні справи, які нам в першу чергу треба робити, але ніяк не хочеться. Для таких задач зазвичай і списку не треба, бо вони про себе нагадують самі. Але замість того, щоб зробити та забути, ми будемо займати час будь-чим інше — продуктивним чи не продуктивним.
Тому придумав сьогодні систему оцінювання задач по квадрантах. За однією шкалою — наскільки хотілося б щоб задача була виконана. За іншою — наскільки не хочеться цього робити.
В першу чергу треба робити те, що дуже не хочеться, але буде найприємніше бачити зробленим. За моїми спостереженнями, це є задачі, що й приносять найбільше задоволення, гордість та користь, задля яких ми все це і робимо.
Далі можна робити те, що приємно й зараз й принесе радість потім (але воно зазвичай робиться само собою.) Потім — що приємно зараз, але потім користі не буде (це всілякі розваги). І нарешті — те що і не приємно, і користі не буде, ми не робимо (бо таке насправді рідко приходить на ум).
Тож ідея моя ось така. Записати на аркуші 3 найбільш болючі та важливі задачі. Робити їх; поки не зробиш, фокус має повертатись на них постійно. Поповнювати список за ходом виконання. Повторювати до досягнення душевного комфорту.
03.04.2023
Стрес-тест як дослідження системи
На першу чергу, метою стрес-тесту є обчислення деяких метрик. Насправді на мою думку, обчислення метрик — це тільки початок роботи. Мені більше цікаві пояснення цих метрик, та уявлення про роботу системи, яке можна з них отримати. Для мене головне питання стрес-тесту — у що він упреться?
Що я маю на увазі. Щоб дізнатись, на що здатна система, треба завантажити її на 100%. Але, в розподілених системах (якою є навіть додаток з його базою даних) навантаження ніколи не накладається рівномірно — обовʼязково є вузьке місце. Після отримання результатів стрес-тесту необхідно знайти це місце, а далі найцікавіше — прибрати вузьке місце, та спробувати тест знову. Повторювати до тих пір, поки не буде чітко знайдено місце, яке неможливо “розширити” (та тому причина) - воно і є справжнім обмеженням всієї системи.
Наприклад, протестували API. Перевіряємо — де 100%? Якщо ніде немає — недовантажили мережу. Треба більше запитів. Зробили більше запитів — бачимо, база натужилася. Знайшли N+1 запит — виправили. Нарешті, тепер бачимо 100% CPU додатка. Якщо припустити, що в додатку немає що оптимізувати, то тепер ми маємо справжню картину. Але можна й взяти профайлер, та продовжувати вже на рівні коду — всередині додатка теж буде вузьке місце.
Без цих дій, на мою думку, стрес-тест власної системи — марна витрата часу. Це як розганяти машину на першій передачі — якесь число ми отримаємо, але хіба воно буде корисне? Тільки як показник “як все було погано”.
02.04.2023
Короткий огляд KVM-засобів для ігор
В мене ігровий ПК стоїть у вітальні, під телевізором, бо працює також і медіацентром. Там зручно грати у “консольні” ігри, бо вони розробляються для гри з дивану — мабуть, найголовніше в цьому великий масштаб інтерфейсу, хоча розташування камери (віртуальної) теж важливе. Технічно з дивану можна грати в будь-що, але якщо стрілялки з клавіатурою та мишею ще хоч якось прийнятно, то стратегії зовсім тяжко.
Тому захотів я підʼєднати цей ПК також і до робочого місця. Тобто влаштувати собі [KVM-перемикач] між робочим ноутбуком та ПК. Тоді можна спокійно собі сидіти та грати хоч в Cyberpunk, хоч в який-небудь The Great War: Western Front, яка вийшла два дні тому
Мій новий монітор Sony inzone M9 як раз підтримує KVM, тож перше що я хотів зробити, це банально протягнути HDMI та USB від ПК до монітора. Але дріт цей буде йти з кімнати в кімнату та мати довжину метрів 15-20; при цьому звичайний HDMI (та і USB) вже не підійде через втрату сигналу, тому потрібний так званий “KVM extender”. Такі є на основі кабелю Ethernet, а є оптичного кабелю (з максимальною довжиною — хвилиночку - 40 км!) Проблема — це дорого; від $100 за варіант з 1080p, до $400 та вище за оптику та 4K. До того ж “апаратність” тут досить умовна, бо пристрої подовжувача є по суті компʼютерами. HDMI складний протокол. На моєму досвіді, “апаратне” рішення ніяк не гарантує відсутність проблем, але практично гарантує, що якщо вони виникнуть, то ти їх не розвʼяжеш.
Для будь-якого програмного KVM перше та наголовне — це встановити звʼязок через дріт. Без всякого Wi-Fi. Інакше затримки сигналу гарантовані. На такий рівень, щоб реально хотілось грати через мережу, а не напряму, можна розраховувати тільки з дротовим підключенням. Та й взагалі, в домашній офіс зі постійним робочим місцем Ethernet треба тягнути обовʼязково.
Synergy, а також її нащадки Barrier та Input Leap - хоч називаються KVM, але дають розділити тільки клавіатуру та мишу; не відео. Тож для моїх цілей не підходить - Synergy для випадку, коли у вас поруч два монітори з різними системами, та потрібно ними керувати.
Steam Remote Play - працює непогано, але тільки з іграми Steam. Колись я грав в Elden Ring на відстані у 200 км, та навіть виходило — аж до першого серйозного боса — хоч якість зображення була ганебна. Втім з кімнати в кімнату Remote Play працює добре.
Parsec - тільки його знайшов, але оце KVM що справді мене влаштовує! Якість зображення на висоті (до речі, використовує сучасний кодек H.265, який апаратно кодується та декодується як на ПК, так і на ноуті). Затримок не має. Поводить себе як нормальний додаток macOS. Підтримує будь-які ігри, бо взагалі показує весь віддалений екран. Parsec безплатний для приватного використання. Так що раджу спробувати, дуже приємне рішення.
Одним словом, поки налаштував собі Parsec та він, схоже, вміє все, що я хочу. Не треба купувати коштовні пристрої та свердлити стіни. Успіх!
01.04.2023
Граматики PEG для розбору документів
Взагалі якщо вже потрібно розібрати складні документи, такі як CSS, то варто взяти генератор парсерів з граматики, тобто PEG. Принаймні, я б це так робив.
Чому PEG? Тому що думати про мову в декларативному контексті (граматиці) простіше, ніж в імперативному (коли треба писати свій парсер.) А також код, який вона генерує, зазвичай простіше алгоритмічно, ніж код розбору з регулярними виразами. Граматика PEG описує структуру мови; весь документ складається з деяких частин або виразів, вони розбиваються на менші вирази, і так далі до мовних примітивів — констант, ідентифікаторів, ключових слів.
В мене є досвід розбору власної мови на Go. Там для цього є бібліотека Pigeon. Мені подобається, що парсер на Pigeon не просто розбирає текст документа в синтаксичне дерево: натомість ти задаєш код, який буде викликатись на кожний елемент цього дерева. Так можна не тільки відразу будувати семантичну структуру (таку, що складається з обʼєктів бізнес-логіки), а й в деяких випадках взагалі відразу робити обчислення та робити результат.
В Ruby теж є схожі бібліотеки, наприклад Treetop або Raabro. Вони не дуже відомі, бо власні мови нечасто зустрінеш. Але при цьому їх можна знайти в залежностях гемів, які нам добре знайомі — наприклад, sidekiq-cron використовує Raabro для розбору виразів Cron.
PS: нещодавно оновив Hugo, та він, як виявляється, змінив порядок постів в RSS. Тому стрічка стала містити 30 перших, а не останніх постів, тож фактично перестала оновлюватись. Здається, тепер виправив.

