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

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

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

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 цікава модель синхронізації налаштувань: всі вони належать до поточного схрону нотаток, та якщо придивитись, сидять там у вигляді… звичайних файлів.)

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


05.06.2024

Профілювання у Swift та оптимізація запитів

Сьогодні вперше профілював застосунок на Swift, щоб його пришвидшити. Проблема наступна: список тегів при перемиканні на режим “сортувати за частотою” помітно гальмував. Вдалося знайти причину та оптимізувати.

В XCode найбільш дружній профайлер з всіх, що я бачив; він не тільки показує профіль, а ще й виділяє підвисання UI та відразу знаходить найважчий виклик. (Хоча планка дружності у профайлерів наднизька: навіть просто графічний інтерфейс є тільки для JavaScript в браузері.)

В чому виявилася біда. У SwiftData, щоб підрахувати кількість обʼєктів у асоціації, їх потрібно повністю завантажити та ініціалізувати. А значить, для мого списку за частотою фактично завантажувалась вся база, та ще й антипатерном N+1, та ще й, здається, не один раз, бо це відбувалося всередині алгоритму сортування.

Проблема загальна, зате рішення, до якого я звик в SQL, немає. А саме, жодних COUNT ... GROUP BY. Або взагалі способу обходити граф обʼєктів, окрім як прямий пошук, або асоціації. Вихід, який я знайшов, простий — зберігати кількість в окремому атрибуті (так званий кеш кількості.) Тепер можна взагалі з бази діставати теги, впорядковані за частотою.

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

Висновок: виходить, у SwiftData/CoreData більше логіки перекладається на шар застосунку. Це відрізняється від звичного для вебу підходу, де база є потужнішою та відповідальнішою. Втім, і контекст застосунку на одного користувача з локальною базою суттєво відрізняється від рівночасного багатокористувацького вебу.


04.06.2024

Як я живу з <10 вкладок браузера

Хоч я розумію людей, в яких завжди в браузері безліч вкладок — та ще й через те бракує памʼяті (оперативної! або..?) - але сам все життя обмежуюсь мінімальною кількістю. Тобто від жодної до, може, двадцяти, якщо щось активно шукаю — але завжди намагаюся всі їх закрити.

Оскільки, на мою думку, безліч вкладок має обʼєктивні (витрати памʼяті) та субʼєктивні (це рудиментарна та неефективна система збереження контексту) недоліки, хочу поділитися тим, куди в мене ті вкладки зникають.

На мою скромну думку, безліч вкладок — це виліковне, та від неї варто звільнятися. А у тебе чому стільки вкладок?


03.06.2024

Тести на покриття коду (особливо на Ruby)

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

…Я погоджуюсь, що покриття як абсолютна ціль — безглузда. Воно не підтверджує вірності коду. Але в інтерпретованій мові, фактично, поки не запустиш код, не знаєш, що він працює. В цьому і є сенс покриття — підтвердити, що код взагалі працює, що параметри вірні, і так далі. З іншого боку, нещодавно працював над покращенням покриття та додаткові 3% не виявили нових помилок.


02.06.2024

GTD: поточні справи проти планування

В мене була весь час ця ідея, що система GTD повинна охопити все життя. Ну воно десь так: порівняно з простим “списком задач”, GTD пропонує перелічити всі “відкриті цикли” в житті, щоб їх… поступово закрити. Проте ось що я тільки починаю розуміти: GTD розрахований тільки на поточні справи, а ніяк не на всі майбутні плани: обовʼязкові, чи можливі, чи бажані.

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

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

Наприклад, якщо мої робочі задачі сидять в Jira, то мені не потрібна синхронізація з Jira, щоб використати GTD. Достатньо переписати в проєкти дві-три поточні задачі. А наступні дії можуть зʼявитися як самі собою, так і з плану реалізації чи інших підготованих заздалегідь матеріалів. Причому не потрібно переносити самі плани в GTD: достатньо щоб їх було легко знайти та передивитись (там же ж в Jira).

А відповідно, GTD дійсно можна займатися хоч в блокноті, бо саме таку інформацію й зручно зберігати в блокноті: короткочасну та стислу. А цифрові рішення навпаки, несуть ризик все ускладнити та загубитись.


01.06.2024

OpenSearch: база, де все відбувається не відразу

Нарешті зміг для себе зрозуміти, що мене понад усе дратує в роботі з OpenSearch: майже нічого в цій базі не відбувається синхронно. Я звик, що база даних є синхронною; звісно, реплікація займає час, але той вузол, з яким працюєш, все робить коли йому скажеш. В OpenSearch все не так.

Навіть з базовими діями — наприклад, індексацією одного документа — є спеціальний параметр refresh=wait_for, який змусить виклик чекати, поки документ не стане проіндексований. За замовчуванням індексація буде відкладена. Це відразу помічаєш у тестах, бо без цього параметра вони ніколи не будуть стабільними.

А коли маєш справу зі складнішими операціями, взагалі краще думати про них як про процеси; в деяких випадках — буквально. Наприклад, в PostgreSQL масове оновлення (UPDATE ... WHERE) теж може тривати навіть години, але таблиця може бути тільки у двох станах: не оновлена та оновлена. З OpenSearch масове оновлення опрацює скільки встигне та повернеться — далі запускай наново.

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

Все це добре, коли вас влаштовує кінцева узгодженість, а чи буде вона досягнена зараз, чи через хвилину — байдуже. Та це, певно, найбільша перешкода у використанні OpenSearch як традиційної бази даних.


31.05.2024

Setapp

Операційна система macOS завжди мала потужну екосистему якісних та платних застосунків. Настільки, що саме з переходом на macOS у 2011 році я почав віддавати за застосунки реальні гроші — на Windows та Linux не доводилось. А тут програма могла запросто коштувати десятки доларів. Тоді ще не було App Store та не було підписок; втім, було нормально брати гроші за кожну мажорну версію.

Ефективне використання macOS потребує кураторства власної колекції застосунків, яка розвʼязує твої особисті потреби. Для мене такими є Bartender, Yoink, BetterTouchTool, Dash та багато інших — колись писав цілу статтю.

Помітили спільне в цих посиланнях? Вони всі ведуть на Setapp - сервіс “оренди застосунків за єдиною підпискою”. За 9 доларів на місяць я отримую ці та десятки інших застосунків та більше не думаю, чи попросять вони гроші за наступну версію, чи є в них власна підписка (як зараз модно), та скільки взагалі коштує окремий застосунок. Тому я щасливо підписаний на Setapp без жодних роздумів.

Наприклад, за Bartender 1 я заплатив у 2012, а потім за Bartender 2 у 2015. У 2016 зʼявився Setapp, та наступну версію Bartender я встановив вже звідти, та так і продовжую користатися ним за єдину підписку — наразі версією Bartender 5. Так само з iStat Menus. А Dash з 2023 перейшов на модель підписки, проте мене це вже не турбує — бо в Setapp він доступний в повному обсязі за ту саму єдину ціну.

Наразі в Setapp доступні найкращі застосунки для macOS (ну, не всі). Може, їх не так легко знайти: точніше, я ніколи не шукав їх через Setapp, а скоріше, знаходжу в широкому інтернеті, а потім, наприклад, перевіряю, яка з 3 програм доступна в Setapp. Або коли потрібно щось разове, тоді можу звернутися до Setapp, щоб безплатно отримати якіснішу програму: може, архіватор чи клієнт випадкової бази даних.

За моїм реферальним посиланням можна отримати місяць безплатно.


30.05.2024

Механізм оновлення у SwiftUI

Коли йдеться по декларативні презентаційні фреймворки, я звик до React та його парадигми “воно само магічно перемалюється”: при найменшій потребі React викличе всю ієрархію компонентів, а потім завдяки Virtual DOM ефективно впровадить зміни у реальність. У Swift все не як в React: хоч код теж має декларативний вигляд, але він працює на підписках на зміни в даних за шаблоном Спостерігач та оновлює тільки там, де відбулися зміни.

З одного боку, це ефективно та круто, але з іншого, потребувало чітко розуміти які дані можуть змінюватись та стежити за анотаціями. Такої простоти, як в React, не було.

Але це поки використовувався фреймворк Combine (офіційний, від Apple). Він надає загальну модель асинхронної обробки подій, а як окремий випадок — протокол ObservableObject для стеження за змінами в обʼєкті. Минулого року вийшов новий фреймворк - Observation. Більше деталей знайшов у супроводжувальному документі.

Observation, що цікаво, побудований не на підписці, а на механізмі зворотних посилань; серцем фреймворку є метод withObservationTracking, який зберігає всі звернення до відстежуваних атрибутів всередині та один раз викликає обробник, коли один з тих атрибутів змінився.  (На наступний виклик ми можемо потрапити в іншу гілку коду та звернутися до інших атрибутів; тому щоразу перелік посилань будується наново.)

У SwiftUI все це приховано, та ми знову просто пишемо код, та він сам магічно перемальовується. Майже як в React. Але навіть краще ніж React, бо перемальовуються тільки ті компоненти, які залежать від атрибутів, що дійсно змінилися.