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

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

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

14.11.2024

Ефективна робота зі сповіщеннями GitHub

Колись майже два роки тому мене дратував надлишок сповіщень з GitHub, та я навіть намагався зробити для того застосуночок. Погані новини: за весь час, що я витратив на перегляд PRів, такий застосунок не написати.

(Апарт: зі стохастичним трекером я “точно” знаю, скільки це часу. За минулі 9 місяців — близько 30 годин.)

Гарні новини: зі сторінкою сповіщень можна працювати ефективно. Та, якщо в одних обставинах має сенс збирати всі вхідні в один “кошик”, то тут, навпаки, варто розділити. Причому розділити за кількістю уваги, яку PR вимагає. Бо якщо дивитися на всі сповіщення разом, то доведеться кожному приділяти достатньо уваги, щоб нічого не пропустити.

Для цього звертаємо увагу, що на бічній панелі є посилання “Add new filter”. Туди можна окрім вбудованих фільтрів, назбирати власних, за обставинами. Можна або фільтрувати те, що варте уваги, або навпаки — те, що не варте, та масово “відмічати як прочитане”. Ось кілька ідей:


13.11.2024

Рушії для блогу

Взагалі я, звісно, переписував колись блог на новий рушій. Коли я починав щось публікувати, здається, ще взагалі “рушіїв” ніяких безплатних не було, а платити тоді не було чим. Перший сайт був на рукописному HTML.

Втім, я все ж був програмістом, тому знайшов таку цікаву технологію як SSI (включення на стороні сервера), якими можна замінити повторюваний початок та кінець сторінки. Хоч SSI не давав справжніх шаблонів, бо не було ані параметрів, ані “обгорток” - тільки пряме включення.

На початку 2008 в мене зʼявився перший віртуальний сервер, а також перша версія блогу на WordPress. Не памʼятаю, як обрав саме його. Я на той час працював на PHP та й фрілансив для WordPress, тож, мабуть, тому. Здається, в мене була власна тема та чомусь багато всього складного… Хоча найбільший мінус WordPress як я бачу зараз це його вразливість. Для найпопулярнішої платформи в інтернеті, в ній надто багато дірок, чим без кінця користуються спамери. Сайт на WordPress потребує постійної уваги та оновлень. Або просто будеш інколи помічати, що вже пару місяців хтось розсилає пошту з твого VPS/

Іронія в тому, що в тому самому 2008 я почав дивитись на RubyOnRails, а невдовзі й працювати з ним професійно… тож підтримка WordPress подобалася ще менше. Я не знайшов нічого кращого, ніж у 2011 переписати все на Rails.

З плюсів — ламати припинили, код став приємніше (HAML/SASS, між іншим). Блог перетворився на справжній проєкт-хобі. З мінусів - Ruby on Rails значно ненажерливіше. Особливо коли не розробляти сайт з розрахунком на кешування повних сторінок. Бо, якщо чесно, якщо кешувати, то недалеко від наступного рішення…

У 2016 мені набридло підтримувати Rails, та я переписав блог на Hugo - щоб він знову став статичним сайтом. Бо, дійсно, від блогу одного автора не потрібно багато динамічності. До речі, статичність не означає, що в сайті відсутня логіка та програмування; їх тут повно — але весь код виконується в момент компіляції. Головне, від чого довелося позбавитися — це коментарі — а точніше, замінити на зовнішнє рішення. Спочатку на Disqus, а зараз на власний скрипт. Втім, коментарі на сайтах все одно відійшли в минуле.

(Також, очевидно, зникла адміністративна панель та вебредактор. Тут я не бачу проблем, бо на розробку гідної адміністративної панелі часу не вистачало — а у статичного сайту замість неї звичний IDE та Git.)

Виходить, блог я переписував двічі: спочатку на Rails, а потім — з них. За цим трендом у 2023 пора було переписувати наново. Але, я переконаний, що статичний сайт — це найкраще рішення для мене, тому нікуди не поспішаю.


12.11.2024

У вас, певно, не буде часу на це переписування

Безперечно, переписати проєкт наново приваблива пропозиція. Можна нарешті врахувати все розуміння, виправити всі помилки… Під час це звучить настільки привабливо, що всі інші покращення відкладаються “на після переписування”. От тільки зараз часу переписувати немає, але як руки дійдуть… Тоді все зробимо як треба.

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

Таких аргументів для переписування недостатньо. Потрібні вагомі, категоричні переваги нового рішення, до того ж релевантні для проєкту. Навіть більше, старе рішення мусить мати такі ж категоричні вади. Тоді переписування з мрій перетворюється на потребу.

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

Наприклад, я нещодавно думав переписувати наново рушій для блогу. Бо… надто складний він зараз. Але нічого технологічно нового я не планував: той самий Hugo. Та от бачу, що краще поступово додавати функції та оновлювати дизайн на місці. (Цими днями додав посилання на Mastodon… а також замінив значки на обрізаний Nerd Fonts.) Бо переписувати буде нереально довго.


11.11.2024

Порядок виконання задач

Загально прийнятно планувати виконання задач крайньою датою (due date). Але, як вам повідомить кожний студент, крайня дата не є дієвою для планування роботи. Як на мене, то крайні дати взагалі є засобом комунікації, а не планування. Ми домовляємось з кимось (або з самими собою) про очікуваний результат. Але є мало сенсу робити задачі в порядку крайніх дат.

Зараз є інший досить популярний підхід — це дати виконання (do date). Або їхній спрощений варіант “зробити сьогодні / завтра”. Так трохи легше, в першу чергу тому, що дати виконання можна розставляти сміливіше, ніж крайні дати. А точніше, сміливіше їх порушувати.

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

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

Для вибору порядку виконання є й більш просунуті системи: наприклад, Autofocus чи Final Version. Але головне, що можна зробити, це частіше звертатися до списку та щось з нього виконувати, а не тільки планувати та розставляти дати.


10.11.2024

Найгірша функція macOS (idleassetsd)

Знаєте оті відеошпалери від Apple з мальовничими краєвидами? Дуже їх люблю. На Apple TV. На macOS я їх просто ненавиджу. Не через те, що вони некрасиві — насправді, я взагалі ними не користуюся, бо рідко бачу робочий стіл. А через те, як вони обурливо марнують системні ресурси.

Почнемо з того, що повний пакет відеошпалер займає понад 80 Гб. Це більше, ніж багато ігор AAA, але в контексті macOS краще порівняння, що це 20% базового розміру накопичувача. На шпалери!

Ніби все не так погано, бо в файловій системі APFS файли шпалер відмічені як “доступні для видалення”, тому якщо на диску закінчується місце, то macOS автоматично їх видалить. В теорії це звільняє нас від турбот про місце, але на практиці деякі програми про це не знають, та вживають власних заходів зі звільнення місця (наприклад, Телеграм.)

Також, як я розумію, шпалери є “доступними для видалення” разом зі значно важливішими файлами, як-от локальні копії з iCloud чи з Apple Photos, або кеш — та мають рівні права на існування. Це як обирати, що брати в подорож — валізу з одягом чи валізу з журналами.

Але і це ще не все. Коли на диску зʼявляється місце для шпалер, то macOS автоматично завантажує їх назад. Бо звісно, шпалери це важливіше, ніж документи з iCloud, які завантажуються тільки за запитом. А коли мій диск майже заповнений, то взагалі починаються нескінченні пересування туди-сюди!

Менеджер відеошпалер називається idleassetsd та в інтернеті повно скарг на його марнування процесора, памʼяті чи інтернету. На жаль, зупинити його неможливо — ось така критична підсистема. Можна заблокувати доступ до інтернету через TripMode, LittleSnitch, LuLu тощо.

А також знайшов на Реддіті як його надурити: не видаляти файли шпалер, а зробити порожніми.

sudo truncate -s 0 /Library/Application\ Support/com.apple.idleassetsd/Customer/4KSDR240FPS/*.mov

👑 Шпалери 4K 240 FPS, на якості не економимо!


09.11.2024

Переваги розробки наодинці

Професійне програмування включає багато підходів, які допомагають команді досягти успіху. Та коли ти раптом хочеш зробити проєкт самотужки, природно буде намагатися відтворити ці підходи. Деякі з них, безперечно, варті того (використання система контролю версій?) Але не всі (наприклад, вичерпне покриття тестами.)

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

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

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

Також не обовʼязково витрачати час на правильну архітектуру, покриття всіх уявних випадків, та стовідсоткову надійність. Це не робить тебе гіршим розробником — тільки більш свідомим та прагматичним.


08.11.2024

Пошук перегонів даних в Go

🏁 Перегони даних — це коли два рівночасні процеси наввипередки оновлюють змінну, без відома про існування один одного (Мені не дуже зрозуміло, чому це називається перегонами.) В результаті отримуємо напівзіпсоване значення, в якому не врахована частина обчислень. Причому, звісно, рівночасність — непередбачуване явище, тому псування трапляється не кожного разу, а може взагалі чекати на високе навантаження в продакшні.

Одним словом. Шукав, чому випадково хибиться тест. Звузив причину до ділянки з використанням go-redis#ClusterClient.ForEachMaster - вона збирала значення з усіх серверів Redis в один масив. Спочатку думав, що тесту бракує очікування (ще одна класична причина випадкових хиб) та намагався виправити. Тут є легка перевірка, насправді: додай свідомо перебільшене очікування — може, 10 секунд — якщо це не виправляє тест, то проблема в іншому.

А потім помітив в документації по ForEachMaster, що вона-то рівночасна!. Звісно, через рівночасність зміст вихідного масиву був неповним, до того ж для кожного хибного випадку різний. Щоб виправити, я додав збір результатів через канал, але можна було б й мьютекс поставити. Такі API з прихованою рівночасністю мене обурюють, бо з ними хоч знаєш, а не зробиш правильно.

Тут я згадав, що в Go є детектор перегонів та раптом дізнався, що він не увімкнений за замовчуванням. Увімкнув — та дійсно, проблемний тест відразу “засвітився”. Хотів вже увімкнути для всіх тестів та локальних запусків, але виявив пару проблем з цим. По-перше, тести з детектором тривають в три рази більше. По-друге, як не дивно, але для компіляції з детектором потрібно увімкнути CGO, а це йде зі своїм пакетом ускладнень, як-от неможливість кроскомпілювати з macOS в Linux. Довелося відмовитись.

Нарешті, детектор знайшов ще одну гідну обурення ситуацію. Такого я ще не бачив. Офіційних серіалізатор Protobuf у JSON - protojson - додає у випадкові місця JSON пробіли. Та цього навіть не можна вимкнути!. Пояснюють вони це тим, що “споживачі мусять не очікувати чіткого формату”, оскільки команда Protobuf з ним ще не визначилася (sic!) Тому поки відстежуємо обговорення, якому вже 4 роки, а в тесті довелося декодувати JSON та порівнювати не рядком, а за змістом.


07.11.2024

Майже синоніми

Тільки писав про переклади айтівської лексики, а тепер пишу коментар в коді англійською та виходить щось на кшталт “ці атрибути доступні тільки для читання… а оце поле можна писати”. Дивлюся та думаю: навіщо стільки слів, які достатньо схожі, щоб їх плутати, але все ж різні, щоб доводилося стежити за використанням. Це ж гірше ніж табуляція проти пробілів!

В мене в голові слова “атрибут” та “поле” це майже синоніми. А їхнє використання більше залежить від оточення: в Go “поля”, в Ruby “атрибути”. (Причому в Ruby атрибут — це суто домовленість, що пара методів читає/пише змінну екземпляру.) Хоча, думаю, читач здогадається, про що йдеться, але все одно варто дотримуватися заведеного набору слів. Що стає проблемою, коли працюєш в декількох оточеннях.

Атрибут, поле, властивість — тут майже повна взаємозамінність, хоча в кожній мові своя назва. Головне не плутати в одному реченні дві назви. Є ще стовпчик в базі.

Метод, функція, процедура — тут все розбігається… в Go функція сама собою — це “функція”, але в межах типу чи інтерфейсу це “метод”. А в Ruby всі функції то “методи”, от тільки чомусь є метод module_function, який перетворює всі методи модуля в методи на модулі. На щастя, “процедура” майже не зустрічається… хіба що в SQL є й “функції” й “процедури”. А ще є параметр, аргумент, опція.

Обʼєкт, структура, запис, сутність, екземпляр, а також клас, тип, структура — тут потрібно бути обережним. В JS/TS є тип “обʼєкт”, а є “клас”, і різниця важлива. У Swift є “класи” та “структури” та це фундаментально різні речі (класи передаються за посиланням, а структури — за значенням.) В Ruby все є класом, навіть модулі.

А ще в кожного слова є його математичне значення. Та побутове значення. А ще різні бібліотеки можуть залучати “вільні” слова для внутрішнього використання (так, в Ruby обʼєкти типу ActiveRecord зазвичай називаються “запис”.) Все складно!


06.11.2024

Порожній список дій на роботі та висновки

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

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

Це моя перша роздільна система для роботи та дому. Раніше робота завжди була контекстом (текою, зоною) в спільній системі. Зараз в мене окремий компʼютер для роботи та я намагаюсь відокремити роботу від особистих справ, тому було логічно й системи задач зробити дві.

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

В домашній системі до такого успіху ще далеко, бо там все (поки?) вдесятеро складніше. Контекстів багато, проєктів багато, вони всі різні. А головне — потрібно вставати з-за компʼютера. Бо дійсно, зараз робота стала такою зоною комфорту, де все заздалегідь впорядковано — сиди та роби. Раніше так хіба з компʼютерними іграми було. Втім, такий успіх надихає влаштувати особисті справи так само.

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

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


05.11.2024

Теги в каналі та HTML

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

Іншою особливістю тут є те, що метадані (разом з тегами) є частиною вихідного тексту, а значить, зʼявляються не до, а одночасно з обробкою Markdown. Тому легше за все замінити теги вже в підготованому для Telegram тексті. Який є потворним гібридом HTML та текстової розмітки. Тож доведеться заміняти в HTML.

Як заміняти? Точно не регулярними виразами. Тут потрібний той чи інший парсер HTML. В Go для того є модуль net/html - я про нього вже згадував. Він надає, окрім іншого, токенізатор HTML, тобто спосіб перетворити HTML в послідовність токенів: “тег”, “текст”, “коментар” тощо.

Для такої задачі токенізатор краще, ніж розбір документа в дерево, оскільки дерево нас не цікавить. Нам важливо тільки одне: чи знаходиться текст всередині посилання. Тому заводимо прапорець “чи ми в посиланні” та біжимо по документу.Бачимо токен “відкрити тег A” - вмикаємо прапорець; “закрити тег A” - вимикаємо прапорець. Якщо зустріли токен “текст” та прапорець вимкнений — шукаємо в ньому теги. А решту токенів копіюємо в вихід, як є.

Замість складного обходу дерева чи пошуку батьків — простий прохід з тривіальним скінченним автоматом. Швидко та прозоро.