Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
30.01.2023
Порада про захист сайтів з Cloudflare, та інша порада про цінність вузько націленого коду.
-
Якщо використовуєте Cloudflare, моя порада — встановити у правилах сторінок високий рівень безпеки для вашої сторінки логіну (а також, можливо, реєстрації та білінгу, залежить.) Це у
Page rules -> додати -> Security Level: High. До такого висновку я прийшов після того, як припинив чергову атаку по підбору паролів на нашому сайті. А ще цікаво, що наш нападник, який мав доступ до тисячі IP-адрес, не здогадався міняти свій User Agent, і таким чином був легко відфільтрований та знешкоджений. Добре, що Cloudflare дає всі інструменти, щоб відділити злочинні запити від нормальних, та швиденько їх заблокувати. Погано, що я поки не знайшов способу автоматично помічати такі атаки раніше. Цього разу помітив через високе споживання процесора, але це трапилось суттєво пізніше початку атаки. -
Всі інженери полюбляють узагальнені, універсальні рішення. Так приємно знати, що ти готовий до будь-чого. Але треба признати, що універсальність часто отримується в обмін на швидкодію. Іноді найкраща оптимізація — це прописати код чітко під задачу. Так в мене і трапилось: шукав шляхи оптимізації величезної SQL-вьюхи на будь-який випадок життя. А потім зрозумів, що насправді треба виписати найбільш популярні структури запитів, та зробити для них окремі, спрощені вьюхи. До речі, оскільки все це керується будівельником запитів на Ruby, то клієнти навіть не дізнаються, що від обраних аргументів міняється повністю весь запит. Так з єдиним інтерфейсом продовжуватимуть працювати як прискорені популярні запити, так і універсальні, але повільні.
29.01.2023
OpenMW: сучасний спосіб пограти у Morrowind. А також, його збірка — спосіб себе помучити.
Morrowind, на мою думку — вершина RPG-пісочниць від першого лиця. Немає у наш час більше великобюджетних ігор з левітацією (бо швидкодія), з такою кількістю діалогів (бо озвучка), та й з таким дивним, незвичним світом (бо не окупиться.) Так що, хоч грі вже понад 20 років, а спільнота досі жива та є що від неї чекати.
Сучасний спосіб грати у Morrowind - це через клієнта OpenMW; він повністю заміняє оригінальну програму, та не тільки підтримує весь функціонал, а й додає купу нового. Чого варто хоча б підтримка macOS!
Для керування модами є сучасний менеджер модів portmod. А для пошуку модів, окрім сайту NexusMods, що колись називався TES Nexus, є ще й сучасний ресурс Modding OpenMW, де зручно перелічені різні набори модів — від тих, що роблять косметичний ремонт оригінальної гри, до повних перетворень. (До речі, portmod вміє встановлювати списки модів з цього сайту.) Також наприкінці минулого року вийшли величезні доповнення карти та квестів від Tamriel Rebuilt та Skyrim: Home of the Nords.
Одним словом, для мене Morrowind залишається чудовою розвагою, яку можна запустити на ноутбуці для короткої перерви. Так воно й було, поки не захотілось більшого. Побачив, що у їхньої команди немає кому зробити збірку останньої тестової версії для M1 Mac; стабільна версія є тільки для Intel, а попередня тестова версія для M1 працює в рази краще, але вона з багами.
Що ж, я щось вмію, вирішив зробити збірку сам. Основний набутий досвід — тулчейни для веброзробників це просто космос, порівняно з тим, з чим працюють розробники на C++. Керування залежностями як таке відсутнє; залежності “просто” мають бути присутніми на твоїй машині. Щось з них може встановити Homebrew; щось потрібно стягнути та зібрати вручну. Але стандартів бібліотек як таких теж немає; буває так, що встановлена з Homebrew версія має іншу структуру та не підходить для скрипту збірки (так сталося з bullet). До речі, всі бібліотеки, які довелося збирати, використовують утиліту CMake. Кожний скрипт CMake має секцію, де він намагається вгадати, чи є на диску його залежності, та де, та в якому форматі. Інколи бібліотек є декілька, та він плутає. Інколи замість бібліотеки на M1 бере бібліотеку для Intel. Інколи він спочатку знаходить, а потім під час компіляції каже дивну помилку, причому у 100% випадків якщо щось не компілюється — то проблема з залежностями. Якщо тільки не з компілятором. Бо на різних системах все компілюється різними компіляторами, а MacOS - не сама популярна OS, та до того ж, з не дуже стабільним тулчейном.
Поки в мене вийшло зібрати додаток OpenMW, але в ньому чомусь бракує динамічних бібліотек, тому він не запускається. Спробую наступного разу, як буду сердитися на Yarn.
28.01.2023
Як працюють віджети на iOS
Вже два роки на iOS є віджети, та, напевно, всі вже звикли до цих зручних доповнень до звичайного інтерфейсу додатків. Але з боку розробки віджети стали революцією. Будь-який розробник додатків для iOS добре знає, що вся архітектура цієї операційної системи побудована на економії батареї, а значить — процесорного часу. Тільки поточний додаток отримує повний доступ до процесора; всі інші — тільки суттєво обмежений; фактично, вони стоять на паузі, якщо не отримують повідомлень та не відтворюють звук. До того ж додаток, прихований з екрана, має бути готовий, що ОС повністю завершить його роботу будь-який момент. Як же ж при такій суворій економії енергії можливо, щоб відразу декілька віджетів були постійно відображені на головному екрані?
Відповідь в тому, що віджети на iOS взагалі не є додатками. Правильніше скати, що віджет являє собою векторне зображення, тобто інструкцію про те, що треба намалювати. Технічно, є також програма, яка будує віджет, але вона викликається відносно рідко — в кращому випадку, декілька десятків разів на день. Тож віджети за своєю природою не можуть мати нічого інтерактивного, окрім кнопок-посилань. Для економії оновлень, віджет насправді задається як така собі анімація, тобто не одне, а серія зображень, які змінюються за зазначеним розкладом. Наприклад, віджет погоди може завантажити послідовність погодних станів на кожну з наступних годин по черзі. Чого він не може зробити, це щогодини ходити на сервер за новими даними. Принаймні, не гарантовано.
Така система розрахована на те, що ми можемо передбачити зміст віджета, поки додаток не змінюється. Та дійсно, за моїм досвідом, такий прогноз можливо та навіть цікаво робити. Наприклад, мій віджет для самоменеджменту враховував поточний таймбокс (наприклад, робота / дім), та показував відповідну наступну задачу. Для цього в додатку я будував серію станів для кожного таймбоксу. Така серія була актуальна, допоки ти не зайдеш у додаток — наприклад, щоб закрити задачу. Тоді віджет перемальовувався.
А ще цікаво, що структура віджета — це, фактично та буквально, SwiftUI. Як бачите, коли Apple робили декларативну бібліотеку для інтерфейсів, вони планували не просто спростити розробку та зробити її схожою на React. Вони також заклали можливість зберігати та відтворювати знімки інтерфейсу. Це корисно не тільки для віджетів, але й для Apple Watch, де економія батареї ще більш важлива.
27.01.2023
Чому важливо відмовлятись від справ
Сьогодні, нарешті, заархівував всі свої плагіни до Sublime Text. Це після того, як я вже багато років не користуюсь цим редактором, а переїхав на VS Code - де, до речі, функції моїх плагінів були вбудовані. Звісно, ніякої мотивації підтримувати плагіни не залишилось. Але припиняти проєкти — це боляче. Тому вони просто існували, накопичували жалоби користувачів на Гітхабі, та страшенно муляли мені очі.
Мало написано про те, як скасовувати справи. Література про продуктивність зазвичай турбується або про те, як закінчувати справи, або як їх розпочати. Але скасовувати найважче — принаймні, для мене — бо для цього треба признати, що ціль не буде досягнута. Легше тримати таку справу в стані зомбі. Хоча й очевидно, що багато справ не варті того, щоб їх починати, та навіть розпочавши — закінчувати. Тому, — принаймні, в мене — кожний список задач з часом загрузає в пунктах, які я вже точно (якщо бути реалістом) не зроблю. Це одна з головних причин моїх невдач з самоменеджментом. В мене завжди нових ідей більше, ніж часу на їх виконання, тому як в робочому, так і в особистому житті без свідомого видалення задач система приречена.
Зараз з блокнотом пробую такий підхід: список задач щодня переписую наново. Так застряглі задачі стають нестерпно очевидними. Під час переписування задачу можна зробити чіткіше, простіше, детальніше — а можна просто видалити. Ось ще одна можливість блокнота, яку я не можу уявити в електронній системі.
26.01.2023
Як я робив презентації у Markdown, та як їх рятувати від забуття
В мене на сайті є розділ “Доповіді”, в якому, насправді, відсутні практично всі мої доповіді. Зібрався наповнити його змістом - бо колись мені доводилось робити цілу купу презентацій. Але, поки все зупинилось: розділ був створений для презентацій, створених з бібліотекою remark.js, та його треба перероблювати на більш загальний формат сторінки, щоб влізли презентації в будь-якому форматі. Remark то така бібліотека для написання презентацій у форматі Markdown та відтворення їх у браузері. Як я бачу, підхід цей все ще популярний - в гуглі можна найти десятки схожих інструментів. Але саме Remark.js підтримується погано. І тут стає очевидною найбільша проблема таких бібліотек - презентація у нестандартному форматі вмирає з програмою, що цей формат споживає. (А стандартного Markdown для презентацій, фактично, немає.)
Але розвʼязок є - я знайшов утіліту Decktape, яка за допомогою браузера перетворює презентацію Remark.js (або ще декількох форматів) у гарний стандартний PDF - або у окремі скріншоти слайдів. У найближчому майбутньому сподіваюсь замінити Remark.js на більш звичайний розділ зі слайдами та текстом, або ж переглядачем відео або PDF. Коротше кажучи, моя порада - зберігати всі свої презентації у PDF. Якщо потрібно їх показати в браузері, то є бібліотека pdf.js.
А мій улюблений інструмент для створення презентацій на Markdown - це Deckset. Його б взяв, якщо б мене запросили робити презентацію сьогодні. На відміну від Remark.js та інших бібліотек, у Deckset є вбудований експорт в PDF.
25.01.2023
AWS DynamoDB - база для глобальних додатків
Коротенька оповідь про NoSQL базу даних AWS DynamoDB. В мене вона використовується в продакшені, хоч і іграшковому — в ній зберігаються коментарі до мого блогу (дивіться ось тут.) Для коментарів обрав через те, що на таких обсягах вона безплатна, а також щоб не хостити базу самостійно. Хоча насправді головна її перевага, це те, що DynamoDB практично не має обмежень в масштабуванні, та, обравши її для проєкту, можна ніколи більше не піклуватись про швидкодію.
Уважний читач запитає — не має обмежень в обмін на що? У випадку DynamoDB така величезна перевага забезпечена величезним компромісом — простотою запитів. Замість бази в DynamoDB є таблиця. Записи у таблиці — обʼєкти довільної форми. Тут все як звичайно у NoSQL. Але дістати записи можна або тільки за єдиним атрибутом — ключем розподілення, або ж за діапазоном значень другого атрибута — ключа сортування. Щоб була хоч якась гнучкість, додатково можна створити копії таблиці з тими самими даними, але іншими ключами — вторинні індекси. Причому переіндексація неможлива без перестворення таблиці чи індексу. Тому чим DynamoDB найбільше відрізняється від нормальної бази — тим, що необхідно якнайкраще продумати схему запитів замість схеми даних.
Наприклад, для моєї системи коментарів первинний індекс такий: ключ розподілення - URL сторінки, ключ сортування - ID коментаря (ID коментарів в мене впорядковані за часом). Таким чином я можу вибрати з таблиці всі коментарі для заданої сторінки. Це головне, що потрібно для додатка. Але з такою схемою неможливо знайти коментар за його ID, не знаючи URL. Тому є ще вторинний індекс, у якому ID коментаря — вже ключ розподілення. Якби я хотів сторінку коментарів за автором, то додав би ще індекс за автором.
Зрозуміло, що такий підхід влаштує не кожний додаток. Головне, що треба забути про довільні запити, як до бази SQL. Тож навіть адміністративної панелі на кшталт ActiveAdmin не зробиш — треба всі запити планувати заздалегідь. (Технічно, в DynamoDB ще є можливість фільтрувати результати запитів за довільними критеріями, але це робиться перебором, та коштує так само як нефільтрований запит. До речі, платити доведеться за обсяг прочитаних та записаних рядків.)
Але насправді у DynamoDB великий потенціал, що розкривається через кмітливо розроблену структуру індексів. Якщо хочеться дізнатись більше, раджу цю книжку, в ній такі приклади розбираються, що самому дуже важко було б доперти.
24.01.2023
Чому не варто використовувати UUID та які є альтернативи
Інколи буває, здасться, що чисельні ID тобі не підходять. Тоді руки тягнуться за добре відомими UUID. У PostgreSQL навіть тип для них є - uuid. Але застережу - UUID майже ніколи не будуть найкращим форматом ідентифікаторів, та можуть створити страшенні перешкоди в майбутньому. А міняти формат ідентифікаторів буде непросто.
Зазначу єдиний випадок, коли UUID - правильний вибір: коли ідентифікатор генерується невідомо де, без всякої домовленості, і все ж таки має бути унікальним. Це рішення здебільшого для глобальних стандартів — коли потрібен ідентифікатор, який буде зрозумілий для всіх. Це автоматично значить, що цей ID буде зовнішнім, та хорошим дизайном бази буде додати ще внутрішній, чисельний ID.
Проблеми UUID: він величезний. Якщо взяти поле uuid - то це фактично рядок з 16 байтів. Якщо ж не брати, а зберігати у текстовому полі (а у базі Redshift або навіть MySQL такого типу немає), то це вже 36 символи. Ви це помітите не тільки в базі, але й при будь-якій передачі даних, в URL, і так далі. Також: UUID генеруються не в послідовності. А індекси в базі працюють найкраще саме зі значеннями, що додаються за порядком. В сукупності ці дві особливості гарантують вам повільні запити по полю UUID, особливо якщо по ньому робляться джойни. Як бонус: UUID людьми сприймаються гірше, ніж числа.
Що ж взяти натомість? По-перше, вам вистачить 64-бітного числа, щоб підрахувати будь-що. Далі, є купа різних форматів послідовних ID, які збираються за принципом: відбиток часу + додаткова інформація для забезпечення унікальності. Мені понад усе подобається Snowflake ID. Залишається тільки придумати, як розрізняти машини, що генерують ID - можна, наприклад, по IP.
Якщо вам потрібно приховати послідовність ID (трапляється така вимога), то Snowflake ID це зробить — між послідовними ID будуть мільйони незайнятих.
Якщо треба перетворити ID на рядок, та щоб він був компактніше та не виглядав, як число, то можна закодувати його у base64; так 19 символів перетворяться на 11.
А тепер, як відправити пост собі, але два роки тому?
23.01.2023
Формат iCal генерується простіше простого
Сьогодні знову довелося генерувати графік відключень. Минулого разу я писав, що формат календаря iCal дуже простий, та для його генерації не потрібно ніяких бібліотек. Тепер покажу, як саме. Ось завершений приклад файлу .ics (завантажити):
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
SUMMARY:Велика Подія
DTSTART:20230124
DTEND:20230126
UID:stendap_sogodni.event1
DTSTAMP:20230123T194432Z
END:VEVENT
END:VCALENDAR
Як бачите, його можна створити навіть вручну в текстовому редакторі (власне, так я і зробив.) Формат файлу являє собою перелік — починається та закінчується він рядками BEGIN:VCALENDAR та END:VCALENDAR, а всередині містить блоки подій - BEGIN/END:VEVENT. Звісно, опцій є багато — і посилання, і нагадування, і запрошення, і багато всього іншого. Ось є хороша документація по iCal. А я зазначу головні та необхідні.
Поля SUMMARY, DTSTART та DTEND позначають назву події, а також дати початку та кінця. Тут, думаю, всі знають, що це таке. Дати можуть бути як з часом, так і без.
Поля UID та DTSTAMP цікавіші та служать для редагування подій. UID має бути унікальним ідентифікатором. А DTSTAMP містить дату оновлення події, зазвичай — дату створення файлу. В сукупності завдяки цим двом значенням програма календаря може заміняти події на новіші версії.
22.01.2023
Почав роботу над додатком для швидкого перегляду повідомлень GitHub
В мене робочий день починається з перегляду всіх нових повідомлень GitHub. Таких повідомлень за день накопичується від 25 до 50, тому на весь перегляд уходить до години. З набутою після відпустки ясністю помітив, що велика частка цього часу уходить на навігацію — бо кожний перехід з переліку повідомлень на сторінку пул-реквесту робить повне перезавантаження SPA. При чому частина повідомлень не потребують уваги — наприклад, коли автор зливає PR після того, як я його схвалив. Але все одно доводиться заходити та переглядати, чи не змінилось там що.
Все це можна вирішити з кращим інтерфейсом для списку повідомлень. Моя головна вимога — щоб можна було швидко побачити, що саме змінилося в кожному ПРі після мого останнього перегляду — а потім також швидко прийняти дії. На жаль, нічого подібного не знайшов — хоча буду радий рекомендаціям. Тому вирішив зробити сам.
Поки зміг забрати по API список повідомлень. Концептуальна модель тут заплутана, але головне, що API повертає посилання на відповідний ПР, а також дату останнього перегляду. Тепер треба отримати список подій з ПРу, та обрізати його по даті. Також є API для того, щоб відмітити повідомлення як прочитане — а от чого немає, то відмітки як “зроблене”, щоб прибрати зі списку. Але це не критично.
Як фронтенд обрав Svelte. Мої думки про нього я вже писав. Цього разу ці думки тільки підкріплюються — зі Svelte легше почати працювати над бізнес-логікою, ніж з React. Та й взагалі, виходить, що хоч академічно мені більше подобається React, але для практичної розробки Svelte простіше та приємніше. Принаймні після того, як звикнеш до того, що їх синтаксис, хоча й нагадує JS та HTML, але ж має власні конструкції, які треба знати та помічати - JSX набагато простіше та помітити його легше.
21.01.2023
Налаштування WireGuard на роутері для доступу ззовні
Сьогодні хотів налаштувати на роутері доступ ззовні по WireGuard. Власне, в мене вже такий є, проте працює з домашнього сервера. Оскільки сучасні роутери ASUS підтримують WireGuard, хотілося спростити систему та зробити все прямо на роутері.
Спочатку, я хотів назначити роутеру зовнішній домен. Це роутери ASUS теж вміють робити, вже досить давно. Але для цього потрібний акаунт на одному з переліку сервісів, одні з яких платні, а іншим я не довіряю. Виручило те, що окрім заданих сервісів, можна просто додати свій скрипт, який викликатиметься при зміні зовнішнього IP, а цей скрипт вже буде робити що завгодно. Наприклад, такий скрипт для CloudFlare вже існує. А CloudFlare - з недавніх пір мій улюблений DNS провайдер.
На жаль, після всього цього виявилось, що Київстар все одно не пропускає клієнтів ззовні, тож хоч по IP, хоч по домену, а напряму підключатись не вийде. На щастя, WireGuard цю проблему частково вирішує.
WireGuard - то дуже класний сучасний протокол VPN. Що мені в ньому подобається, це легкість встановлення. А налаштування для клієнтів достатньо компактні, щоб з них можна було зробити QR код — так дуже просто приєднати до свого VPN телефони. Минулого року я навіть зробив пакет скриптів, щоб все це автоматизувати.
А ще WireGuard вміє роумінг, тобто, поєднання декількох серверів у цілу сукупність віртуальних мереж зі спільною маршрутизацією. В мене є два сервери: один — вдома, інший — в інтернеті. Домашній сервер є клієнтом відкритого, та підключається до нього автоматично. Тепер, я можу будь-звідки підʼєднатись до відкритого серверу, та завдяки роумінгу відправляти запити не тільки до домашнього сервера WireGuard, але й взагалі до всіх домашніх систем.
Найскладніше в налаштуваннях WireGuard то побудова правильної таблиці маршрутів iptables. Схема маршрутів залежить від того, що має робити система. Типові сучасні VPN дають клієнтам вихід в інтернет, тобто клієнти направлятимуть всі пакети до інтернету у канал VPN, а VPN передаватимете їх далі. Але мені для організації доступу до домашньої мережі зовсім таке не потрібно. Треба чітко розуміти, які пакети мають бути пропущені, які — перенаправлені, і так далі. Раджу гарний репозиторій з купою статей.

