Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
02.10.2023
Як працювати з кодом JavaScript, коли вже звик до TypeScript?
Коротка відповідь — навпомацки. Відсутність типів відбирає приємне відчуття що код “звʼязався до купи.” Втім — доводиться стикатися з проєктами де TypeScript немає.
На щастя, VS Code й у JavaScript робить часткову типізацію. Підказки до коду та автодоповнення враховують ті типи, які можна зʼясувати з оточення. Це більш потужно, ніж можна подумати — на типах з пакетів залежностей можна далеко доїхати.
Але щоб дійсно досягти бажаної типізації, можна впроваджувати типи у JSDoc. Фактично це ті ж самі типи, тільки обʼявлені всередині коментарів (та тому на них не діє автоформатування, що дратує мене щоразу.) Не чув, щоб хтось був проти додаткових коментарів, тому це вірний шлях для проєктів з багатьма учасниками та великою базою коду.
В JSDoc можна робити все те ж саме, що й просто в TypeScript - імпорти з інших модулів, складні типи, дженеріки, оголошення типів за іменем. Не раджу, наприклад, власний підхід JSDoc до типізації обʼєктів тегами @property; краще просто оголосити тип-обʼєкт в синтаксисі TypeScript в тезі @typedef, а потім використати його.
На останнє, якщо в файлі JavaScript написати магічний коментар //@ts-check, то для нього увімкнеться повноцінна перевірка на типи та вкаже всі помилки. Так хоч би тимчасово (або ні) можна переконатись в правильності коду та отримати ту дозу дофаміну.
01.10.2023
Змінні CSS
Під час розробки плагіну для Obsidian дізнався про таку технологію, як змінні CSS. Вона тільки відносно нова, бо доступна в усіх браузерах з 2018 року. Варто про них знати, бо це багато спрощує.
Змінна оголошує значення в контексті каскаду стилів та успадковується схоже до звичайних властивостей CSS. Стилі, які знаходяться глибше за визначення, можуть цю змінну використати. Таким чином каскадність стилів розширюється; тепер в наших компонентах ми можемо не просто спиратись на атрибути, які визначені вище (наприклад, колір шрифту), а й додавати власну логіку (наприклад, зробити рамку такого ж кольору, як шрифт, а скоріше, узагальненого кольору на кшталт var(--color-fg).)
Коли я вчив CSS, то змінних там ще не було. Зате змінні були в Sass. Між ними та змінними CSS є суттєва різниця: в Sass змінні мають синтаксичний контекст, тобто вони привʼязані не до таблиці стилів, а до початкового коду Sass. Так що змінні CSS це не просто заміна змінним Sass, а інший підхід, що має кращу синергію зі семантикою каскадних таблиць стилів.
Та окрема перевага — те, що змінні CSS залишаються в кінцевому коді. Це дуже зручно для розробки всіляких доповнень, оскільки стилі доповнення можуть легко використати базові стилі, якщо ті визначені через змінні. Так, в Obsidian тема оголошує змінними всі свої параметри. Якщо я хочу підсвітити термінову задачу червоним — мені не потрібно вигадувати колір, який буде сумісний з темою користувача — можна просто взяти --color-red або, можливо, --text-warning. Шкода що не можу знайти другого прикладу такої системи.
30.09.2023
Перехід з віджета до документа з задачею
Плагін потроху набуває форму. Одна з необхідних функцій це перехід з віджета активних задач до документа, в якому задача розташована. Спочатку хотів вставляти звичайне посилання, тобто <a>; посилання на файли в Obsidian працюють, але немає можливості відправити посилання на конкретний рядок. А без цього якось некрасиво. (Можна тільки посилання тільки на заголовки та на попередньо проставлені якорі.)
Тому пішов іншим шляхом — через API. Все ж віджет це повноцінний додаток, в якому можна написати будь-яку логіку. В Obsidian є така прикольна функція Workspace.getLeaf, яка утворює нові панелі редактора у вказаному розташуванні. Або бере поточну, що мені й треба. Далі робимо openFile() та файл відкритий. Цікавий нюанс: якщо панель закріплена, то openFile автоматично утворює нову, тобто покриває за нас поведінку самого Obsidian.
А щоб пересунутись на правильний рядок, є два варіанти. Або пересунути курсор в рядок задачі функцією setCursor - це прокрутить документ так, щоб курсор був на екрані. Або викликати scrollIntoView - це просто прокрутить до зазначеного місця.
Мені жоден варіант не сподобався, бо знайти курсор серед тексту все одно важко. Придумав гарне рішення: додатково виділяти відрізок тексту — виділення помітніше. (Для того є функція setSelection.) Але що виділяти, щоб це було корисно? На мою думку, найбільш корисним є виділяти статус задачі, оскільки найчастіша дія це саме зміна статусу. (Поки не вирішив, чи треба додавати таку фічу в сам віджет, та в якій формі.)
29.09.2023
Про екрани завантаження в іграх Bethesda
Попалося мені порівняння завантаження зони в Cyberpunk проти Starfield. А саме: в Cyberpunk перехід з будівлі на вулицю відбувається безперервно, а в Starfield двері відкриваються через екран завантаження. Та не секрет що в усіх іграх Bethesda були такі екрани завантаження. Задумався, чому це так. Я не думаю, що Bethesda навмисно користуються застарілим рушієм просто щоб заощадити гроші — тож яка може бути причина?
Знайшов один показник, за яким ігри Bethesda абсолютно виділяються. Це величезна кількість модів, що додають до гри локації та квести. Дійсно, під час зміст модів перевищує зміст самої гри (Morrowind) або утворює повноцінну нову гру (Enderal на базі Skyrim, наприклад.) Серед рольових ігор з відкритим світом немає нічого навіть близького.
У Bethesda завжди був неперевершений редактор для модів - Creation Kit. Ще з часів Morrowind в ньому було досить нескладно додати свої будівлі, персонажів, діалоги. Тільки, як відомо інженерам, одного редактору мало — потрібна зручна ментальна модель.
Світ рольової гри можна моделювати по-різному. Простіше думати про світ, якщо він поділений на ізольовані зони. Найголовніше, що не треба думати про стикування отворів — а це значить, що інтерʼєр та екстерʼєр можна розробляти окремо та в різних масштабах. Так само ізольовано можна думати про скрипти та поведінку. Це така собі інкапсуляція ігрового світу. Саме в цьому я бачу пояснення екранам завантажень.
28.09.2023
Головний програміст в пласкій команді
У нас інженерна організація абсолютно пласка. Кожний програміст на проєкті є потужним індивідуальним вкладником. Старшинства немає — щоб зробили “по твоєму”, треба це обґрунтувати та “продати”. Питання вирішуються демократією Втім, я бачу потребу в головному інженері (lead of engineering).
Посада головного інженера існує для того, щоб охоплювати контекстом весь проєкт, та координувати дії його підрозділів. Якщо ти та я копаємо тунель з різних сторін, то хтось має перевіряти, що ми зійдемось в одній точці. Причому координація це теж робота, окрема від утворення результату.
Якщо головного інженера немає, то в обовʼязки кожного інженера входить: а) повідомляти всю команду про свої архітектурні зміни, та б) стежити за змінами, що надходять від інших інженерів, та реагувати на них. Чим більше проєкт, тим складніше бути в курсі всього, що відбувається. Ба більше, постійна потреба не пропустити важливу зміну веде до тривоги та конфліктів в команді.
Головний інженер в пласкій команді не буде стояти зверху, він буде стояти посередині, та тримати всі контексти, щоб решта команди могла заглибитись у свою роботу.
27.09.2023
Використання засобів AI для написання коду
Я вже писав про Tabnine - помічник для написання коду, яким я користуюся. Проте Tabnine дає мені тільки доповнення в межах рядка. А більш просунуті помічники навіть не хочеться пробувати. Спробував зʼясувати, чому.
Насправді все просто: код, який можна використати як є, помічники поки не генерують, а переробляти чужий код для мене менш приємно, ніж писати свій. Написання коду це набагато більше ніж просто введення символів: під час написання формується розуміння того, що цей код має робити. Якщо код не містить нового розуміння, то той код зайвий, та я б хотів його позбутися, а не генерувати автоматично. Якщо код задачі може згенерувати ChatGPT, це вже розвʼязана задача; я не хочу бачити дублікат розвʼязку у своєму проєкті, я хочу імпортувати бібліотеку (з якої, ймовірно, ChatGPT й навчився написати цей код.) (І це я ще нічого не сказав про галюцинації та як їх буде приємно перевіряти в нетипізованій мові.)
Звісно, не всі аспекти програмування потребують такої уваги. Я давно не форматую код сам, а використовую Prettier та аналоги; так само автоматизовані організація імпортів та стилістичні виправлення. Але моя робота — перекладання нечіткої та багатозначної бізнес-задачі в формат, який зрозумілий машині. Для цього написання коду поки мені подобається більше, ніж спілкування з нейронною мережею.
Де б я хотів помічника, так це для пошуку по малознайомих проєктах. Я витрачаю на це чимало часу. Наприклад, відкриваю franz-go та питаю: “як визначити, скільки залишилось непрочитаних записів?”. Або, взагалі, для пошуку самих проєктів: було б чудово сказати “мені потрібно розібрати Markdown в синтаксичне дерево з відстеженням позицій вузлів” та отримати хорошу рекомендацію. Може, у вас знайдеться рекомендація такого сервісу?
26.09.2023
Плагін для Obsidian - як вони випускаються
Мій плагін нарешті став корисним, а значить, настав час перенести його з тестової бази на справжню.
Всі плагіни, що в тебе встановлені, сидять в теці .obsidian/plugins всередині сховища. Це значить, що в кожного сховища плагіни свої. Тому для розробки плагіну розумно створити окреме сховище документів та встановити плагін туди — тоді можна спокійно та без ризиків все протестувати.
Плагіни також синхронізуються між пристроями та навіть підключаються в мобільну версію. Так що плагін для Obsidian - це, можливо, найпростіший спосіб створити мобільний додаток. Навіть місце для зберігання даних та синхронізація буде. Та й дійсно, мій плагін без додаткових зусиль запрацював на телефоні. Тепер я навіть планую особливі екрани для телефону, щоб нашвидкуруч робити прості організаційні дії.
Як тоді зробити релізну версію плагіну та встановити її? Виявилось, дуже просто. Пакет складається з трьох файлів: коду, стилів, та маніфесту. Причому так для всіх плагінів. Інші ресурси — наприклад, зображення — ховаються в файлі з кодом, якщо я правильно розумію. Принаймні великих CSS в готових плагінах я не побачив.
Щоб випустити плагін для всіх (що я поки зробити не готовий), треба зробити репозиторій на GitHub, створити в ньому нову версію та підʼєднати до неї ці три файли як це зроблено тут. Трохи дивний спосіб випускати пакети, але він працює та не потребує додатково інфраструктури. Каталог плагінів теж розташований на Гітхабі.
А для себе достатньо створити нову теку в .obsidian/plugins, скопіювати туди файли та увімкнути плагін в налаштуваннях — це все. В мобільній версії плагін зʼявиться сам (якщо увімкнена синхронізація, звісно.) Одним словом, хороше середовище для розробки, раджу спробувати.
25.09.2023
Логічна реплікація в PostgreSQL як засіб відстеження змін
Я вже писав про логічну реплікацію як найкраще рішення для часткової синхронізації двох баз PostgreSQL. Нова версія PostgreSQL 16, яка вийшла десять днів тому, містить ще декілька покращень для логічної реплікації. Я радий тому, що вона активно доробляється, оскільки, як писав, не все там ідеально.
А сьогодні про інше. Логічна реплікація дуже проста технологія — одна база зберігає журнал, інша забирає його по протоколу реплікації та відтворює зміни у себе. За цим протоколом не тільки PostgreSQL, а будь-яка програма може забирати зміни та робити з ними що завгодно.
Виходить, що з PostgreSQL можна зробити маленьку Кафку: замість топіка в нас буде журнал WAL, причому підписників як і в Кафки може бути декілька. З тою різницею, що PostgreSQL також зберігатиме дані в таблиці, як завжди. Точніше, у зворотному сенсі: до звичайних таблиць можна також додати сервіс, який оброблятиме зміни у формі подій. Може, для аналітики, може, для побудови похідного стану. Реплікація працює миттєво та не потребує сканування таблиці.
З технічної реалізації: ось пакет pglogrepl для Go. Я перевірив локально — все працює. Ми отримуємо зміни у вигляді структур — знати схему таблиці не обовʼязково. Налаштувати підключення до бази ледве складніше, ніж звичайне.
Може, спробую наступного разу, як доведеться будувати реактивну логіку навколо бази PostgreSQL.
24.09.2023
Думки про ремонт
В мене останні три дні було закінчення підготовки до ремонту. Було зроблено роботи на місяць, мабуть.
-
Мене підсилюють крайні терміни та взагалі кризи. На жаль, тому що хотілося б якось і без криз підсилюватись. А так — дивишся, скільки можна встигнути за три дні, та шкодуєш, що так не виходить завжди. Або принаймні, чому не можна так зробити відразу, а потім відпочивати. Але ні — задля результату потрібний тиск. (Штучні терміни зі мною, на жаль, не працюють.)
-
Ведення нотаток і тут допомагає тримати все в голові… а точніше, як раз не в голові. Нової інформації, а також контекстів, стільки, що в голові не утримаєш. Окремо виділю збереження всіляких світлин та малюнків — радий, що це легко робити в Obsidian. Часто робив так: знайшов річ (меблі, плитку, ще щось) - зберіг посилання — зробив скриншот та розмістив поруч.
-
Не знаю, хто як обирає побутову техніку, але я роблю перебір по декількох сайтах (різні категорії на різних сайтах зручніше) - щоб поступово зрозуміти, які фактори важливі. Зокрема по фільтрах — дивлюся на кількість позицій за варіантами, щоб зʼясувати, які фільтри варто обирати, а де вибору не буде. Також визначаю адекватну ціну. Далі звужую пошук та знову перебираю каталоги, щоб сформувати короткий список, який потім переглядається на наявність оглядів (на ютубі зараз можна цікаві огляди знайти) та згадок в статтях. (До речі, дарую ідею для стартапу: підбір кахлю за схожістю за допомогою нейронної мережі. Звісно, з агрегацією та перевіркою наявності.)
-
Сюжет “Відьмака 3” настільки кращий за “Кіберпанк 2077”, що навіть не віриться, що вони зроблені однією студією. Кожне завдання “Відьмака” відповідає світу, в якому потвори є реальною загрозою людям, життя знецінене, та насильство є нормалізованим. Втім, герой залишається моральним актором всередині цього світу, а не всупереч йому. Та гра помічає, коли ми вирішуємо завдання насильством. Тут, звісно, допомагає те, що моральність застосування сили — головне питання оригінальних романів.
23.09.2023
Чому саме дерево — найкраща структура для задач?
Наступна фішка для моєї системи задач в Obsidian - то підтримка вкладеності. Але не просто вкладеності пунктів — то зрозуміло. Мені хочеться, щоб вкладеність працювала через документи.
Тобто якщо задача має вигляд - [ ] [[ремонт]], то документ ремонт з усім своїм змістом вважається частиною дерева задач. Це дозволяє досягнути довільного рівня вкладеності без створення непомірно довгих списків.
Мій поточний досвід показує, що при плануванні це допомагає. Реальні задачі мають категорично різні рівні складності, та загнати відразу все в красиво обмежені абстракції не виходить.
Точніше, не так: “картки” в Trello, або “епіки/задачі” в Jira зручні для виконання вже після того, як планування закінчене та ми маємо чіткий набір кроків. Хоч всім знайомо, що деякі картки виявляються складними та займають багато днів, а інші, що стоять поруч, виконуються за пʼять хвилин.
От тільки в мене ніколи не буває окремих етапів планування та виконання. Та завжди може зʼявитися потреба розбити один з пунктів ще глибше. Тому прийшов до того, що дерево задач — найбільш природна та зручна форма. Особливо коли це дерево зберігається в Markdown та легко може доповнюватись нотатками, посиланнями, ілюстраціями й так далі.
Проте видобувати з дерева потрібні пункти (наприклад, те, що я зараз роблю, або всі термінові задачі) вручну не є практичним. А коли йдеться про вкладені документи, то й зовсім нереальним. Тому будувати з дерева списки будуть мої віджети.

