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

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

📢 Канал в Telegram @stendap_sogodni

01.10.2022

☁️🏗️🎈 Хотів написати довший пост сьогодні про те, як заощадити гроші на хостингу, але виявилось, що економія доступна тільки в планах з місячною підпискою, тож пост буде коротше.

Річ йде про Fly.io. Це мій улюблений хостинг для проєктів-хоббі. Можна сказати, новітня заміна Heroku (а оскільки Heroku закрив безплатні плани — то саме час знайти їм заміну.) Але в Fly.io розміщають контейнери Docker. В наш час це найкращий спосіб розмістити свій додаток в інтернеті: він балансує добрий контроль над змістом і середовищем додатка, та простий і стандартний зовнішній інтерфейс. Будь то Rails, Golang або чийсь сторонній додаток — загорнути їх в Docker не ставить проблем.

Але вибір хостингу для Docker не такий великий. Є Heroku. Є, звісно, всі хмарні платформи — я дуже люблю AWS Fargate, але для малих проєктів це надто дорого і складно. Ще можна завжди підняти свій хостинг на будь-якому VPS, але тоді втрачається вся простота рішення.

На Fly.io місячна ціна починається з $1.94 (і до того поки що ще є безплатний ресурс.) При тому є всі сучасні зручності — метрики, CLI, власні домени з TLS, купа регіонів та інше. В мене вже пару років тут працює декілька додатків - RSS-читач та RSS-адаптер, система коментування для блогу, база CouchDB. Проблем не маю.

Як щодо згаданої вище економії: нещодавно Fly.io запровадили можливість вимикати додатки, коли в них немає клієнтів. Для малих проєктів це було б ідеально. Але, здається, такий функціонал доступний в платних планах від $29 на місяць.


30.09.2022

✉️✍️📭 Наступна дивина SMTP. Всі знають, що у листа є адреси “кому” та “від кого”. Але насправді у кожного листа є 2 пари адрес. Якщо проводити аналогію з паперовим листом, то одна пара — на конверті, а інша — на самому листі.

Технічно це виглядає так: електронний лист являє собою повідомлення формату RFC 5322, який дуже схожий на формат HTTP. Між іншим, в листі є заголовки, серед яких і From, і To. Тут все достатньо зрозуміло.

Але називати цей формат “форматом SMTP” буде невірно. Бо, як я вже казав, SMTP - діалоговий протокол, і весь лист, з усіма заголовками відправляється командою DATA. Так от що виявляється — перед цією командою сервер SMTP очікує команди MAIL FROM та RCPT TO, в яких також вказується відправник і отримувач! Це і є той самий “конверт” SMTP, визначений у RFC 5321.

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

Який в цьому сенс? Я напевно не знаю, але знаю одну функцію пошти, яка на цьому базується, а саме BCC - “прихована копія”. (Я це несподівано дізнався, коли довелося її реалізовувати.) Коли ти вказуєш заголовок Bcc, то твій поштовий клієнт відправить лист без цього заголовку, але додасть отримувача в перелік RCPT TO. Так всі адресати побачать той самий лист, але не побачать, хто отримав приховану копію.

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


29.09.2022

⏰📝💸 Багато хто не любить тайм-трекінг і бачить в ньому тільки інструмент бюрократії та терору. Я теж не люблю їм займатись, але це як чистка зубів — на тайм-трекінг є користь.

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

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


28.09.2022

✉️📭💬 Продовжуючи серію про дивний протокол SMTP. Який ми всі використовуємо щодня, але ніхто не знає, як він працює.

Як вам така дивина: на відміну від HTTP, SMTP - протокол діалоговий. Тобто для того, щоб відправити одного листа, потрібно обмінятися з отримувачем не однією, а декількома командами. Спочатку HELO, потім MAIL FROM, потім RCPT TO, і нарешті DATA - зміст листа. Перед тим, як слати наступну команду, треба дочекатись відповіді до попередньої. Проблема в тому, що затримка підключення накладається на кожну з команд, тож з повільним звʼязком або на далекий сервер SMTP йде набагато довше, ніж HTTP. Це, до речі, одна з головних причин того, що сьогоденні поштові сервіси як то Mailtrap або SendGrid пропонують відправляти по HTTP API, а не по SMTP.

А ще через цю діалоговість SMTP має дуже дивну форму шифрування. (Бо, звісно, всі листи, як і вебсайти, варто відправляти тільки через зашифрований канал.) Так от, хоч і існує SMTP-аналог до HTTPS, тобто, коли спочатку встановлюється канал TLS, а потім вже через нього SMTP, але такий спосіб непопулярний. Натомість у протоколі SMTP є команда STARTTLS, після якої сервер має припинити комунікацію по відкритому каналу, та почати сеанс TLS на тому самому підключенні. І так роблять практично всі клієнти SMTP. Через STARTTLS всім серверам SMTP доводиться керувати власними TLS-сертифікатами, і не можна цю роботу делегувати балансиру, як це зазвичай трапляється з HTTP.


27.09.2022

🔐✉️✍️ Сьогодні розкажу про DKIM - один з механізмів безпеки поштового протоколу SMTP.

SMTP - унікально лібертаріанська система. Як і в реальному світі, до вашої поштової скрині може покласти будь-хто та будь-що. Хто завгодно в інтернеті може надіслати листа з будь-яким змістом. Немає ніяких механізмів авторизації. Це, мабуть, підходило для інтернету в 80-х, але в наші часи це й дозволяє існування спаму. З усім тим, SMTP, як найвитриваліша і найпоширеніша система комунікації, продовжує існувати та нема основ вважати, що колись перестане.

Так от, за відсутністю авторизації, SMTP працює за принципом довіри. Кожен лист оцінюється на автентичність. Вплинути може і зміст листа, і сервер відправника, і багато різних факторів, які цілком не оголошуються. (Бо попри всю відкритість, більшість скринь в інтернеті належать до GMail, а за ним — до декількох провайдерів менше. Кожен має свій ноу-хау для визначення спаму.)

DKIM - це один з погоджених механізмів, що покращить автентичність вашого листа. Якщо дуже просто, то це електронний підпис. Лист підписується деяким доменом. Такий підпис можна зробити тільки з дозволу власника домену. В першу чергу накладається підпис домену відправника (як вказаний в адресі), але також може бути домен сервера, що виконує виправляння. А взагалі технічно лист можна підписати будь-яким доменом, тільки навряд чи це вплине на автентичність.

DKIM працює за звичним принципом криптографічної пари. Приватний ключ знає тільки відправник і використовує для підпису змісту листа. Публічний ключ оголошують в особливому DNS-запису. Тоді будь-який отримувач може дістати публічний ключ та перевірити підпис.

Що це дає? Після перевірки DKIM, отримувач знає, що відправник — власник свого домену, або довірена особа. Це досить сильний сигнал автентичності. Звісно, спамери можуть (і роблять) повністю коректні DKIM підписи для своїх підозрілих доменів — але про це іншим разом.

Щоб подивитись підпис DKIM листа в вашій поштовій скрині, дивіться на заголовки DKIM-Signature, а також Authentication-Results (його додає ваш поштовий сервіс.)


26.09.2022

❄️📦🪣 Сьогодні вдало попрацював з AWS Redshift.

Redshift - це аналітична (OLAP) база даних, що виросла з PostgreSQL, виглядає як PostgreSQL, але працює фундаментально по-іншому. Вона призначена для обробки великого обсягу даних, про що свідчить і цінник, що починається з $0.25 на годину.

Але просто завантажити дані у Redshift та отримати швидкий результат не вийде. (Перевірено.) Треба знати деякі ключові моменти.


25.09.2022

💳💸💎 Сьогодні несподівано випустив оновлення гему Liqpay для Ruby on Rails.

Цей гем я зробив одинадцять років тому, щоб уможливити оплату на одному проєкті. Тоді екосистема онлайн-платежів була зовсім іншою аніж зараз. Втім, LiqPAY все ще живий та здоровий, та використовується багатьма українськими сервісами. Тож гем все ще може комусь згодиться. Він додає до Ruby on Rails хелпер кнопки оплати, що перекине покупця на LiqPAY, а потім відправить результат на адресу вашого сервера. Таким чином, за кілька годин ви вже будете приймати оплати з українських користувачів.

В LiqPAY за ці роки небагато змінилось. Що головне, то вони переїхали на новий хост, а старий повністю відключений. (Зворотна сумісність 0 з 10.) Актуалізація адреси API й була головною метою оновлення. Крім того, освіжив код:

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

До речі, з ПриватБанком я ніяк не повʼязаний і вони мені нічого за це не платять. (Тому, може, я й не оновлюю бібліотеку аж 4 роки після того, як перестав працювати старий URL.)


24.09.2022

🌐📖🔄 В мене на блозі триває SEO-покаліпсіс: майже всі сторінки випали з індексів, та відвідувачі з пошуковиків практично скінчились. Зробив деякі зміни, щоб виправити, але на жаль пройдуть дні, поки я зможу побачити якийсь результат.

Поки все це відбувається, переглянув зображення деякої метаінформації, між іншим, також і про мову.

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

(До речі, Hugo буде додавати до всіх адрес локалізованих сторінок префікс з кодом мови. Цього неможливо уникнути глобально, але для конкретної сторінки завжди можна задати повний url у front matter - тоді префікс не додається.)

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

Тому натомість просто додав свій, особливий параметр сторінки lang (насправді він давно вже був), і використовую його для локалізації окремих сторінок (наприклад, у тезі <html lang="uk">). Ще бачив поради зробити мову тегом або категорією. В будь-якому разі, тоді Hugo продовжує працювати у звичайному режимі без локалізації.

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


23.09.2022

🌎🔐💸 Продовжуючи тему проблемних вебтехнологій: TLS. Або ж SSL (чи знаєте ви, що TLS - це нова версія SSL, а SSL абсолютно застарілий та ненадійний та давно його ніхто не підтримує?)

Зараз такий час що всі користуються TLS, а все завдяки поширенню чудової ініціативи Let’s Encrypt. Тепер будь-хто може безплатно отримати сертифікат для сайту. Тепер і більшість хостингів безплатно створять його за вас, включаючи й AWS. Це дуже добре, що всі мають доступ до безпечного інтернету.

Де ж проблеми? Проблеми в тому, що не всюди ці сертифікати приймають. Якщо сертифікат вам потрібен для сайту на HTTPS - то, напевно, обійдетесь Let’s Encrypt. (Чи знаєте ви, що HTTPS - це звичайний HTTP, але комунікація відбувається через канал TLS?) Браузери з ними нормально працюють — і браузерів насправді не так багато.

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

Тому, якщо у вашого проєкту є бюджет хоч на $20 на рік, раджу придбати “справжній” сертифікат і не мати проблем. Справжній — то від серйозного емітента, наприклад, Comodo. Рекомендую купувати на NameCheap, хоч вони мені не платять. До того ж оновляти такий сертифікат доведеться раз на рік, а не на місяць.


22.09.2022

🕸️📖👈 Що я вам скажу — не раджу підіймати свій DNS.

Принаймні, не рекурсивний. Річ у тім, що DNS - вкрай езотерична технологія. І хоч ми всі їй користуємося постійно, мабуть, мало хто здогадується, що таке рекурсивний DNS, і який ще буває.

Так от, DNS це насправді дві роздільні системи.

Перша — це, грубо кажучи, дерево DNS-серверів, які зберігають адреси сайтів. А саме, є кореневі сервера, що знають адреси DNS-серверів доменів верхнього рівня (.org). Далі у домену .org є свої сервери, які знають адреси DNS-серверів всіх доменів .org - наприклад, .telegram.org. Зазвичай DNS-сервер домену другого рівня скаже вам адресу самого сайту та його піддоменів. Але не завжди — бо глибина дерева технічно не обмежена. (До речі, самі DNS-сервера вказуються у вигляді доменів, а не IP-адрес. Мені це здається зациклюванням, але ж якось воно працює. Таємниця!)

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

Через повільність і ненадійність такої системи DNS існує друга. Це кешуючі DNS сервера, які зберігають результати запитів та віддають їх моментально. Часто вони теж не роблять рекурсивний пошук, а питають в інших. Так робить DNS-сервер на вашому пристрої (бо звісно, є й такий!), на роутері, у провайдера.

А є ще публічні кешуючі DNS сервери, наприклад, 1.1.1.1 від Cloudflare. Їх користь в тому, що вони працюють “нормально”. Бо протокол DNS складний і неоднозначний, і в деяких історичних ситуаціях “нормальні” сервери роблять не так, як написано. (Принаймні, це я так розумію.)

Ми спробували підіймати рекурсивний DNS сервер Unbound. Він дуже класний, але він жорстко слідкує за стандартом, а це “ненормально”, тобто інколи результати не збігаються з очікуваннями, і пояснити, чому, нелегко. Після численних проблем повернулись до DNS від Cloudflare.

Якщо хочеться почитати про DNS більше, раджу чудовий блог Джулії Еванс.


21.09.2022

🔎🧰🔥 Сьогодні боровся з пошуковою оптимізацією.

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

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

Отже, раджу зареєструватись у Google Webmaster Tools, а також в Bing Webmaster Tools, і подивитись, що вони кажуть. Лайфхак: підтверджені сайти з Google можна в один клац імпортувати до Bing. Тобто не треба два рази підтверджувати власність.

І не зволікайте на те, що Bing не такий крутий, як Google. Бо саме в індекс Bing дивиться DuckDuckGo, а ось DDG досить популярна альтернатива Google. Та й сам Bing у багатьох користувачів Windows стоїть за замовчуванням.

Що я сьогодні встиг зробити, це додати до всіх сторінок meta description. Бо Bing їх дуже хоче. А також виправити внутрішні посилання, що вели на сторінки без кінцевого слешу. Бо як виявляється, Google не може з цим змиритися, навіть якщо посилання насправді працюють через перенаправлення. А ще додати до сторінок тег link rel=canonical, що допомагає пошукачам зрозуміти, яку саме сторінку показувати — це теж корисно у ситуації з перенаправленнями.

До речі, для вебаналітики я вже більше як рік користуюсь Plausible. Це платний сервіс, який свідомо не будує ніякого “портрету користувача”, а спирається тільки на анонімну статистику.


20.09.2022

📁🧹🗑️ Як впоратись з програмами, які невпинно створюють на диску всякий брухт? Як приклад: XCode накопичує архіви з кожної збірки, а також файли підтримки для кожної нової версії iOS.

Для автоматичного управління файлами для macOS існує додаток Hazel. Він вміє не тільки видаляти файли, але й впорядковувати за різними схемами. Ідея така: Hazel слідкує за директоріями. Задаєш шлях до директорій та правила вибору та обробки файлів; якщо є такий файл — то зробити таку дію. Наприклад, можна слідкувати за директорією з архівами XCode та видаляти все, що старіше за місяць.

Ще зручно за допомогою Hazel виправляти незручності в автоматичному розміщенні файлів. Наприклад, я не люблю, коли програми зберігають файли на робочий стіл. Тож можна зробити так, щоб Hazel переносив всі файли з робочого столу в документи.

Що Hazel погано вміє робити, це слідкувати за глибоким деревом директорій. Технічно така можливість є — через правило recurse into directories - але воно дуже неефективне.

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

А ще щоб знайти, куди ділось місце, багато років використовую DaisyDisk. Можу і для Windows порадити - TreeSize.


19.09.2022

😸🔐⚙️ Пара порад про налаштування GitHub Actions.

По-перше, у Terraform є провайдер для GitHub. Якщо у вас багато репозиторіїв, то це допоможе налаштувати їх за одною системою, а також зручно керувати доступом. Особливо це важливо для складних в настройці правилах, таких, як захист гілок.

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

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

До речі, середовище вмикається через аргумент у workflow, тож є різні підходи до його визначення. Ну, наприклад, можна вирішити, що деплой в продакшн йде з гілки master. Тоді захищаємо master правилами, щоб не можна було писати туди напряму, а потім вказуємо в середовищі production, що воно доступне тільки з цієї гілки.

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


18.09.2022

🗳️👍👎 Сьогодні пару слів про демократію в нашій команді.

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

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

Інший — спиратися на дані. Збираємо всі “за” і “проти”, зважуємо, підраховуємо, і маємо науковий результат. Нібито так все буде чесно. Але ж ні. Якби було очевидне обґрунтування, питання не стало б політичним в першу чергу. А так, збір аргументів перетворюється на конфлікт волі — більше збере той, хто більше прагне перемоги. І це, на мою думку, псує весь “логічно обґрунтований” підхід.

Ми ж прийшли до демократії (що цікаво, не хтось так вирішив, а через командний досвід побачили, що вона працює.) Якщо стає питання, яке не можна вирішити вузьким колом — бо ніхто не хоче поступатись — то таке питання виноситься на обговорення всією командою. Спочатку кожен може висловити свої аргументи та подискутувати. Потім команда голосує. І за кількістю голосів обираємо рішення.

Чому це круто:


17.09.2022

🗞️🔄📢 Нарешті добив сьогодні одночасну публікацію в блог і в Телеграм.

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

Складнощі створило те, що у Telegram Bot API немає способу завантажити історію постів. Отакої. Є ще клієнтський API, який, напевно, зможе це зробити (бо клієнти історію показують.) Проте, щоб не звʼязуватись з ще одним API, знайшов спосіб експортувати історію вручну. Така можливість існує в так званому Telegram Desktop (не плутати з Telegram for Mac, яким я зазвичай користуюсь.) Експорт можна зробити у JSON формат (додатково прикладаються світлини та відео.) Потім цей JSON експорт перетворюю на пости для Hugo. Цікаво, що форматований текст, замість Markdown чи HTML, експортується у вигляді структури AST, з якої досить просто збудувати HTML (чому не Markdown? тому, що у HTML простіше екранувати спеціальні символи.)

Далі, коли всі пости вже готові, залишилось налаштувати шаблони на сайті — в Hugo таке називається content section.

Поки шаблони дуже прості, буду ще розвивати. Але розділ на сайті вже працює: https://leonid.shevtsov.me/stendap/.


16.09.2022

🏞️🌄🌆 Що ж, розібрався сьогодні з публікуванням світлин до Телеграму.

З боку бота все досить просто: замість sendMessage є метод sendPhoto. До нього можна навіть додати опис, в тому числі форматований. Але замість 4096 символів посту, опис може мати не більше 1024. До того ж пости зі світлинами мають вузький вигляд. Тому я вже раніше вирішив світлини відправляти окремо.

Але що з боку блогу? В блозі світлина до посту має бути разом з постом, звісно. Спочатку я розглядав ідею додавати фото розміткою в тексті поста, і витягувати при розборі. Але це складно. Тоді згадав по таку функцію Hugo, як ресурси сторінки: це відносно новий спосіб єднати пости та їхні ілюстрації в одній директорії. Після цього можна у метаданих (frontmatter) до посту доповнити ілюстрацію описом.

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

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


15.09.2022

🚧🤖📢 Просуваюсь потрохи з телеграм-ботом. Переробив відправлення в формат HTML, тому що Markdown все ж таки вельми плющений. Щоб публікувати нормальний Markdown в Telegram, треба спочатку розібрати та зібрати наново з екрануванням всіх спеціальних символів.

З HTML набагато простіше — екранування потрібне тільки таке як завжди. Тут нюанс інший — в тексті мають бути тільки теги, що Telegram підтримує — це ті, що уможливлюють засоби форматування. Навіть тег <p> ставити не можна.

Я міг би писати пости прямо в HTML, але, по-перше, яка в тому радість, а по-друге, не вийде той самий пост покласти в блог — хоча б через відсутність параграфів. Тому знайшов спосіб зі звичайного Markdown робити такий HTML, щоб Телеграму подобалось.

Для цього узяв Markdown-парсер Goldmark, який використовується в Hugo. Та написав для нього особливий рендерер. Він не тільки параграфів не робить, а й конвертує списки назад у дефіси, і зберігає вірні перенесення строк.

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


14.09.2022

🧙☕🏕️ Сьогодні якось згадалась між словом мова Clojure, яку я обожнюю, хоч не використовую.

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

А проте, досвід, набутий з Clojure, залишився зі мною на довгі роки. Тому, на мою думку, цю мову корисно випробувати кожному інженеру.

Якщо хочеться глянути на 50 рядків красивого коду на Clojure, пропоную мою імплементацію OAuth.


13.09.2022

🎂👮🍱 Сьогодні день програміста. Вітаю з 0х100!

Поскаржуся трохи на REST, як систему організації HTTP API.

Спочатку про хороше: більшість того, що ми робимо через API - це саме створення, перегляд, редагування та видалення ресурсів. Ці дії чудово вписуються в ментальну модель REST, і дуже добре, що є конвенція, яку всі знають і не треба кожного разу щось складати своє.

Тепер про погане: як і будь-яка система, модель REST не описує всі операції. Наприклад:

Оскільки у Ruby on Rails дуже зручно створювати API для ресурсів, то є тенденція натягувати на REST абсолютно все, до фанатизму. Так виходять ресурси на кшталт bulk_imports або, ще гірше, publishs - тобто з дієслова штучно робиться іменник. А ще HTTP-методи окрім GET та POST не повністю підтримуються браузерами — спробуйте зробити DELETE через форму.

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

REST - для явних ресурсів. Для всього іншого - POST по шляху з назвою дії.


12.09.2022

🤖✨🔖 Позавчора я розповідав, який зручний список читання у Reeder. А вчора навідкривав десь 40 вкладок (передивлявся архів Hacker News), після чого зрозумів — чого Reeder не вміє, це додати у список відразу всі вкладки. Що ж робити?

Сьогодні скористався вбудованими засобами автоматизації, щоб це виправити. Спочатку хотів написати AppleScript. Це давня та езотерична мова, яка надає доступ до даних запущених застосунків. З допомогою AppleScript можна отримати перелік всіх вкладок з Safari - після того, як трохи пограєшся з “наближеним до людської мови” синтаксисом.

Але є проблема. AppleScript працює тільки з тими застосунками, що його підтримують — оголошують власний API. На жаль, Reeder так не робить. Проте виявилось, що він підтримує Shortcuts - більш сучасну систему автоматизації. Shortcuts прийшов з iOS і дозволяє збирати скрипти з графічних блоків.

Shortcuts не працює з вкладками Safari. Зате, в шорткат можна вбудувати шматочок AppleScript (або JavaScript, або шелл-скрипта.) Оскільки скрипт я вже написав, залишилось додати до його результатів цикл та операцію додавання до Reeder. Тут теж не без хитрощів — треба, щоб між кроками збігались типи даних — але в цілому Shortcuts простіше у використанні, ніж AppleScript.

Готовий шорткат можна зашарити, а ви можете подивитись за посиланням. Дивна система поширення шорткатів — каталогу немає, просто ти отримуєш посилання і все.


11.09.2022

🤖🤝😁 Сьогодні метапост: я запостив цей пост за допомогою бота, який теж написав сьогодні. До цього пости публікував вручну через додаток Telegram.

Навіщо це потрібно? Є декілька важливих переваг:

Телеграм-бота створити досить нескладно — для Go є бібліотека, а реєстрація проходить через телеграм-бот @BotFather та займає хвилину.

До того ж для публікації постів потрібен не бот, а просто скрипт. Ідея скрипту проста: для телеграм-каналу створив окремий тип постів (а блог в мене на Hugo); також тримаю файл з відповідністю постів до ідентифікаторів у Telegram. Перед публікацією в Hugo запускаю скрипт, який запостить або оновить пост в Телеграмі, дивлячись на файл відповідностей.

Все б було ідеально, якби Телеграм не вимагав суворого екранування символів для Markdown (наприклад, треба екранувати дефіси та крапки.) Спробую для наступного поста HTML.


10.09.2022

👓☕📰 Окрім RSS-читача та RSS-генератора, незамінною частиною мого читального арсеналу є сервіс "список для читання".

Якщо не чули, то такий сервіс попросту зберігає перелік статей, яки відразу прочитати не виходить. Дивлячись на те, скільки я бачив браузерів з десятками вкладок, то, мабуть, не всі чули про такі сервіси. Шкода, бо вони зручніше і місткіше як вкладок, так і закладок.

Найбільш відомий список для читання — на мою думку, Pocket, тож пропоную роздивитись його. Що не рекомендую, це вбудований список для читання з Safari. А я натомість користуюсь списком, вбудованим в обраний мною RSS-читач Reeder. Що я в ньому полюбляю:

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

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

Отже, десь так я і споживаю новини:

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


09.09.2022

🔥🧑‍🚒🔥 Сьогодні простій того самого сервісу AWS SSM Parameter Store, який я так хвалив нещодавно, спричинив 3 години простою нашого. Як так сталось?

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

Але був нюанс. Той самий SSM використався також у хелс-чеку. Та коли SSM зламався, то хелс-чек почав видавати помилку. Це спричинило нездоровий стан додатка та його перезапуск. А коли додаток перезапустився, то й він підхопив ту ж саму болячку... і вже не піднявся аж допоки SSM не повернувся до життя.

Стислі висновки:

- Хелс-чек краще робити найпростішим та з мінімальними залежностями. (Але так виходить не завжди.)
- Хелс-чек має видавати позитивний результат, якщо є побічна проблема з його виконанням — наприклад, з залежностями. Негативний результат видавати, тільки якщо сам хелс-чек працює добре, а додаток — ні.
- Конкретно по SSM: будемо зберігати останню успішну конфігурацію в локальне сховище, і використати в разі наступного відключення. Не думаю, що це дуже потрібно — головне виправити хелс-чек — але й зробити досить просто.


08.09.2022

🌡️🎛️⚠️ Продовжив сьогодні налаштовувати оповіщення Cloudwatch. Облаштував сервіси ECS (тобто, аплікації.)

Два оповіщення тривіальні — на високий рівень утилізації процесора та памʼяті. Ці дві метрики повідомляє сам ECS.

- Памʼять — на 80%. Сервіси на Ruby дуже полюбляють памʼять, але 20% треба тримати в резерві.
- Процесор — на 50%. Якщо у вебсервісу постійне навантаження до 50%, скоріш за все щось відбувається не так. Зазвичай більшість часу вебсервіси чекають або на базу, або на клієнта, тобто процесор простоює.

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

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

Друга підступніша — це вихід за нестачею памʼяті. Можна жити та не помічати, як вони трапляються. (Я знаю, бо так і було.)

Отже, хитрим поєднанням AWS EventBridge, Cloudwatch Logs, Log Metric Filter, та потім власне Metric Alarm, можна зробити так, щоб події зупинки задач ECS потрапляли до журналу, фільтрувалися за причиною (бо є ще очікувані зупинки) та підраховувались метрикою.

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


07.09.2022

🔥🧑‍🚒🚨 Сьогодні в нас день хотфіксів, може п'ять разів випускали. (То добре, що процес деплою на це готовий.)

Пара постмортем висновків.

- Не нехтувати тікетами для інфраструктурних або внутрішніх змін в проєкті. Тікети існують не для бюрократії та не тільки для передачі задач від менеджера до інженера. Сенс існування тікетів — це комунікація. В цьому випадку — комунікувати треба до QA команди, що відбулися зміни, які потребують перевірки (або принаймні уваги.)

- Автоматичні тривоги — це критична частина інфраструктури. А саме: в ситуації, коли у вас ламається сервіс, а ви це помічаєте вручну через години (або хвилини), або вам повідомляють користувачі, треба попіклуватись і додати тривогу, щоб наступного разу про поламку було відомо одразу. Ось, сьогодні додав тривогу на довжину черги повторів у Sidekiq. Ще шукаю можливість зробити тривогу на високу кількість перезапусків задач в ECS.


06.09.2022

🔍🗺️🕸️ Сьогодні пораджу як зручно керувати DNS записами. А саме, варто записати їх у Terraform. Terraform - не тільки для того, щоб керувати інфраструктурою AWS; він також дозволяє описати практично будь-які налаштування, за наявності відповідного провайдера. (Провайдер — це плагін, що дозволяє Terraform робити зміни в деякому сервісі.)

Зазвичай реєстратори DNS (Godaddy, Namecheap, та інше) мають вкрай незручний інтерфейс. Особливо якщо у вас декілька доменів, то керувати всіма записами вручну це страждання. Добре що зазвичай ці записи налаштовують один раз та далі вільні про них забути; погано, що такий важливий аспект продукту так важко роздивитись.

Так от, замість того, пропоную перенести конфігурацію DNS-записів в Terraform. Існують провайдери для всіх визначних реєстраторів. Якщо ж для вашого немає, можна переїхати, наприклад, на Cloudflare - вони надають DNS хостинг безоплатно.

Terraform замінить складні та незграбні веб-інтерфейси простими конфігураційними файлами. А якщо ви робите багато однотипних записів, то повторення навіть видасться "підсушити".


05.09.2022

🧹🕸️🐒 Сьогодні раптово згадав та освіжив один зі своїх стародавніх проєктів - MonkeySort. Тобто точніше, згадав один з користувачів (виявляється, такі є!) А проєкт за десять років перестав працювати через більш суворі вимоги браузерів до CDN. Треба було змінити посилання на HTTPS, але замість того я всі залежності додав до самого проєкту. До речі, великий плюс до стабільності Google та Cloudflare CDN, що вони все ще працюють. На таке можна покластися.

Що, власне, за проєкт? Про це є стаття, а якщо у двох реченнях, то це експеримент по сортуванню предметів, у якому порядок визначає людина, що порівнює їх попарно. Наприклад, так можна відсортувати задачі за складністю, або улюблені страви. Головна ідея в тому, що багато речей складно порівняти, а дві речі — легко.

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

Відразу зрозуміти, що відкинути — дуже складно і боязно. Тому замість того я оцінюю кожну річ за шкалою на п'ять "балів":

- Річ на 1 бал відразу викидається.
- Речі з 2 балами теж викидаються без розбору, але не миттєво, а після закінчення оцінок (так вже легше це прийняти).
- Якщо після цього все ще залишається багато речей, то речі на 3 бали знов сортуються таким же ж чином, але вже проміж собою.
- Речі на 4 бали — це те, що майже напевно хочеться залишити, їх і не чіпаємо.
- І, нарешті, 5 балів — це стовідсотково цінна річ.

Звісно, оцінювати треба швидко, покладаючись на інтуїцію.


04.09.2022

🤖🏗️🗞️ Минулої неділі я згадав, що збираю та читаю контент здебільшого через систему RSS. Сьогодні розкажу, що я роблю, коли джерело RSS не підтримує.

Річ у тім, що нічого магічного в RSS немає. Навпаки, це дуже простий формат (тому й не прижився). RSS - це просто файл ("стрічка") з переліком записів, де у кожної є унікальний URL, а також текст, заголовок, та деякі метадані. Все, що роблять програми для читання RSS - це періодично завантажують RSS-стрічки, та зберігають всі наявні записи. Потім, завдяки унікальності, вдається відстежувати статус прочитання кожного запису.

Головна перевага формату RSS, порівняно з HTML-сайтами, до яких всі звикли — це те, що стрічка чітко поділена на унікально визначені записи. Головна вада RSS - він не надає власникам контенту ніяких можливостей аналітики та мінімальні можливості оздоблення. Отже, цілком зрозуміло, що багато сайтів RSS не підтримують (Twitter), або підтримують з мінімальним функціоналом (Reddit.)

Але, якщо ти вмієш програмувати, то збудувати RSS для майже будь-якого сайту зовсім нескладно. Достатньо написати скрипт, що завантажує HTML-джерело, розбирає його та генерує RSS-записи для наявних на першій сторінці статей (І десь його захостити.) З нормальним RSS-читачем цього вже достатньо — він сам буде викликати ваш скрипт та накопичувати статті.

Нерідко навіть програмувати не треба, бо є багато готових рішень — як у хмарі, так і self-hosted. Self-hosted має ту перевагу, що легше обходить блокування (наприклад, з Instagram це критично.) В мене налаштований генератор стрічок RSSHub. Ще є декілька самописних скриптів на Ruby.


03.09.2022

🇺🇦🌐🇺🇸 Сьогодні покращував свої знаряддя для написання текстів

Перше: зручна обиралка емодзі. Шукав рішення, що не буде слухати введення з клавіатури (як це робить добра утиліта Rocket.) Знайшов скрипт alfred-emoji для Альфреда. Так вдалося уникнути додавання ще одної сервісної програми. До речі, на скрипти Альфреда можна призначати гарячі клавіші, що мега зручно. Тепер в мене Hyper+: викликає меню сніпетів, а Hyper+' (сусідня) викликає емодзі.

Друге: добра перевірялка українського правопису. Для англійської мови є Grammarly (яку зробили українці, до речі.) А що для української? Знайшов цікавий проєкт LanguageTool - це практично Grammarly, але з відкритим кодом, і з підтримкою аж 16 мов. LanguageTool можна запускати локально, але в них також є платна хмарна версія що дає більш просунуті стилістичні поради для англійської. Ще саме зараз у них 50% знижка для України.

Третє: перекладач, переважно такий що працює офлайн. Я користуюсь перекладачем, щоб перевірити свої знання або розуміння деяких слів. Набрів на сервіс Lingvanex. Він перекладає більш ніж 100 мов за допомогою машинного навчання. За моїм тестуванням, працює не гірше Google Translate, але платна версія вміє офлайн. Тут поки не знаю — схоже що перекладає він добре, але маркетинг досить брудний. Почекаю наступного великого розпродажу. 🤑


02.09.2022

🪓📺🌈 Сьогодні трошки точив сокиру. А саме: вийшла нова версія Visual Studio Code. У ній з’явилася офіційна інтеграція с термінальною оболонкою Fish. (Цією оболонкою я вже багато років користуюсь, а терміналом виключно через VSCode - може з рік.)

Інтеграція, наприклад, відмічає в терміналі початок та результат кожної команди та дозволяє легко скопіювати її вихід. Все б добре, але чомусь вона зламала підказку (prompt) - а саме, після підказки підставляє перенос рядка.

~/w/proj master ❱
echo “пише тут"

Поки розбирався, що з цим робити, та випробував різні популярні підказки, зрозумів щось інше:

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

Але підказка за замовчуванням зовсім довга та незручна:

user@Laptop.local /Users/user/work/proj > echo “пише тут"

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

🏠 ❯ echo "у корені робочого простору"
🏠 /src ❯ echo "якщо перейти в під-папку"
🌍 ~/Downloads ❯ echo "якщо вийти за межі простору"

Дрібниці, але цю підказку бачиш сто разів на день.

(До речі, проблема з переносом була через наявний, але порожній файл fish_right_prompt.fish. Але моя підказка працює і так.)


01.09.2022

📺🧙🧠 Сьогодні подивися відео про технології "зомбування" людей, тобто введення в оману. Головна думка: більшість людей схильні до прийняття правильно нав'язаної їм точки зору, аж до відкидання здорового глузду. Про це свідчить відомий і багато повторюваний експеримент Аша. Цим користується пропаганда на телебаченні та інше. На всяку людину можна знайти прийом, але краще всіх супротивляються ті, хто толерантні до своїх або чужих помилок.

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

Все гірше. Ми невпинно вбираємо з оточення думки, погляди, сигнали, і вони несвідомо впливають на наше мислення та систему переконань.

Свідомість - як ліхтарик, а наше мислення - як пляж вночі. Ми ходимо по пляжу з ліхтариком і будуємо замки з піску. Тим часом, океан нашого оточення нескінченно змінює нас, і ми не можемо бачити, де і як саме.

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

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

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

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

Про розходження точки зору раджу подивитись стрічку "Рашьомон" Акіри Куросави.


31.08.2022

📃🔍🐞 Сьогодні довелося шукати причину перенавантаження бази по логах в AWS Cloudwatch (це амазонівський сервіс логування та спостереження).

- З'ясували, що база почала перенавантажуватись раптово, з деякого часу. (Це просто по метриках.)
- Визначаємо - чи це база досягнула технічної межі, або чи маємо аномальне навантаження. Пишемо простий запит в Log Insights, та по гістограмі бачимо, що кількість запитів дійсно зросла стрибком. (Це можна теж подивитись по метриках.)
- Ставимо гіпотезу - додаткові запити походять з конкретного акаунту користувача (це найпростіше пояснення.) Як визначити, з якого?
- В Cloudwatch можна тегувати записи, просто передаючи в тілі записа JSON об'єкт. Але на жаль, ми ще тегували акаунтом. (Тепер будемо)
- Якщо тегів немає, Cloudwatch також вміє парсити записи регулярками, на льоту, командою parse. Це спрацювало.
- Потім за допомогою статистичного запиту stats() та сортування знаходимо акаунт з найбільшою кількістю запитів.
- Акаунт знайшли, далі вже інша історія.

PS
- Треба знати, що в Cloudwatch потік - належить конкретному процесу, а група - збирає потоки однакової форми. Наприклад, по групі на сервіс. Групувати потоки різної форми - це ускладнювати собі життя.
- До речі, навіть API Cloudwatch так побудований, що в потік можна писати тільки знаючи токен з попереднього запису, тобто виключно послідовно.


30.08.2022

🛠️📦☁️ Сьогодні повідаю про мало відомий, але дуже корисний сервіс AWS Parameter Store. Якщо ви мешкаєте у AWS-і, то це найзручніший спосіб зберігати налаштування та секрети до вашого коду. Ось кілька фактів про нього:

- У технічному сенсі Parameter Store це key-value база даних, у якій дані - це рядки, а ключі організовані у ієрархію на кшталт файлової системи (або кращий приклад - S3).
- Для рядків до 4 КБ він абсолютно безкоштовний. Рядки від 4 КБ до 8 КБ трошки коштують (у нас з таких тільки TLS-сертифікати.) 8 КБ - це максімум.
- Керування доступом здійснюється засобами IAM та спирається на ієрархію. Тобто, можна надати доступ до якогось під-дерева. Саме так ми й робимо - у кожного сервісу свій префікс до свого дерева конфігурації.
- Окрім обмеження доступу, дані також можна шифрувати ключами KMS, що ми робимо для всіляких секретів.
- Само собою, параметри можна створювати за допомогою Terraform, як ми й робимо для параметрів, що походять з інфраструктури та "склеюють" сервіси, наприклад, їхніх адрес.
- Звісно, параметри можна отримати через API, але ще AWS ECS може передавати їх у змінні оточення (зручно це чи ні - залежить від обставин проєкту.).
- AWS веде облік версій параметрів, з датою та автором зміни. Інколи це дуже корисно.

Ми Parameter Strore широко використовуємо, тому наші rubygem та go package вміють завантажувати параметри у вкладену структуру JSON. Тож і вам раджу.


29.08.2022

📽🎑📈 Сьогодні у нас що-двотижневий демо-мітінг. На мою думку, як не найважливіший регулярний мітинг. Ідея дуже проста - кожний член команди по черзі показує що-небудь новеньке. Це може бути і фіча з продакшену, і щось свіже, запущене локально. Не обов'язково це має бути "візуальна" фіча - дехто показує внутрішні частини або просто відрізки коду. Цікаві метрики. Звісно, нові дизайни та дослідження теж потрапляють до демо.

Чому важливо мати такі демо:

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


28.08.2022

🗞📥⏰ Сьогодні взагалі вихідний. Що я роблю в вихідні - це читаю новини. Для цього в мене є ціла система, розкажу трохи про неї.

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

Раджу почитати книжку Hooked від Nir Eyal, щоб зрозуміти базові принципи (та, будемо відвертими, застосувати у своїй роботі.)

Чим це погано? Тим, що, споживаючи контент як цього від нас хочуть автори, ми втрачаємо контроль над фокусом своєї уваги. Навіть якщо вимкнути нагадування, залишається невпинне відчуття, що може хтось виклав щось новеньке.

Зовім не читати новин і не споживати інформацію безглуздо або просто неможливо. Мій компроміс - збирати всі цікаві мені джерела в одну стрічку, та прочитувати цю стрічку по вихідним.

Домомагає мені в цьому RSS, Miniflux та програма Reeder. На сьогодні все.


27.08.2022

📰🕸🔨 Сьогодні шукав конструктор сайту для дружини. Вимога проста: щоб вона могла без моєї участі працювати над контентом - а саме, для початку, наповнювати фотогалереї. (В мене є стаття про сходи веб технологій, так от в термінології тієї статті потрібно піднятись на другу сходинку.)

Подивився, що пропонують сучасні конструктори. Для мене є два значущих: це Squarespace та Wix. Але хоч я їх поважаю, але жодним не користувався. Ось і тут, Squarespace не підходить за браком української локализації, а Wix мені якось дуже складний та заплутаний. Отже, шукав альтернативи. Знайшов ще Sitepro, який я помітив у партнерці деяких доменних реєстраторів. Але ж не можу знайти в собі довіри до такої платформи.

Нарешті повернувся до того, що знаю, а саме до керованої інсталяції Wordpress. Чому Wordpress:

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

Для початкового налаштування Wordpress потрібно, на мою думку, трошки знатись з технологіями, але якщо перетнути цей бар'єр, то це найкраща платформа для інформаційних сайтів.


26.08.2022

⚛️📲🪄 Пам'ятаєте як вчора Apple попросили зробити видалення акаунту? Так от, сьогодні ввечорі зробив може години за дві.

Головним помічником і заставою продуктивності є React Native. Бачите, видалення акаунту у веб-версії вже зроблено, доволі давно. Чи можу я скопіювати цю фічу з React до мобільного додатку? Звісно ж, ні. Компоненти, вигляд, поведінка фундаментально відрізняються.

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

Зазвичай при оцінці React Native недоглядають цю дуже важливу перевагу - наявність спільного шару бізнес логіки.


25.08.2022

🔥🔥🔥 Сьогодні замість написання гарного посту займався гасінням пожежі (на щастя, метафоричної.)

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

Що ж трапилось? Трапилось те, що між Route53 та Cloudflare є одна маленіка різниця у роботі з TXT записами для CNAME доменов. А цей нюанс ламає перевірку DNS записів. А від перевірки записів залежить дієздатність хелс-чеку. А від роботи хелс-чеку залежить, чи буде супервайзер рестартувати сервіси. А коли сервіси свавільно рестартують, ось це ми називаємо метафоричною пожежею. 🔥

Щоб відновити, довелось перенести хелс-чек на інший домен, що не був схильний до цього багу. Буде про що завтра дописати документацію.

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


24.08.2022

🇺🇦🍾🔑 Сьогодні день приємно продуктивний.

По-перше, з нагоди 🔱 Дня Незалежності, ми випустили в світ повністю українізовану версію Сінтри. Останнє, що довелось зробити - це локалізувати параметри App Store та підписок. Бо і там є рядки, що потребують перекладу - назва та опис додатка, та інше. Локалізація продукта - це набагато ширший процес, ніж просто переклад коду додатка.

Друге - налаштував для стейджингу Cloudflare Access. Це сервіс, яким можна обмежити або захистити доступ до деякого веб-ресурсу. Я вкрай задоволений його гнучкістю.

Раніше ми прикривали стейджинг нашим VPN за допомогою груп безпеки AWS. Це надійно, але незручно. Наприклад, нелегко дати доступ сервісним та тестовим скриптам, або пустити консультантів з-поза меж компанії.

Так от, Cloudflare Access вміє все, що можуть групи безпеки (обмежити доступ по IP), тобто рішення з VPN продовжує працювати. Але до того ж можна: поставити перед сайтом вхід через акаунт Google з певними імейлами чи цілим доменом; дозволити доступ з сервісним токеном; під’єднати тунель від Cloudflare; та багато іншого. Я за один день вирішив всі питання захисту стейджингів, що стояли перед нами роками (бо саморобні рішення вимагали купу часу).


23.08.2022

🛡🚤🏎 Дві цікавинки сьогодні. По-перше, Cloudflare - все ж таки дуже корисний сервіс, з безліччю функцій для захисту. Тут і точне керування протоколами шифрування. І статистика по ним. І можливість закрити весь сайт за примусовим логіном (корисно для стейджингу.) І CDN. Очі розбігаються. Радий що спробували, бо у AWS для всього цього треба робити свої рішення.

По-друге, порівняв MacBook Air M1 vs MacHook Air M2 на самому об'єктивному бенчмарку - а саме, тестах нашого проєкта. Тут і Ruby, і PostgreSQL, і інтеграційні тести фронтенду на React у браузері Chrome. Тобто те, що доводиться робити кожного дня.

Отже, результат: M2 виявився швидше за M1 на 8%. Дрібниці насправді, але приємно. (Набагато важливіше +8 GB RAM.)

Окремий результат - жоден ноут не навантажував CPU більш ніж на 25%. Це обумовлено тим, що тести працюють фактично з одним ядром CPU з восьми. Може, двома, якщо врахувати роботу браузера. Висновок перший: насправді веб-розробнику ніякий M1 Pro з 10 ядрами не потрібен. Висновок другий: при звичайній роботі розробника MacBook Air не має підстав нагріватися та гальмувати.

І нарешті, порівнював ігровий тест, а саме, вбудований тест Shadow of the Tomb Raider. Був здивований майже однаковим результатам: на найвищих налаштуваннях та 1280x800 обидва ноута показують 31 FPS, а на 1920x1200 M2 показує 17 FPS супротив 15 у M1. Остаточний висновок: брати модель з 10 GPU великого сенсу немає.


22.08.2022

🕸🛡☁️ Сьогодні налагоджував захист сайту через Cloudflare. Перше, що для цього потрібно зробити - це перенести DNS записи до Cloudflare. Наші DNS записи описані у Terraform. Як зазвичай, Cloudflare також підтримується терраформом, так що перенесення звелося до переписування ресурсів з aws_route53_record у cloudflare_record. Кльово, що деякі значення у Cloudflare беруться з ресурсів AWS (наприклад, записи для підтверждення сертифікатів.)

Terraform залишається улюбленим інструментом.

Ще така кумедна історія вийшла: в мене вже пару місяців докер віджирав біля 25% CPU. Я це списував на вроджені вади докера, і нічого не робив. Сьогодні прокрастинував і подивився, що ж таке жре CPU в докері. Виявилось, що це не сам докер, а контейнери з haproxy, а потів виявилось, що у haproxy 2.6.3 є баг з постійним використанням 100% одного CPU. Відкотився до 2.6.2, споживання CPU зникло.

До речі, корисна команда: docker stats


21.08.2022

✉️🌍✅ Сьогодні займався локалізацією, доробляв переклади листів. Раніше шаблони листів були у Handlebars (ще раніше просто в Mailgun). Тепер ті самі шаблони обробляються бібліотекою i18next. Так простіше, тим паче нічого більш заміни змінних ми в шаблонах не використовували. Тепер можна і теми листів локалізувати, і форматування дат сховати в шаблон, і консистентність з іншим локалізованим кодом краще.

Цікаво що шаблони листів ми тримаємо в текстових файлах (а теми в типовій структурі i18next.) Стало питання, як бути впевненим, що для кожного різновиду листів визначені обидва шаблона. А до того ж, що кожний шаблон має переклад.

У таких випадках має сенс написати скрипт. Скрипт дуже простий - завантажує ресурси локалізації та перевіряє, що всі переклади задані і немає зайвих. Додав його до лінтерів і таким чином до CI. Тепер можна бути впевненим, що все перекладено вірно.

Скрипти для власного користування - часто зневажена категорія програмування. Чи робиш ти рутинні дії, які міг би за тебе робити скріпт?


20.08.2022

📦💻🤩 Сьогодні розпаковував новий макбук Air M2. Про попередню модель я вже писав детально - новий відрізняється не сильно, але в декількох важливих деталях. Якщо в двух словах, то це все ще кращий ноут для веб-девелоперів, беріть - не пошкодуєте.

- "опівнічний" колір виглядає чорним з ледве помітним синім відливом. Скучив за чорним ноутом, так що дуже задоволений.
- тепер нарешті можна взяти 24 ГБ оперативки, щоб влізли всі докери, рубішні програми, редактори на електроні та інше.
- цей Air зроблений в новому дизайні Apple Silicon, тобто нарешті зовнішність співпадає наповненню
- люблю Fn-рядок з клавішами в повну висоту. ще більше люблю Escape нормального поважного розміру.
- щось дивне зробили з динаміками, тепер вони в торці та направлені в екран. ще не розібрався чи краще чи гірше.

Migration Assistant не захотів переносити по шнурку USB-C, а використав peer-to-peer Wi-Fi. До того, не переніс більшу частину папки з проєктами. Могло бути й краще.


19.08.2022

🛌🍲🏃 Сьогодні робота не дуже клеїлась. Можна шукати багато пояснень, але я в свому житті прийшов до того, що три дуже прості речі є заставою самопочуття і продуктивності.

- Сон - хоча б сім, а краще вісім годин в день. Недостача сна буквально робить нас дурніше, показують дослідження. І це, мабуть, головне, що треба виправляти більшості айтівців.
- Їжа - здорове і регулярне харчування. Якщо неясно, з чого почати, раджу почитати про середземноморсью дієту. Не забуваєм і про українські суперфуди - борщ та гречку. (Серйозно, греча вважається нарівні з модними кіноа та амарантом.)
- Моціон - байдуже що, але головне щоб регулярно. Хоча б прогулянки на свіжому повітрі. Але краще щось, що задіє все тіло. Якщо душа до спорту не лежить, є 7-хвилинні тренування.

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


18.08.2022

🐛🔍🔥 Сьогодні (та й вчора, та й позавчора) довго дебажив. Дебажив досить складний шлях перетворення даних, що проходить через декілька систем. Добре що це було на стейджингу, і що в нас є хелс-чек, який хоча б підказав, що щось поламане.

Окрім хелс-чеків, у складній системі перетворень важливо пам'ятати, де слаба ланка.

Технологія, яка не підводить: AWS Kinesis Firehose. Це такий безрозмірний приймач повідомлень, які він батчить та складає в базу. Зручно для ситуації, коли потрібне бути впевненим в масштабуванні. Колись на проєкті мільярди повідомлень в день збирали, і Firehose цілком спокійно їх обробляв. Ще Firehose добре порається з помилками на боці бази, а саме вміє спробувати завантаження декілька разів, та в разі остаточної невдачі складає помилкові записи на S3. Та й моніторінг у нього зручний і прозорий. Дуже класна технологія і недорога - близько $0.03 за ГБ даних.

Технологія, яка підвела вже не раз: гем sidekiq-unique-jobs. Він запобігає подвійному запуску завдання за допомогою запираючих записів у Redis. Але, в разі катастрофічного виходу ці записи можуть залишитись назавжди, і наступного разу завдання ніколи не запуститься. А якщо не налаштувати правильно вихід sidekiq при зупинці сервісу, то катастрофічним буде кожний вихід. Через це ми пройшли минулого разу коли це трапилось. Цього разу ще додав Time-To-Live. Раджу без Time-To-Live для лок-записів навіть не починати з цим гемом.


17.08.2022

📱🎮⏱ Сьогодні несподівано для себе зробив маленьку, але справжню мобільну гру, і навіть встиг завантажити до Test Flight. Ну тобто не всю гру, а "вертикальний зріз". Але, як кажуть, лиха біда - початок.

Я давно це обіцяв синові, бо ідея його, та й оформлення буде теж його. З мене - програмування.

Почати було важко. Новий проєкт - купа питань. На чому писати. (До речі, гра має вийти в iOS/Play Store/Steam, тож щось кросплатформенне.) Як все облаштувати. І таке інше. Свято прокрастинації та гоління яків.

Але сьогодні все ж таки взяв найзнайоміший інструмент та почав. На React Native. І от, на створення проєкту та перші прототипи уйшло десь півгодини. У сучасного React Native гарний шаблон додатка, до того ж є версія на TypeScript. Ще півгодини на публікацію в TestFlight (акаунт в мене вже був.) Тепер є шанс, що гра все ж таки побачить світ.

Моралі дві:

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


16.08.2022

🗄🗄🗄 Сьогодні продовжую розбиратися з ElasticSearch, тобто насправді з OpenSearch.

Завантажив датасет на 5 ГБ. Для цього є операція _bulk, в яку влазить невідомо скільки записів за раз. Сто тисяч точно влазить, а більше соромно було спробувати. Звісно, записи відправляються в форматі рядків JSON, тобто якщо ви відвантажили JSON з іншої бази, то його можна без перетворень залити в OpenSearch. Тільки й різниці, що перед кожним рядком треба додати рядок з командою _create. П'ять гігабайтів база забрала десь за 8 хвилин - це з негайною індексацією. Відзначу, що непогано працює система типів - mappings (а саме, значення типу "дата" або "IP адреса" проходять перевірку).

Після цього до бази можна ставити запити - або за допомогою езотеричних JSON-структур, або SQL з купою обмежень.І це, мабуть, найслабкіше місце OpenSearch. З прикладів видно, що база вміє дуже багато - наприклад, миттєво проводить пошук та агрегації. Але це якщо навчитись писати до неї запити.

Але ж так само з Redis, Mongo, CouchDB або будь-якою новітньою базою даних. У кожної є деякі переваги над SQL базами. Як правило це набагато краще продуктивність у деяких специфічних сценаріях. І кожну з них треба знати, коли і як використати. Натомість SQL бази можуть "все", але ж в продуктивності програють.


15.08.2022

🇺🇦📲❤️ Сьогодні, на хвилі локалізації, переклав українською мовою RSS-читач miniflux.

Miniflux - це RSS-читач, написаний на Go, з самостійним розміщенням (в мене - на fly.io.) Люблю його за простоту та за надійність. З необхідних мені фіч, він вміє організувати стрічки в категорії та підтримує Google Reader API (що й досі є де-факто стандартним API для читачів RSS.)

А щодо перекладу - на мою думку, якщо ти знаєш англійську мову - то це легкий та доступний внесок в поширення української. Послідовність дій така:

- або знаходиш OSS проєкт з наявною підтримкою I18n, але відсутнєю українською мовою. Тоді все, що залишається - це перекласти словник з фразами. Ось приклад інструкції з miniflux.

- або знаходиш iOS/macOS додаток, який має підтримку декількох мов (це повідомляється на сторінці додадка у App Store), та пропонуєш творцям додати переклад. Далі, скоріш за все, перекладаєш такий самий словник.

А ще з цього вийшов би добрий хакатон.


14.08.2022

🔥☁️🪄 Сьогодні ще трошки займався локалізацією, а саме перемиканням мови. Отже, хочу похвалитися чарівною синхронизацією, яку нам надає Firebase.

На скріншоті показано наш сайт та мобільний додаток. Вони ніяк між собою не пов'язані, окрім як через хмарну базу даних Firebase Firestore. І як ви бачите, при перемиканні мови на сайті, мова в додатку перемикається миттєво! Так працює не тільки локалізація, а й будь-які ваші дії. Це найкрутіший рівень синхронізації який я взагалі бачив. Особливо приємно, що Firestore так працює "сама", ми жодних зусиль до цього не прикладали. Все, що треба було зробити - це підключити клієнт та підписатись на оновлення документів. Ну та й звісно, використовувати React / Redux.

До речі, детальніше про нашу архітектуру я писав у статті.


13.08.2022

✨🔄🇺🇦 Сьогодні займався локалізацією Сінтри. А конкретно, переклав статичну частину. Сайт у нас на Hugo. У Hugo дуже кльова система локалізації.

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

Відкриття дня: Google App Engine автоматично робить геолокацію по IP і надсилає результат в заголовках. Тобто ніякого MaxMind не треба, щоб дізнатись країну користувача. Оскільки ми хостимося у Firebase, то на наші хмарні функції це як раз поширюється.


12.08.2022

⏱🗂🔍 Сьогодні розбираюсь з ElasticSearch. Відкриття дня: це не двигун повнотекстового пошуку, як я завжди думав.

ElasticSearch це NoSQL база даних. Вона не тільки шукає, а й зберігає документи, тобто в деяких випадках може бути єдиною базою в проєкті. Як виявляється, вона заточена під роботу з часовими потоками даних. Приклад з підручника - структуровані журнальні записи. Дані можно і шукати, і агрегувати. До того ж, є можливість згортати (rollup) старі записи, коли від них залишаються тільки результати агрегацій за деякими атрибутами.

Ще одна вигідна якість - ElasticSearch індексує нові документи миттєво. Ще її можна використати з AWS Kinesis Firehose - звідти я на неЇ і потрапив. (До речі, з минулого року ElasticSearch звузили ліцензію і тепер у AWS та навіть у Homebrew доступний тільки відкритий форк - OpenSearch.)

Поки ще ретельно не тестував, але обіцяє буди гарною заміною доморощеним засобам на базі Redshift.


11.08.2022

🏗🤖☁️ Сьогодні переносив наш Terraform до сервісу Scalr. Тепер, замість запусків вручну на своїй машині, Scalr буде зтягувати з Git конфігурацію, (напів-)автоматично її приміняти, та зберігати стан. Спободалось.

Головне, що очікую від Scalr - ясність в тому, що де розгорнуто. У нас над конфігурацією працюють багато людей, до того ж ми тримаємо декілька стейджингів. У цьому хаосі стало важко відстежити, яка версія розгорнута на якому стейджингу, чи свіжий продакшн, і що взагалі відбувається. Scalr має допомогти і з прозорістю, і з послідовністю.

Але у Scalr є й інші смачні фічі - гнучке керування доступом, можливість імпортувати значення з однієї конфігурацію в іншу.

Прикольно, що сам Scalr надає провайдера для Terraform. Тобто для налаштування Scalr не треба блукати веб-інтерфейсом, можна написати конфігурацію. Як завжди, Terraform - ідеальна альтернатива заповненню форм вручну. Колись Terraform відкрив для мене світ хмарної інфраструктури. Бо управління AWS вручну то була сізіфова праця; а Terraform замість того дає описати ресурси на декларативній мові і підтримувати їх в порядку.


10.08.2022

🐞🔍😅 Сьогодні довелося багато попрацювати з помилками виконання на мові Go. Go - мова з яскраво вираженою авторською думкою. Отже і обробка помилок в Go зроблена цікавим і авторським чином. Ось декілька фактів про неї:

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

Цю систему я то ненавиджу, то люблю. Адже вона привчає до того, що помилки виконання - неминучий аспект життя, і готуватись до них потрібно завжди.


09.08.2022

👱‍♂️💻👱‍♂️ Сьогодні я майже цілий день програмував у парі. Колись я вважав парне програмування безглуздим марнуванням часу (а може, ще й оплачуваного клієнтом). Але це буде правдою, тільки якщо припустити, що поодинці два інженери зроблять в два рази більше роботи, ніж удвох. Продуктивність програмістів - дуже абстрактна величина, тому таке твердження легко приймається на віру.

Але ж робота програміста складається не тільки з написання коду. І мета парного програмування - зовсім не написати його більше (це взагалі погана мета.)

В пару сідають, щоб:

- приймати удвох складні тактичні рішення - про архітектуру, про шлях відлагодження, про іменування...
- навчити чомусь одне одного - про проєкт, про код, про технології, про підходи...

Кращий код та сильніша команда - гідний привід деколи "помарнувати час".


08.08.2022

👷🤙🪓 Сьогодні я повісив люстру-вентилятор. Особливого хисту до ремонтних робіт в мене немає, але ж шукати найманця теж не хотілось, а люстра мала бути повішена.

Інструкції до люстри були суто схематичні, до того ж іспанською мовою та ще й явно перекладені з китайської. Та такі пазли інженеру розв’язувати знайомо та приємно. Розклав частини на дивані, зрозумів приблизно що за чим йде, та й стало все ясно.

Слабким місцем виявилось свердління у стелі під анкерний болт. Ось тут я взагалі не майстр. Після десяти хвилин знущання над стелею шуруповертом зробив третину одного з двох отворів. Тобто чисто математично, за годину я б впорався - але година притискання свердла до стелі це неабиякий воркаут. І... хіба всі так довго дірки роблять?

Замість того, запитав у досвідченої людини, як правильно налаштувати шуруповерта. У розмові проміж діла виявилось, що свердла мають властивість “втомлюватись” - тупитися і міняти колір. Який збіг - в мене свердло взагалі коричневе! Сходив до крамниці за новим свердлом. Звичайним дешевим свердлом по бетону.

З новим свердлом робота зайняла менше хвилини! Воно вгризалося в стелю настільки швидко, що я не вірив своїм очам. Після цього залишок роботи пройшов впевнено та вчасно.

Занотую три висновки:

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