Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS · 📢 Канал в Telegram @stendap_sogodni
21.06.2024
Колір та фарби
Щільно зайнявся ремонтом, тому не залишається часу ані на роботу, ані на проєкти. Втім, цікавим для мене відкриттям була фізична фарба. Бо веде вона себе зовсім не так, як на екрані.
Я, звісно, все життя стикаюся з кольором: цифровим. Система RGB - найпряміший опис кольору на екрані — перекладається прямо на інтенсивність пікселів. Система HSL - не така пряма, зате як легко з нею коригувати та поєднувати кольори. Навіть з друком все зрозуміло: там система CMYK.
Але фарба себе поводить зовсім інакше; на відміну від пікселів на екрані та крапок в принтері, фарба не є дискретною, а натомість наповнена часточками пігментів. Неможливо “надрукувати пігмент правильного кольору”, тому навіть з цифровими машинами для змішування ми все одно обмежені фізичними властивостями вхідних пігментів.
Ну, тобто звісно, теоретично ми можемо намішати нескінченно багато комбінацій. Але щоб робити це повторювано, доведеться покластись на ті тисячі кольорів, які закладені в можливості машини. В тому й лежить вся складність: фарбу не можна просто обрати за палітрою з 16 мільйонів кольорів.
Замість того доводиться брати віяло зразків… Що мене перед усім дратує у віялі — то обмеженість рухів (порівняно з RGB, де я легко знаю, як додати, наприклад червоного.) Тут допомагає знання системи NCS, в якій кольори вписані в трикутник “чорний — білий — відтінок”. Звісно, можна конвертувати RGB в NCS, але далеко не всі кольори будуть дійсно збігатися.
20.06.2024
Стилі для Obsidian Canvas - реалізація
Ось перша версія стилів для канви. Не знаю, наскільки вони універсальні, бо мені більше подобається ідея стилів для індивідуальних потреб — в кого як голова працює.
Що в мене: по-перше, обовʼязково треба бачити, які вузли потребують додаткового опрацювання. Це задачі (червоним), питання (жовтим) та ідеї (синім). Далі, відзначаю закінчені (зеленим), скасовані (сірим), та заблоковані (крижано-блакитним) вузли, щоб не звертати увагу на них. Тип та стан можна поєднувати: заблоковане питання. Нарешті, для кращої організації додав великі та дуже великі вузли; вони грають роль заголовків.
Про технічну реалізацію. В Obsidian потужна система змінних CSS. Через неї, в сукупності з сучасними функціями CSS як calc та color-mix, можна вийти на власний набір кольорів. Масштабування вузлів зробив через атрибут zoom; так вони зберігають внутрішню структуру.
До речі, всі ці стилі можна додавати не тільки до текстових вузлів, а й до будь-яких — малюнків, вебсторінок тощо. Сторінки на канві я не люблю, бо це виходить повільно, до того ж більше хотілося б додавати вирізки, а не весь зміст. А малюнки навпаки, революційно зручно. Почав розуміти, чому Obsidian Sync надає 40 Гб місця — для тексту точно занадто.
Весь пакет можна забрати тут, але зручності поки на альфа-рівні. Пізніше, теоретично можна навіть написати скрипт, який зробить все повністю автоматично, оскільки всі налаштування — це зміст файлів JSON, не більше.
19.06.2024
Семантичні графи в Obsidian Canvas
У форматі JSON Canvas мене відразу привабило те, що у вузлів та ребер можуть зʼявлятися власні атрибути; таким чином, канва набуває не тільки вигляду, а й змісту, тобто стає семантичною.
Наприклад, якщо порівняти моє виконання схеми BRIDGeS (див. малюнок вище) в Obsidian та офіційне в Figma, то в останньому схема має суто візуальний характер: це вузли різного кольору та приліплені до них візуально відмітки пріоритетів. А в Obsidian кожен тип вузла та кожен пріоритет стає атрибутом.
Мені зараз для планування потрібне рішення, щоб було помітно, де задача, де питання, де ідея, а де просто факт. Поки що просто придумав фарбувати активні задачі червоним, а виконані — зеленим (це єдина вбудована можливість оформлення, якщо не рахувати Markdown). Але хочу зробити власні атрибути, та за допомогою Obsidian Canvas Style Menu їх оформити.
Це стане корисним для автоматичної обробки. Наприклад, скрипт може знайти в канві всі задачі, та зробити список за пріоритетом. Також, звісно, оформлення допомагає розрізняти вузли, причому можна навіть комбінувати класи: на ілюстрації зверху дуже просте поєднання типу (за кольором) та пріоритету (міткою); але можна робити навіть на кшталт “якщо це задача та вона виконана, показати галочку.”
18.06.2024
Труднощі статичного хостингу
Статичний хостинг (тобто такий, що вміє тільки віддавати файли) - ніби найпростіша річ, абсолютний commodity. Втім, обрати між ними не так легко, як здається. Все залежить від того, які у вас очікування. Але ось в чому нюанс: як тільки скористуєшся одним статичним хостингом, то очікування поведінки фіксуються, та під час переїзду доведеться з ними рахуватися (або дізнатися, що сайт працює не до кінця, тільки пізніше.)
Нюанси починаються з правил перенаправлення. Будь-який сайт стикається рано чи пізно зі зміною адрес. Будь-який чемний сайт підтримуватиме старі адреси через механізм перенаправлень. Він всюди налаштовується за власними правилами — ось, наприклад, Vercel. А ось Cloudflare Pages. Все так, та не зовсім. Доведеться вручну коригувати та перевіряти. Коли перенаправлень сотні (так трапляється після реструктуризації сайту) - це вже ціла пригода.
Деякі хостинги підтримують адреси без слеша на кінці, а інші — ні. Технічно, ніби присутність слеша “правильніша”, оскільки ми віддаємо index.html
для директорії — а не файл без розширення. Але те, що адреса сторінки виглядає як директорія, це принаймні дивно. Раніше мене це обурювало, зараз вже змирився та зробив все зі слешами (Звісно, через перенаправлення.) Також не всі хостинги готові взагалі показати index.html
(бо це вже не просто “віддавати файли”, авжеж?)
Характер відвантаження файлів на хостинг теж відрізняється. Ось на Vercel примусово потрібно мати репозиторій на GitHub. Що гарно, поки в тебе немає величезних світлин або взагалі — завантажень на гігабайти. На Cloudflare Pages можна відвантажити на пряму, але не можна замінити єдиний файл — тільки все разом. На AWS S3 можна просто оновити окремі файли.
Нарешті, хоч і здається, що статичний хостинг — найшвидше, що може бути в вебі, насправді провайдери, особливо безплатні, не гарантують швидкості. В мене Ahrefs не раз скаржився на повільні сторінки на Vercel. А найшвидше сайт працював на власному сервері — але ж то незрівнянно складніше в підтримці. А ще, на власному сервері буде максимальна кількість особливих умов, та з нього найскладніше буде зʼїхати.
Хотілося закінчити на рекомендації конкретного хостингу, але її в мене немає. Хіба можу порадити не вигадувати власні обмеження (як я зі слешами), а триматися ближче до базової парадигми “сторінка = файл”.
17.06.2024
Miniflux: персональний агрегатор RSS
📢 Останній раз я згадував про Miniflux ще два роки тому. Відтоді та й досі він залишається моїм агрегатором стрічок RSS. Останнім часом їх стало тільки більше: особисті блоги знову набувають популярності.
Miniflux - чудовий застосунок для власного хостингу. Він написаний на Go, тож просто розгортується та потребує мінімум ресурсів. Єдине, що наразі Miniflux працює тільки з PostgreSQL, тож доведеться розгорнути також її. (До речі, Fly.io вміє це робити під ключ.
Неочевидним потужним інструментом в Miniflux є правила переписування. Це готові рішення для типових недоліків RSS: наприклад, він вміє робити підписи зображень видимими, підставляти відеопрогравач, та перетворювати зміст постів. А може взагалі, звернутись до оригінальної сторінки, та отримати з неї зміст: це вже правила скрейпера. Ну та й зрозуміло, що можна фільтрувати зміст стрічки — прибирати нецікаві категорії та інше.
Все це виводить агрегацію RSS на якісно інший рівень. Хоча потреба в RSSHub залишається — наприклад, щоб забирати стрічки з Twitter та Telegram.
Один неприємний момент: за замовчуванням в Miniflux надто лінивий графік повторної перевірки стрічок після помилки: тимчасові помилки швидко стають постійними. Щоб те виправити, можна змінити POLLING_PARSING_ERROR_LIMIT=0
та стрічки будуть перевірятися нескінченно. Все одно не так легко помітити, що конкретна стрічка має помилку — особливо якщо читати Miniflux через програму-клієнта, а не напряму.
16.06.2024
Айсберг технічного боргу
Нещодавно використав цю фразу, та хотілося зупинитися детальніше. Технічний борг не просто сидить та чекає, поки ви за нього візьметеся. В будь-якому проєкті є багато рівнів технічного боргу — від нешкідливого до такого, що змусить вас виправляти продакшн вночі на вихідних.
(Під технічним боргом я розумію все, де виконання розбігається з очікуваними стандартами. Так, це коли не встигли рефакторити код. Але ще й коли поміняли підходи, але частина коду залишилась зі старими. Або не коду, а структури бази даних. Або ще гірше, інфраструктури — її не так швидко змінити. Або CI займав десять хвилин пів року тому, а тепер триває двадцять. Або застаріла версія фреймворку.)
Винищити технічний борг — неможливо. Тому важливо 1) про нього памʼятати та 2) мати розуміння про пріоритети. Це один з обовʼязків головного інженера. Ще один обовʼязок: стежити за сигналами та впроваджувати зміни в доцільний час. Наприклад, не дати CI уповільнюватися надалі. Або оновити бази в “повільний сезон”.
Що б не було, але рішення про виправлення технічного боргу ніколи не прийде від менеджменту. Це суто задача інженерів. Менеджмент може тільки спитати: чому тут повільно / багато помилок / робота гальмує? Але то вже поганий знак: айсберг загрожує кораблю. Краще, щоб інженери помітили потребу раніше; але мали глузд не виправляти кожну дрібницю.
15.06.2024
Балконні сонячні панелі — досвід
🔆 Чули про балконну сонячну систему від EcoFlow? Я чув, та мене спокусило. Ось власний досвід (пишу, поки немає світла 🕯️.) Мій рівень в електриці — зʼєднувати розʼєми та клеми, тож я орієнтуюся на більш-менш готові системи — впевнений, що з більшим хистом можна побудувати щось дешевше та при тому спеціалізоване.
🧶 Перше, що спокусило — це гнучкі панелі. Та ще й легкі. Я придбав комплект з двох панелей по 200 Вт. Одна панель має розміри квадрата стороною метр з гаком та вагу 4.5 кг. Таку вагу досить легко закріпити: навіть на спеціальний дюбель в пінопласт, або на монтажний клей. Або взагалі поставити на карниз, чи зачепити мотузкою за віконний профіль (це стане важливо нижче.)
🔌 Панелі підʼєднуються до павербанка EcoFlow кабелем, який потрібно придбати окремо; сам розʼєм стандартний, на станції Anker є такий самий. Щоб заряджати павербанк від панелі, більше нічого не потрібно. Тому така сонячна панель — гарний, повністю автономний спосіб підзарядити батарею — аби було сонце. Пристрій, що називається інвертором, потрібний тільки для підключення панелі до електромережі, в чому я сенсу не бачу, про що далі.
⚡ Тепер, яку потужність здатна видати вертикальна сонячна панель? На моєму південному боці у червні я побачив від 40 Вт вранці до 90 Вт вдень з теоретичних 200. Зазначу що потужність суттєво змінюється від невеликих змін кута нахилу; коли панель на 3 градуси нахилилась донизу, генерація впала на 20%!
💸 Але… як їх не крути, дві панелі згенерують не більше 1.5 кВт*год на день, і це за щедрою оцінкою. Тобто для не тільки для автономного живлення не вистачить, а й економії електроенергії вийде лише 200 грн на місяць — з новими тарифами.
🌞 Висновок мого експерименту: купувати мікроінвертор та монтувати панелі на постійне місце сенсу немає, але я радий мати їх як незалежний резерв (тому й важливо мати можливість легко їх повісити та зняти). Взагалі, це маленьке диво — бачити, як в павербанк тече енергія просто з сонця!
14.06.2024
Організація робочих справ
Мені чомусь набагато складніше було підійти до збору та обробки робочих задач, аніж особистих.
З першого погляду, робочих не так багато: те, що є задачами на спринт, фактично перетворюється у два проєкти за GTD, а то й один. Наступні дії для них не так вже й складно визначити, про що я вже писав.
Але окрім явно запланованих задач ще є безліч того, що я тримаю в голові. Це й айсберг технічних боргів, і кладовище застарілих підходів, і тулчейни, які завжди розладжуються.
Намагаюся все це зібрати до купи та більше робити планування. Бо була нещодавно зустріч для визначення наступних планів, та прикро стало, що я можу згадати тільки декілька пунктів, які на слуху. Навіть коли решта була десь в нотатках чи листуванні.
А зараз намагаюся звести все в одну велику канву, організовувати та проробляти. Так відразу видно, де багато задач. Наприклад, виявив чимало пунктів про покращення адмінки. Дійсно, дрібне виправлення не має важливості, то й висить. А от коли бачиш, що вже виріс конкретний список задач — то можна навіть в спринт ставити.
Раніше пробував записувати всі ідеї в Jira. Це в мене працює погано. Незручно переглядати скупчення задач, встановлювати звʼязки, поєднувати чи ділити задачі. А коли там сидить просто необдуманий “список ідей”, то взагалі неясно, що з ним робити. Береш на грумінг — навіть складно згадати, що вони значать. В Jira зручно мати задачі, які вже набули конкретики.
13.06.2024
Генерація Obsidian Canvas з тексту
В Obsidian Canvas бракує можливості перетворити список задач у вузли канви. Проте канва — це просто документ JSON з простою схемою. Взявся згенерувати.
Взагалі сама генерація не ставить проблем. ID для вузла може бути будь-яким рядком, унікальним в межах канви; UUID цілком влаштовує. З розміром вузлів доведеться вгадати; хоча розумніший алгоритм можливо дивився б на довжину рядка. Можна було б зробити обробку вкладених списків, якщо розбирати Markdown, а також звʼязувати вузли між собою.
Мені поки було потрібно тільки перетворити простий список у вузли, тому й скрипт вийшов дуже простий.
А далі стало дурне питання: як його додати в Obsidian? Дурне, бо звісно ж, файл можна просто скопіювати чи навіть перетягнути у вікно Obsidian. Але мені не стільки потрібний файл, скільки ці ж вузли на канві, що вже існує. В ідеалі, скопіювати їх в буфер та вставити, куди потрібно. Спробував звичайним pbcopy - нічого не вийшло; код JSON додається текстом. При цьому в самому Obsidian можна копіювати та вставляти з канви, тож що не так?
Знайшов у XCode Additional Tools утиліту Clipboard Viewer. Вона показала, що Obsidian копіює дані у “внутрішньому форматі”, а саме org.chromium.web-custom-data
. :) Всередині з HEX-перегляду очевидно сидить той самий JSON, але як його прочитати? А ще, як записати? З вихідного коду Chromium знайшов, що дані закодовані в формат Pickle (не той самий, що в Python.) Формат простецький, за допомогою ImHex запрототипував читач.
Далі — як його записати в буфер обміну? Не те щоб хотів знову про Swift, але на macOS легше за все це зробити з оточення Apple функцією Pasteboard.setData(forType:). Але як у Swift зібрати той бінарний формат? Знайшов за рекомендацією клас ByteBuffer з офіційної бібліотеки для серверної розробки Swift NIO.
Довелося ще згадати про те, що система в мене big-endian, а формат цей little-endian… але зрештою все запрацювало та результат успішно вставився в канву! Таке рішення могло б допомогти в інших випадках, коли застосунки на Electron/Chromium копіюють у внутрішньому форматі… є ідеї?
12.06.2024
Кооперативна рівночасність
З цього відео зрозумів фундаментально важливий аспект рівночасності у Swift.
Рівночасність з Grand Central Dispatch була витискальною. Це стандартна модель рівночасності, де операційна система планує потоки та перемикає виконання як їй зручно. На ній побудовані всі сучасні ОС, та рівночасні аспекти більшості мов є абстракцією над потоками операційної системи.
Витискальна рівночасність чудово працює, поки потоків не так багато, та вони незалежні один від одного. Втім, з приходом рівночасного програмування в маси зʼявилися нові потреби. Що, якщо ми хочемо завантажити 1000 файлів, та в кожного з них буде рівночасний обробник? Робити 1000 потоків? Всі, хто так робив, швидко дізнаються, що у кількості потоків є технічні обмеження, та варто користуватися пулом, щоб на 1000 задач було лише декілька потоків (дехто каже, стільки, скільки ядер в процесора.)
Але пул потоків — то суто технічна необхідність, ускладнення програми. Тому деякі мови програмування вносять пул потоків у власну платформу та надають нам абстракції вищого рівня — це називається кооперативна рівночасність. Кооперативною, бо планувальник тепер знаходиться на рівні мови, та здатний перемикати задачі згідно з мовними конструкціями. Наприклад, з гарантією, що перемикання не відбудеться посередині синхронного коду. Або, що актор ніколи не матиме дві паралельні задачі.
От як раз у Swift async/await це механізм кооперативної рівночасності. Всі задачі з async/await
виконуються на пулі потоків, та перемикання між ними відбувається лише там, де є ключове слово await
. Ба більше, перехід async/await мало відрізняється від звичайного виклику функції — тільки тим, що стек замінюється новим. Та якщо синхронізація готова відбутися в момент виклику — то виконання просто продовжиться, без жодних пауз.
Це дуже крута та сучасна система. Сходу не знаю інших мов, де async/await
може прямо передавати контроль (пишіть, якщо знаєте.) Наприклад, в JavaScript кожний await
повертає нас у цикл подій; в Golang синхронізація через канали ніби завжди блокує одну сторону, бо це не виклик функції; в Ruby з ракторами так само.