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

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

Підписатись на RSS · 📢 Канал в Telegram @stendap_sogodni

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 з ракторами так само.


11.06.2024

Ізоляція даних у Swift

Зміни у Swift 6 дійсно доторкнулись саме рівночасності. Якщо коротко, то гарантії ізоляції тепер будуть примусово встановлені ще компілятором.

Кожне значення в програмі отримує домен ізоляції. Це або конкретний актор, або глобальний актор, або неізольованість. Важливо, що неізольовані значення не значить вільні для використання; як тільки ми вступаємо в домен актору, то втрачаємо прямий доступ до неізольованого (часто спадкового) коду — доступ залишається тільки через await.

Особливо цікаво, в новому SwiftUI всі компоненти автоматично належать @MainActor. (MainActor - це абстракція для коду, який виконується на головному потоці; але не всього коду, а який добровільно входить в модель акторів.) Це значить, що в типовому застосунку SwiftUI ми не можемо більше ігнорувати питання ізоляції, що дуже добре.

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

Тому нам і потрібні додаткові актори, щоб прибрати повільні обчислення з головного потоку до підсистем — наприклад, завантаження з інтернету, чи перекодування GIF у MP4, як я зараз роблю. Приємно, що компілятор Swift 6 буде автоматично гарантувати ізоляцію таких модулів, та нам достатньо буде виправити помилки. Зазначу, що поки не весь SDK готовий до такої радикальної перевірки всюди. А тому я поки не можу у власних проєктах досягти чистоти ізоляції. Втім, до офіційного виходу Swift 6 ще місяці три.


10.06.2024

Модель рівночасності у Swift

🐇🐢 Рівночасність — це не тільки для серверних застосунків з тисячами паралельних запитів. В розробці застосунків з GUI рівночасність теж має критичну важливість; якщо все робити в одному потоці, довготривалі задачі будуть помітно гальмувати інтерфейс. Тому у Swift нікуди не дітися без розуміння моделі рівночасності, яка тут ускладнена історичною спадщиною та шарами переосмислювань. Сьогодні як раз починається WWDC, де обіцяють ще нововведення, тому саме час розібратися з тим, що є.

📨 Попри те, що, як і всюди, у Swift є потоки, в коді застосунків використовують не їх, а модель задач — фрагментів синхронного коду, який виконується асинхронно на чергах. Черги є послідовні або паралельні; з різними пріоритетами, замками та семафорами тощо. Ця система планування називається Grand Central Dispatch та існує ще з 2009 року, тобто ще до Swift. Як і з запитами HTTP, логіка виконання задач перекладається на операційну систему. Одна з черг є “головною” та обслуговує UI; от з неї ми й хочемо прибирати важку роботу.

🚦 Проблемою є питання власності та спільного доступу; код з різних черг повинен синхронізувати доступи до даних. Найпопулярнішим способом того є перенесення коду на іншу чергу, наприклад на головну: DispatchQueue.main.async { ... }. Але в цілому керування доступом потребувало уважної перевірки вручну.

🎭 Щоб спростити життя, ввели модель акторів — це сучасне бачення рівночасності у Swift. Актори мають ізольований стан, тобто до нього можна звертатись тільки через async/await, та такі звернення будуть послідовними, тобто можна бути впевненим у цілісності даних.

🍱 Сенс існування актора: ми відокремлюємо частину коду (та його дані) за обмеженим інтерфейсом та кажемо: “Цей код ізольований від іншого коду та його можна виконувати паралельно з іншим.” Коли навіть в айфоні вже є 6 ядер, це важлива відзнака. Ось така незвична мені, “декларативна” модель рівночасності є у Swift.


09.06.2024

Я роблю замало планування

💹 Раніше в моїй уяві “планування” значило або стратегічне на кшталт “чого я (чи ми) хочемо досягнути цього року”, або процедурне “розбити розвʼязок на кроки”. Останнім часом зрозумів, що чого дійсно не вистачає — це тактичного планування з метою зрозуміти “що це значить та з чого складається”, а потім вже “що робити”. Причому так розглядати можна будь-які справи, навіть малі — якщо вони викликають роздуми, а не чіткий поклик до дії. Навіть навпаки, малі справи з невизначеністю здатні вбити весь ентузіазм.

🎨 Зараз я беру Obsidian Canvas. Починаю з постановки задачі. А далі скидаю на канву думки, з яких поступово вимальовується картина задачі та зрештою наступні дії. Те саме можна робити на папері, або навіть в текстовому редакторі. Корисно забарвлювати вузли різними стилями: твердження, знання, питання, висновки, дії.

➡️ Потім, коли зробив достатньо планування, виписую декілька наступних дій. Нічого дивного в тому, що вони дуже відрізняються від “очевидних” дій, які я записував раніше. Як один приклад: з мети “худнути” виплив проєкт “навчитися привабливо подавати страви”… 🍱

🏃‍♂️ Якщо невизначену задачу відразу почати з постановки кроків, то, по-перше, зі всією ймовірністю ми оберемо щось наївне та позбавлене змісту, що потім тільки демотивує як робити, так і планувати надалі.

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


08.06.2024

Наступні дії в GTD

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

Отже, що є “наступною дією”? GTD відрізняється від “просто списку задач” тим, що кожна задача обовʼязково є наступною, тобто не потребує підготовки, та не є проєктом, тобто може бути закінчена за один підхід. Вся магія GTD зовсім не в тому, щоб мати “список проєктів” чи розбирати вхідні за схемкою, а в тому щоб для кожного бажаного результату визначитись зі справжньою наступною дією.

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

Але щоб “запрограмувати фічу” стало наступною дією, вона повинна не мати передумов. З цим в програмуванні теж не все легко, бо під час здається, що все ясно, поки не сядеш за роботу. Тут допоможе план реалізації, тобто попередня дія — розробити план реалізації. Або принаймні я б намагався зʼясувати, як та робота почнеться — тобто не написати код фічі Х, а зробити функцію А в модулі Б… якщо і такої ясності немає, то планування зроблено замало.

В тому і є GTD: не просто взяти з вхідних “фіча Х”, створити проєкт “фіча Х” та наступну дію “написати код фічі Х” з контекстом “@компʼютер” - тобто зробити всі рухи системи, але без жодного змісту — а свідомо провести достатньо планування — по всіх своїх проєктах — щоб коли справа дійшла до дій, то в тебе був детальний перелік наступних дій, де вже не потрібно зупинятись над кожним пунктом та думати, що воно значить. Бо парадигма GTD - це “думати кожну думку один раз”… а не щоразу, як дивишся список задач.


07.06.2024

Обережно, Query-Driven Design

Коли шукаєш потужну базу даних, можна натрапити на категорію баз, які обіцяють надзвичайну здатність до масштабування (це ж круто!) з майже незмінною швидкістю запиту (база мрій!) Прикладом будуть Cassandra, DynamoDB, ScyllaDB тощо.

Втім, при пропозиції необмеженого масштабування, варто придивитись, чи використовує база модель “Query-Driven Design / Modelling”, тобто “проєктування згідно з запитами”. За цим безневинним висловом криється небезпечна для проєкту особливість. А саме: Query-Driven Design значить, що всі запити до бази потрібно продумати наперед. Фактично це екстремальна форма оптимізації на читання: якщо коротко, то, дані в таких базах розташовуються так, щоб їх було швидко прочитати, навіть коли база сягає тисячі вузлів.

QDD-бази не є поганими! Вони дійсно надають неперевершену здатність до масштабування. Тому їх використовують компанії, яким потрібні дійсно глобальні обсяги даних. Наприклад, на DynamoDB побудована крамниця Amazon.

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

…Краще, як завжди, почати з PostgreSQL, а переходити на Cassandra коли проєкт того буде потребувати.


06.06.2024

Obsidian Canvas - ідеальне візуальне доповнення для бази знань

Вже півтора року в Obsidian є вбудована “біла дошка”, тобто умовний FigJam (тільки, звісно, на одну персону) - Canvas. Це нескінченна канва, на яку можна викладати картки — текст, ілюстрації, навіть сторінки з вебу. Такий інструмент чудово доповнює і без нього потужний Obsidian, бо надає можливість робити візуальне планування, малювати діаграми, мудборди й так далі.

Хоч, звісно, канва — це вже не текстовий документ в прямому сенсі, але він зберігається у JSON, та у того JSON є відкритий стандарт. Це значить, що ти можеш легко експортувати дані або робити перетворення. Я довгий час не дивився на Canvas, бо мені здавалося, що кожна картка повинна бути окремим документом — але це абсолютно не так. Сама канва здатна містити стільки інформації, скільки буде потрібно. Включаючи картки з повною підтримкою Markdown.

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

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

Canvas є розширюваним. На жаль, наразі це тільки незадокументовані можливості, але, вже є декілька доповнень, які додають особливі стилі для вузлів. З них хочу виділити Obsidian Canvas Style Menu, який служить точкою розширення для твого CSS. Так можна легко назбирати набір стилів для власних потреб. (Як і весь Obsidian, Canvas побудований на вебтехнологіях, та всі можливості CSS до наших послуг.) Стилі, що були накладені доповненням Canvas Style Menu, стають особливими атрибутами у JSON канви; їх легко прочитати та записати.

Як Canvas, так і доповнення до нього синхронізуються та доступні на телефоні. (До речі, в Obsidian цікава модель синхронізації налаштувань: всі вони належать до поточного схрону нотаток, та якщо придивитись, сидять там у вигляді… звичайних файлів.)

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