Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
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 передаватимете їх далі. Але мені для організації доступу до домашньої мережі зовсім таке не потрібно. Треба чітко розуміти, які пакети мають бути пропущені, які — перенаправлені, і так далі. Раджу гарний репозиторій з купою статей.
20.01.2023
Як я колись шаблонізував документи Word
Згадали на роботі мову шаблонів Handlebars. Я її дуже люблю, як просту мову для шаблонів, що редагуються користувачами. Хоч ця мова за мірками інтернету стародавня — ще з 2010 року — вона залишається актуальною. Але спогади про Handlebars нагадали мені іншу цікаву історію, як колись довелось генерувати шаблоном документи Microsoft Word.
Задача була доволі проста за змістом. Треба було скласти звіт за зразком, але заповнити даними користувача. Таке зазвичай роблять з HTML, а потім, можливо, перетворюють на PDF, але тут вимога була отримати звіт у форматі DOCX. Було це років десять дому, тож може вже зʼявились рішення простіше. А на той час гарного способу зробити DOCX з HTML або PDF я не знайшов. Часто-густо якщо такий конвертор і знаходиться, то він псує форматування та підходить тільки для внутрішнього використання.
Але ж корисно знати, що формат документів DOCX являє собою XML-документ, запакований в архів ZIP. Це вже обіцяє хоч якусь можливість автоматичного перетворення. Та дійсно, перша спроба розвʼязку була така: взяли зразок та спробували зробити з нього шаблон за допомогою ERB або ще чогось. Але документ DOCX містить набагато більше, ніж ми бачимо на екрані, та прочитати та зрозуміти його вихідний код — це зовсім не те що редагувати звичні шаблони вебсайтів. Тож “простий” шаблон видався незграбним та складним у редагуванні — бо кожна зміна форматування зразка практично тягнула за собою створення шаблону наново.
Тоді прийшла інша ідея шаблонування. Якщо зразок документа відкрити у Ворді, та залишити в ньому текстовий маркер, наприклад: {{NAME}}
, а потім цей документ відкрити вже у Ruby, то знайти цей маркер за допомогою Nokogiri буде просто. Та не тільки знайти, а й замінити на інший текст. При цьому заміна отримає форматування, що було прикладене до маркера. Тож наш зразок став шаблоном — зберігаючи можливість його відредагувати. Чудово!
На заміні маркерів робота не закінчилась. Вдалося навіть впровадити такі неодмінні функції шаблонування, як умовні блоки та блоки-цикли. Для цього спрацювали ті ж самі маркери. Але тепер ми знаходили пару маркерів, забирали XML-фрагмент, що знаходиться між ними, та опрацьовували. Єдиний нюанс, що маркери мали знаходитись на одному рівні у дереві XML, але це нескладно було влаштувати вручну. Головне, що при виявленні проблем було достатньо видалити маркери з документа та спробувати знову.
В тестуванні це працювало як потрібно, а у продакшн хитре рішення так і не потрапило.
19.01.2023
Проблеми робочих дзвінків — мабуть, такі, як в усіх
Після відпустки помітив, що з усіх аспектів роботи найменш приємним є дзвінки. Хоч вони в нас по ділу та не скажеш, що зайві. Тому вирішив розібратись в собі.
По-перше, кого як, а мене робочі дзвінки дуже виснажують. Навіть якщо не доводиться брати активну участь, все одно, дві години дзвінків — і вже треба психічно відпочивати. До того ж під час дзвінку рідко можливо займатись чимось іншим — ментального ресурсу не вистачає. Хоча деколи дзвінок випадає на момент глибокого занурення в потік програмування, і тоді навпаки, важко відірватись та звернути увагу. А що приємно робити під час дзвінку, то це гуляти. Якщо якість звʼязку дозволяє, та не треба дивитись на екран, то прогулянка та дзвінок — ідеальна комбінація. (А ще залишився спогад з однієї з перших робот, коли ми пішли планувати великий проєкт у зеленому сквері.)
По-друге, все ж таки є питання, обговорення яких на дзвінку є марнуванням часу. В ідеалі, питання мають бути пропорційними кількості присутніх людей (та відповідно, вартості хвилини дзвінку!) Втім, деколи ми натрапляємо на дрібні подробиці, які ж таки є частиною великого цілого, тому без вирішення всіх деталей розмова здається незавершеною. Тоді дзвінок скочується до так званого bike shedding, що ще більше виснажує. Мені здається, що такий момент треба вміти помітити та не боятись переносити кінець обговорення у текстовий чат.
І нарешті, буває й таке, що відчуваю себе зайвим на дзвінку. Або ж буває що присутній тільки на всяк випадок, якщо виникне необхідність. На жаль, відмова від участі у дзвінку виглядає хоча б трохи, але неввічливо. Хоча насправді навпаки, якщо є привід, то уникнути або скоротити дзвінок — це знак поваги до спільного часу. Але робочий етикет в цьому питанні якось недороблений.
Буде що розказати на наступній ретроспективі.
18.01.2023
Рамки, в які нас заганяє Ruby on Rails
Я дуже люблю Ruby on Rails - так, що хоч вже десять років намагаюсь їх здихатись, та ніяк не виходить. Картинка зверху мене трохи зачепила, бо, на мою думку, впевнений вибір — це добре, але досвідчений розробник має знати свої обмеження, та як вони впливають на архітектуру. Тож, не скасовуючи цей мем, все ж таки розгляну питання — в які архітектурні рамки ставить нас Ruby on Rails?
Ну, якщо вже заговорили, то Rails вимагає реляційної бази. Бо ActiveRecord, хоч і чудова технологія, але завʼязана саме на RDBMS - і звісно, саме PostgreSQL буде першим вибором такої. Адаптери для інших баз є другосортними та втрачають найбільш приємні аспекти Rails. Але при цьому Рельси використовують саму базу вкрай обмежено, та купа можливостей — таких як вбудовані функції, складні перевірки цілісності та інше — залишаються проігнорованими. Помилки цілісності — звичне явище для розробника на Ruby on Rails, бо замість перевірок в базі вони робляться на рівні додатка. Виходить технологія в парадигмі “тупо, але дієво” - справжній нащадок PHP.
Далі, Rails була, є та буде дорогою технологією в плані хостингу. Навіть Heroku припинили надавати безплатний хостинг для Ruby on Rails. Хоча головною статтею витрат буде не додаток а… база. Бо хостинг для RDBMS теж не може бути простим та дешевим. Тож як для молодих проєктів, що робляться “з кишені”, так і для гігантів індустрії, вибір Ruby on Rails - обовʼязково також і фінансовий.
Крім того, цей стек відразу анулює можливість мати локальну копію даних. Бо навряд чи у клієнтів на телефоні буде Postgres. А з іншого боку — можливість скористатись безмежним масштабуванням хмарних баз, таких, як Firebase або DynamoDB. Масштабування можна залишити на майбутнє, а ось синхронізація та робота офлайн здатні піднести додаток на абсолютно новий рівень. Хоча, звісно, не кожен додаток такого потребує.
Ніша, де Rails, а з ними й Postgres - це найкращий вибір — нікуди не зникне. Тож, як і розробники на COBOL, знавці цих технологій завжди знайдуть собі роботу. В цьому плані я згоден з вище приведеним мемом.