Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
10.01.2023
Інтернет у відсутності електроживлення
Як отримати інтернет за відсутності електроживлення? Тут варіанта три. Ідеальний — це оптика до квартири. Оптичне підключення не потребує підсилення, тому сигнал йде від провайдера напряму. Якщо у вас є живлення, та у провайдера теж — інтернет буде. Для цього вкрай необхідно, щоб оптичний кабель доходив аж до квартири — не всі провайдери так роблять, у мого Київстару оптика тільки до даху, тож без світла інтернет зникає. А ось інший місцевий провайдер дотягнув оптику до хати. Оптичний кабель закінчується адаптером, з якого виходить звичайна вита пара. Зазначу, що цей адаптер варто розмістити в коридорі або тамбурі, бо пересувати його буде неможливо без майстра та зварювального апарату. Але ж також не забувати, що адаптер треба буде живити, в тому числі від павербанка — про це далі.
Також навіть з дротовим підключенням теоретично можливо заживити апаратуру провайдера на даху, і мати інтернет. Але, як розумієш, це набагато складніше.
Ну і є ще мобільний звʼязок — який в теорії є завжди, але на практиці його пропускна здатність не розрахована на одночасне підключення всіх мешканців дому чи району. А пізніше на стільникових вежах виходять акумулятори, і звʼязок закінчується абсолютно. Проте з переваг — роздавати мобільний звʼязок можна як зі звичайного телефону, так і через USB модем, який, до речі, можна й підключати до більш-менш просунутих роутерів.
Тепер — як живити роутер та оптичний адаптер? У обох є блоки живлення зі звичайною вилкою 220V. Якщо у вас є великий павербанк з інвертором та розеткою, то питання ніби вирішено. Але навіть якщо так, краще буде живити пристрої від джерела постійного струму (DC) - найстандартнішим з яких на цей час є USB. Річ у тім, що блок живлення роутера саме й перетворює 220V назад на постійний низьковольтовий струм. На перетворення туди й назад витрачається коштовна енергія. (До речі, тому й освітлення від павербанка краще живити від USB.)
Тож як під’єднати роутер до USB? Спочатку треба визначити, який саме розʼєм у роутера; для цього виміряти його діаметр, а ще подивитись на блоці живлення напругу та струм. Якщо роутеру потрібно не більше 12V - то його можна заживити від USB адаптером на кшталт такого. А більше — тільки від USB-C - тоді адаптер потрібен такий. Відповідно, павербанк має видавати достатню потужність, а головне — підтримувати напругу. Бо USB-C може видавати різну напругу, від 5V аж до 48V в найбільш сучасному стандарті — але на яку саме спроможний павербанк, можна дізнатись в його документації.
Як абсолютна протилежність всьому цьому - 4G-WiFi роутер, який можна вставити в будь-який павербанк з USB та отримати WiFi з мобільним звʼязком. Не так надійно, зате просто та дешево.
09.01.2023
Дискриміновані союзи у TypeScript як засіб розширення додатків
Продовжуючи тему Сінтри, з “Цілями та заощадженнями” зʼявляється новий різновид витрати — витрата з переводом на заощадження. До неї застосовується особлива логіка, наприклад — замість категорії відображатиметься заощадження. Логічно.
Коли до готової нетипізованої схеми даних додається нова форма, то буде складно відстежити всі місця, де треба врахувати її. На моєму досвіді це зведеться до ручного пошуку помилок, та, якщо пощастило з проєктом — оновленням відповідних тестів. Так буде і на JavaScript, і на Ruby.
В типізованій мові могло б бути так же. Наприклад, якщо в TypeScript до типу Expense я додам нове поле goalID, то так само доведеться шукати всі місця використання цього типу. Але у TypeScript є краще рішення на таку ситуацію — дискриміновані союзи. Це спосіб, фактично, сказати, що у витрати є дві різних форми — або з полем categoryID, або полем goalID. Тепер весь код, що очікує бачити витрати з категоріями, стане помилковим, оскільки не враховує всі можливі варіанти типу. Щоб виправити його, потрібно додати до коду перевірку на тип витрати. Так автоматична перевірка типів замінить нам ручне тестування.
При цьому, що важливо, інформація про тип дискримінованого союзу береться з самого обʼєкту — зі значення або наявності поля-“дискримінанта”. Тож з боку JavaScript та, головне, з боку бази даних цей тип залишається звичайнісіньким обʼєктом JSON.
08.01.2023
Як я будую структури даних додатків на React за допомогою reselect
Сьогодні день Сінтри; просуваюсь до розділу “Ціли та накопичення”. Доречно буде розказати про мою улюблену схему організації потоку даних для React/Redux.
Я звик розташовувати у Redux дані у найбільш спрощеній формі. (Частково тому, що я віддаю перевагу архітектурі без бекенду, тому не маю можливості перенести логіку туди, щоб отримувати більш підготовані дані.) Далі всі форми, що необхідні для відображення компонент, створюються шаром селекторів, тобто функцій, що отримують на вхід стан Redux та повертають те, що потрібно. Компонентам залишається підписатись на результати селекторів хуком useSelector.
Селекторів маю три різновиди. Перший — звичайна функція як вона є; такі добре підходять для простих перетворень, наприклад, вибірки піддерева стану.
Другий — селектори reselect. Їхній результат кешується, але дещо нетривіально. Функція-селектор будується з функцій підготовки аргументів, та “робочої” функції, що обчислює результат. Поки аргументи не змінюються, “робоча” функція не буде викликана. Так, наприклад, можна побудувати селектор, що буде підраховувати загальну суму витрат — але тільки тоді, коли у стані змінюються витрати.
Головне, що для підготовки аргументів можна використати інші селектори, і саме з вкладених функцій-селекторів і будується та частина бізнес-логіки, що стосується відображення.
Але з селекторами, що повертають складні обʼєкти, є проблема: згенерований ними результат буде змінюватись за посиланням навіть коли він залишається сталим за значенням. У такому випадку всі залежні селектори та компоненти будуть перераховані зайвий раз. Ну, наприклад: в мене є селектор, що з масиву цілей робить обʼєкт-словник, проіндексований за ID. Він лежить в основі багатьох інших селекторів. Всі вони будуть перераховані кожний раз, коли є зміни в будь-якому місці вхідного масиву. Саме через такі марні витрати й починають гальмувати додатки на React. Я про це писав цілу статтю, висновок якої — що треба для таких випадків використовувати стабільні селектори, які додатково перевіряють, чи змінився обʼєкт за значенням.
Всі три різновиди селекторів мають інтерфейс звичайної функції, та є взаємозамінними, тому їх легко рефакторити або додавати нові.
До речі, саме таку архітектуру рекомендує сучасний Redux.
07.01.2023
Як я автоматизую обробку відеофайлів - Ruby, MediaInfo, ffmpeg
Ще одна задача святкового прибирання — звільнити на диску місце для фільмів. А саме, вирішив перекодувати колекцію до HEVC, що, порівняно з поширеним кодеком AVC, дає економію розміру в 4-5 разів. Як відомо, перекодування відео — це як не найважча задача для персонального комп’ютера, тож підходити до неї треба з хорошим планом.
По-перше, вирішив знайти найбільші файли. Чомусь гарної утиліти для цього не знайшов — або не хотів шукати довше, ніж писати скрипт на Ruby. Маючи команди Dir#glob та File#stat, зібрати найбільші файли в ієрархії директорій дуже просто.
Окрім розміру важливо було дізнатись відеокодек кожного фільму, щоб не кодувати те, що вже у HEVC. Для цього утиліту знайшов - MediaInfo. Ця утиліта командного рядка може одною командою повідомити про кодек — тому її можна легко вбудувати у той самий скрипт на Ruby. До речі, ще зʼясував найпростіший спосіб викликати з Ruby команду за списком аргументів — езотеричний Open3#capture2: codec, = Open3.capture2('mediainfo', '--Output=Video;%CodecID%', file).
Тепер, як перекодовувати? Тут для мене є очевидний вибір — команда ffmpeg. В інтернеті можна найти купу різних конфігурацій для неї, тож не буду додавати до всього цього шуму свою. Скажу тільки, що знайшов кодек hevc_nvenc, який все робить на моїй відеокартці. GeForce RTX 3080 може кодувати відео 1080p з прискоренням у 16 разів; тобто на один фільм уходить близько 6 хвилин. З цим навіть Apple M2 не може порівнятись; втім, в мене найслабкіший з M2, та головне — без активного охолодження. В той час 3080 має водяне охолодження, та вище 30 градусів не гріється.
І ще нюанс: кодування мені треба робити на машині з Windows, яка служить домашнім медіацентром. Але там бракує знайомого середовища розробки. Тож я написав скрипт на Ruby, який генерує пакетний файл (.bat) з усіма інструкціями. Далі цей скрипт копіюю на медіацентр та просто запускаю.
06.01.2023
Як я впроваджую в себе принцип Inbox Zero
Я думав, що Inbox Zero - загально відома річ, але ось не зміг знайти жодної статті українською. Ну то й годі, розкажу. Це така методологія роботи з інбоксами, себто місцями, куди тобі можуть підсипати новенького — будь то “Вхідні” у пошті, у месенджері, нотатки, робочий стіл, і так далі. Якщо взяти за статус кво так зване “життя в інбоксі” - коли ти реагуєш на вхідні безпосередньо в інбоксі, та видаляєш звідти те, що вже не потребує уваги — то Inbox Zero пропонує замість цього тримати інбокс порожнім. При цьому записи, що потребують уваги, переносити у список задач, а все інше — видаляти. Це робити треба щодня, або за іншим зручним розкладом.
Перевага такого підходу в тому, що задачі чітко відокремлюються від несуттєвих записів. А також в тому, ми гарантовано звернемо увагу на кожний запис, що потрапляє до інбоксу. Ну, і нарешті, метод влаштовує психологічну безпечну зону замість чорної діри, в яку перетворюється інбокс звичайний — в мене на початок року в теці “Вхідні” було близько 2000 листів.
Передумова методу Inbox Zero - якийсь надійний список задач. Оскільки в мене тепер є надійний блокнот, розкажу, як в нього вписується Inbox Zero.
В мене інбоксів декілька. Окрім пошти, головний — це нотатки у Drafts, які я до цього використав як список задач. Drafts - моя улюблена система простих тимчасових нотаток. Записувати їх можна навіть з Apple Watch, тобто в будь-якій ситуації. Також як інбокс варто обробляти кожне місце, де накопичується без контролю зміст — для мене це в першу чергу тека “Завантажені”.
Щоранку першим чином я перебираю всі нові листи, нотатки, файли та т.п., та переношу — або в блокнот як задачу, або в базу знань, або видаляю. Головне — що після цього інбокси стають порожніми. Окрім того, я ще проходжу по повідомленнях в Слаці та в Гітхабі, але там зазвичай реагую “на місці” та теж спорожнюю.
Як перейти до такої схеми, коли вже є 2000 вхідних листів? Звісно ж, не обробляти їх всі. Це займе бозна скільки часу. Краще перемістити всі листи в окрему теку, таким чином впровадити Inbox Zero, а потім поступово вичищати теку зі старими листами. Або, ще можна все видалити, якщо припустити, що лист, який сидить в інбоксі місяць, не вартий уваги. Але я не настільки сміливий.
Жити з порожнім інбоксом набагато спокійніше. Щоправда, тепер є питання — що робити зі списком задач?
05.01.2023
Як налаштувати мовний сервер Solargraph для підказок по Ruby в VS Code
Сьогодні, на запит колеги Антона, інструкція по налаштуванню мовного сервера для Ruby кода для VSCode (та інших редакторів) - Solargraph. Solargraph надає редакторам “розумні” функції роботи над кодом, такі, як перехід до оголошення методу чи класу, доповнення коду та інше. Все це працює по моделі так званого мовного сервера, тому є сумісним з будь-яким редактором, що підтримує відповідний протокол.
Тож першим чином встановлюємо інтеграцію Solargraph з VSCode. Тільки сама інтеграція нічого не вміє. Далі потрібен гем solargraph. Його не треба мати в Бандлері, але — необхідно мати у поточній версії Ruby. Тобто після кожного оновлення доведеться не забути поставити. Тут є трюк — принаймні, для менеджера версій asdf можна записати гем у ~/.default-gems, та він встановиться автоматично. (І так, asdf - єдиний менеджер версій, що є на моїй системі.)
Цього буде достатньо, щоб бачити підказки по власному коду, але не по коду залежностей — тому рухаємося далі. Solargraph насправді читає не код, а його документацію, та спирається на ту, що згенерована командою yard. Тому після встановлення гемів необхідно запустити команду yard gems. Це теж можна автоматизувати, якщо записати відповідну опцію у конфігурацію командою yard config --gem-install-yri; після цього для кожного нового гему документація буде згенерована автоматично. Опція глобальна та міститься у файлі ~/.gemrc.
Все це добре, але для Rails не дасть хороших результатів тому, що Rails, по-перше, не має гарної документації у форматі Yard, а по-друге, вживає багато метапрограмування. Коли атрибути моделі генеруються під час запуску з бази даних, то простий аналіз коду їх не знайде. Потрібний підхід, що знає про конвенції Rails. Для цього існує гем solargraph-rails. Його треба спочатку встановити (так само як і сам Solargraph), а потім додати до проєкту конфігураційний файл. Що робити, якщо файл потрібний тільки тобі, та додавати його до командного репозиторію не дозволяють? Для цього є глобальний .gitignore. Додаємо туди .solargraph.yml, і ніхто не буде знати, що в нас є такий файл.
От і все — після цього твій редактор отримає повноцінне “розуміння” коду на Ruby. На останнє, після всіх налаштувань у VS Code варто запустити команду “Restart Solargraph”. А ще, якщо Solargraph потрібний тільки в окремому проєкті чи проєктах, можна вимкнути доповнення у VS Code глобально, а потім увімкнути для конкретних проєктів — я саме так і роблю.
04.01.2023
Заголовки до постів
Додав сьогодні заголовки до постів у канал (поки що їх видно тільки на сайті.) Головна причина в пошуковій оптимізації, бо як я зʼясував, якщо єдине, що є в заголовку — це дата, то Гугл такі сторінки не дуже високо оцінює.
Але також заголовок допомагає відразу зрозуміти, про що пост, та, я сподіваюсь, швидше вирішити, що його варто читати. Тому рано чи пізно заголовки зʼявляться і в Телеграмі (як тільки додам цю можливість до мого бота.) На початку я збирався до кожного поста робити ілюстрацію з трьох емоджі, але ця ідея в мене вже вичерпалась.
03.01.2023
Огляд локального емулятору для Firebase
Нарешті повернувся до роботи над Сінтрою, бо до Нового Року просто часу не було.
Відкрию таємницю — до сьогодні в нас не було ніякої локальної копії даних; вся розробка велась безпосередньо “в продакшні”. Це працює краще, ніж воно здається, тому що дані в базі розділені за користувачами, та до того ж немає схеми, яку потрібно було б мігрувати. Як ми почали розробку “в продакшні” до публічного запуску, так і не припиняли. Проте все ж таки можна поламати продукт для всіх, наприклад, поганими налаштуваннями правил безпеки. Це трапилось зі мною минулого тижня — тож вирішив нарешті розібратися з локальною копією.
Виявилось, що у Firebase чудовий локальний емулятор, якщо порівнювати його зі стеком Ruby on Rails + PostgreSQL, то працювати з ним навіть легше. Емулятор підтримує все, що нам потрібно — аутентифікацію; базу Firestore; хмарні функції; виклик функції на події (pub/sub). Звісно ж, всі вони працюють як єдине ціле: наприклад, після реєстрації користувача викликається хмарна функція, яка писатиме в Firestore.
Для використання емулятора достатньо встановити його, а в коді клієнта додати виклики useEmulator. Емулятор автоматично візьме з проєкту наявні правила безпеки бази та код хмарних функцій. Порівняно з цим оті Rails та docked виглядає анахронічно.
Але ж емулятор ще й має переваги над роботою зі справжнім Firebase. Правила безпеки бази та хмарні функції оновлюються наживу. У емулятора є UI, де можна переглянути зміст бази та перелік користувачів. Всі запити до бази логуються, а якщо їх не дозволяють правила — то в UI емулятора можна побачити, який саме рядок правил, та з якими вхідними параметрами. Так само логуються й виклики функцій. Та хіба треба нагадувати, що емулятор працює без інтернету? Та дозволяє писати повноцінні інтеграційні тести?
Хоч емулятор і не додається до нового проєкту автоматично, тепер не бачу сенсу не налаштувати його в першу чергу. Firebase - чудова платформа.
02.01.2023
Прогрес з RSS-стрічкою для Reddit
Сьогодні в мене почалась відпустка, але мета відпустки — підігнати інші проєкти, на які з роботою не вистачає часу.
Погрався трохи з генерацією повнотекстової RSS-стрічки Reddit, такої як я зробив для Hacker News. Виявив ряд особливостей.
Ну, по-перше, Hacker News один, а сабреддітів безліч, тож одну стрічку на всіх не зробиш. Якщо відкривати власне рішення (щоб не марно його писати), бачу три варіанти. Або робити сервіс — напевно, платний, бо збирати стрічки та обходити обмеження без витрат не вийде. Або опен-сорсити, щоб кожний сам розгортав. Або ж ще можна зробити стрічки для декількох цікавих мультіреддітів — ну, наприклад, зібрати мультіреддіт для вебтехнологій. От з останнього спробую почати.
Далі, як взагалі забирати дані з Реддіту? Спочатку я хотів витягувати RSS-стрічку та скрейпати додаткові дані зі сторінок окремих постів. Але потім помітив, що адреса RSS - це та сама адреса сабреддіту, але з суфіксом .rss та спробував замість нього написати суфікс .json. Працює! Будь-яку сторінку — сабреддіт або окремий пост — можна легко отримати у форматі JSON. Та для цього не потрібно використання API та ніякої авторизації. На мою думку, чудове рішення.
Нарешті, Reddit зараз суворо ставиться до ботів, кілька запитів — і ви вже бачите блок-сторінку. Але я знайшов, як обійти, через два заходи. Включив cookie - для цього в Ruby є чудовий гем Mechanize. А також почав назначати user agent, згенерований бібліотекою Faker. Так, принаймні, 50 послідовних запитів в мене не блокуються. Також необхідно впровадити кеш, щоб не повторювати ті самі запити — в мене вже такий є.
01.01.2023
Бачення проєкту
Перше січня. Час поговорити про бачення, або ж як ще кажуть, vision. Бачення — це душа проєкту; без бачення залишається проєкт-зомбі, що рухається незрозуміло куди, незрозуміло навіщо.
Про бачення складно говорити, бо це відчуття. У айтівців зазвичай складно з такими “мʼякими” поняттями, тому питання про бачення заміняються на підрахування “за” та “проти”, призначення числових оцінок, та інші аналітичні засоби.
На моєму досвіді, найкращі (високорівневі) рішення приймалися за інтуїцією, а не за аналізом. Безумовно, інтуїція зʼявляється не на порожньому місці, а навпаки, часто доводиться довго тикатись-микатись в пошуках правильного підходу. Але коли доходить до аналізу, то, в гарному випадку — рішення вже прийняте та його залишилось підтвердити; а в поганому випадку — воно вибирається навмання.
Тож я б радив ще до заповнення таблички “за” та “проти” прислухатись до інтуїції та зрозуміти, чи є робочий варіант, що відчувається вірним. Якщо є — добре! Заповняємо табличку від душі. Якщо ні — треба шукати далі; випробувати різні прототипи; поки інтуїція не скаже — ось воно!
Бути архітектором — значить мати сміливість бути впевненим у своїх рішеннях. А також сміливість прийняти відповідальність, коли вони виявляються хибними.
На ці міркування мене наштовхнуло відео про те, як Стів Джобс відповідав на їдке запитання. Та ще трохи перегляд “Матриці”.

