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

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

Підписатись на RSS · 📢 Канал в Telegram @stendap_sogodni

12.07.2024

Хліб

🌡️ Літо — найкраща пора року, щоб почати пекти хліб. Тісто любить підвищену температуру — те, що взимку потребує часу або підігріву, влітку відбувається непомітно. Особливо коли йдеться про закваску; а на заквасці хліб найзапашніший та найхарактерніший.Наприклад, мій “звичайний” хліб взимку готується з обіду до наступного пізнього ранку, а влітку він готовий вже увечері.

Для мене домашній хліб почався з подорожі в Австрію, де я скуштував дуже простий житній хліб на заквасці. У нас такого практично не купиш; або суміш з пшеницею, або щось солодке. Знайшов рецепт. Сподобалось.

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

Наразі я печу хліб з цілозернової спельти. Рецепт тут. Спельта в нас почалася як “здорова альтернатива пшениці”, але як виявилось, вона просто смачна: духмяніша за пшеницю, легша в роботі ніж жито (яке сходить ну дуже важко.) Поки нічого кращого не треба.

Нарешті, можу порадити книгу Ібана Ярса “Домашній хліб”. Мені сподобалось, що рецепті в ній “відкриті”, а техніки добре проілюстровані. Також автор пояснює, як правильно використовувати дріжджі. Гарний посібник.


11.07.2024

Go-global та важливість правильного повідомлення про помилку

Несподівано з новим застосунком натрапили на таку помилку в go-global:

global: : cannot write param: config key is of unsupported type struct

(Go-global це наша бібліотека для завантаження структур параметрів. Останній раз оновлював її ще рік тому, втім, зазвичай вона свою функцію виконує та проблем не створює.)

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

cannot write param: destination should be a primitive type, not a struct

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

Виявив, що параметрів на цей раз зовсім не було. Це утворювало “порожній” верхній рівень… а далі, через збіг обставин, він розглядався як “листок”, та й призводив до помилки. Тобто що дійсно треба побачити користувачу, це попередження про відсутність параметрів:

no parameters in Parameter Store with prefix "/foo/"

Отакої! А без вірного повідомлення навіть я як автор бібліотеки не міг зрозуміти, де криється справжня помилка.


10.07.2024

Перегляд журналів до CodeDeploy

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

Зокрема, дуже складно шукати причину, чому розгортування не вдалося. (А на стейджингу це відбувається досить часто.) В CodeDeploy немає, як це не дивно, явного звʼязку з конкретними екземплярами сервісу та їхніми логами. А якщо до того згадати, що ECS “забуває” задачі десь через годину після зупинки, то відстежити відповідність розгортування до логів стає кропіткою та терміновою ручною роботою. Та це ми навіть не почали дивитися на саму проблему!

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

Для того довелося: з API витягнути розгортування; потім з нього “специфікацію застосунку”; потім з неї “дефініцію задачі”, а також назви Lambda-функцій, що роблять перевірку на здоровʼя; нарешті по назвах знаходжу конфігурації функцій, та з них та дефініцій задач можна здобути групи журналів, які стосуються розгортування. Фух! Не тільки складно, але й досить спеціалізовано; мабуть, саме через це вони самі логи й не показують.

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

А потім всі результати складаю в шаблон HTML та відкриваю в браузері. В терміналі теж гарно, але я може ще якийсь UI додам зверху.

….Альтернативним шляхом було б формулювання запиту до Cloudwatch Insights. Тоді можна було б зупинитися на групах + діапазоні часу розгортування. Так, може, було б і краще.


09.07.2024

MX записи — адресна книжка електронної пошти

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

Для того в стандартах DNS передбачений особливий тип запису: MX. Він вказує з домену отримувача на домен поштової скриньки. Це практично єдиний сервіс, ушанований такого місця; так, пізніше зʼявилися записи SRV, які можуть вказувати на будь-який сервіс, але відокремлений тип є тільки для пошти.

Коли ми хочемо передивитись вебсайт, то знаходимо його IP адресу. А от якщо надіслати листа — то робимо окремий та особливий крок: шукаємо MX запис, а потім вже так само IP адресу, але вже скрині, на яку вказав MX-запис.

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

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

MX-записи не мають жодного відношення до надсилання пошти. Хоча, у форматі SPF є можливість “благословити” надсилання з MX-записів - але це тільки для зручності. Бо сервер для надсилання міг збігатися зі скринею — але це скоріше випадок маленьких, “гаражних” архітектур, якими вже ніхто майже не користується. Якщо у вас MX - це GMail, то надсилати GMail буде зовсім з інших вузлів.


08.07.2024

Помилка повтореного заголовку з ActionMailer

Сьогодні випустив нову версію бібліотеки mailtrap для Ruby. Це було вмотивовано виявленням цікавого збігу обставин, який псував, хоч і не суттєво, зміст листів, які надсилалися через Ruby on Rails.

Яку проблему помітили: в листах було два заголовки MIME-Version (а точніше, другий Mime-Version, тобто очевидно заголовки приходили з різних місць.) Це не призводить до помилки (головне, щоб такий заголовок був.) Але це один з заголовків, які будуть включені в підпис DKIM; та так складалося, що з подвійним заголовком підпис був не до кінця вірним (деякі сервери звертають на це увагу та знижують репутацію листів.) Тому необхідно було позбавитись того зайвого заголовку.

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

Причину я знайшов: ActionMailer до того, як передати листа на доставлення, викликає в нього метод encoded. А той метод зрештою додає той самий заголовок. Все було б більш-менш добре, якби лист надсилався за SMTP; але оскільки він йшов у наш API, то всі заголовки, які є, передавалися як “особливо замовлені”. А наш API, коли будує листа, теж додає MIME-Version за стандартом. Така вийшла плутанина з відповідальностями.

Цікаво також, що ми не знайшли цей збіг, бо не тестували повний цикл разом з застосунком Rails, а тільки починаючи з готового обʼєкту Mail::Message. Тобто все б нічого, але метод encoded ніхто не викликав. Власне, щоб виправити помилку, я спочатку його додав та зламав тести.

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


07.07.2024

Побудова плану квартири, або фотограмметрія в домашніх умовах

Була в мене задача: побудувати план квартири, до якої немає постійного доступу. Та ще й зі стінами, дверми, вікнами. Знайшов підхід, який може й непрофесійний, але результат дав.

До того думав креслити все вручну на папері; але у Pixelmator вийшло не тільки чіткіше, але ще й швидше. Та цей цифровий план легше буде використовувати повторно. Pixelmator 1 : папір 0.


06.07.2024

Стискання шрифтів для вебу

Закінчую роботу над значками для Obsidian. Як минулого разу казав, шрифт значків всім гарний, от тільки завеликий за розміром. Взявся обрізати шрифт, щоб залишилася тільки та купка значків, яку я використовую.

На то знайшов бібліотеку fontTools - до речі, ще один продукт на Python, який треба встановлювати на пайтонівський намір. Ну, зате, на щастя, brew install fonttools теж працює. Бо всі ці pip та virtualenv то просто жах.

FontTools вміє багато всього, а мені була потрібна команда subset - вона саме й обрізає шрифти під замовлення. Приклад можна побачити на знімку вище. Взагалі все дуже прямолінійно: даєш шрифт, даєш символи чи їх діапазон — та готово.

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

Нарешті, тією ж командою можна перекодувати шрифт у WOFF2. Дописав також скрипт, який відразу загортає його в .scss, щоб не робити цього вручну кожного разу, як додам новий значок.


05.07.2024

Тредізація RSS Twitter

Трохи невдала сьогодні спроба. Хотілося у стрічці RSS для Twitter, яку генерує RSSHub, бачити треди в одному пості — бо як окремі пости, їх досить складно сприймати. Взагалі проблема витікає з того, що з API неможливо витягнути твіт, на який зроблена відповідь — тільки його URL. (Та й взагалі той API вже “не той”, та Twitter вже “не той”, та я б із задоволенням про нього забув, проте багато журналістів та дослідників більше нікуди не публікують.)

Ідея була проста: спід час генерації стрічки RSS виявляти ті твіти, що відповідають на інші твіти з того ж RSS, та “підшивати” один до одного. Тут не потрібні додаткові звернення до API - тільки додаткова обробка. Ніби все просто та прототип я навіть зробив, але на практичній перевірці ідея не запрацювала.

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

Та друга проблема: у вибірку може потрапити не весь тред. Спочатку я думав, що це не так погано — умовно, замість 40 постів в стрічці буде не 1, а 2. Але: при наступному оновленні межі вибірки зсуваються не повністю. Виходить, можна отримати хоч 10 напівдубльованих шматків. Щоб цього уникнути, можна залучити кеш та зберігати попередні пости. Але це вже ускладнення на майбутнє.

До речі, розробляти для RSSHub напрочуд просто; це застосунок Node.js, та запускається він за yarn install && yarn dev. Навіть TypeScript та Prettier в них є. Навіть Codespace підготований! Так що, можливо, власні RSS генератори теж перенесу у RSSHub.


04.07.2024

GitHub Codespaces: на диво гарно!

Сьогодні мав перший досвід роботи у GitHub Codespaces. Це, так би мовити, “хмарне робоче місце”: віртуальна машина з приєднаним редактором, на якій можна вести розробку. Перші враження такі, що це дуже гарне рішення, та якщо вам щось таке потрібне, можна не вагатися.

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

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

Всередині отримуємо більш-менш стандартну віртуальну машину з Debian. Головне, що Docker працює. Також маємо можливість доналаштувати, причому, що мені подобається: як спільне для всіх оточення, так і персональне (за допомогою dotfiles). Оце важливий момент: Codespaces це інструмент для команди, тобто досвідчений інженер може налаштувати середовище, яке потім легко запустить будь-хто з колег.

Це приводить нас до питання: кому таке потрібно? Та, як на мене, саме оказійним розробникам. Наприклад, може у вас є підпроєкт, який не всім та не завжди потрібний; можна налаштувати для нього кодспейс та будь-хто з команди зможе долучитися з дрібними змінами. Або інший випадок: для безпеки та ізоляції. Щоб код проєкту та його залежності не потрапляли на локальні диски розробників, вони можуть працювати з ним в кодспейсі. В мене як раз така потреба й виникла, та дуже радий, що я можу майже непомітно перестрибнути у хмарне середовище.

Що тут можна сказати. Microsoft не дарма володіє GitHub, VSCode, та Azure!


03.07.2024

Як запобігти вигорянню на роботі

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

Що мені допомагає?