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

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

Підписатись на RSS
📢 Канал в Telegram @stendap_sogodni
🦣 @stendap_sogodni@shevtsov.me в Федиверсі

23.02.2025

OAuth2 - це просто... завдяки HTTPS

Майже 10 років тому я написав пост про те, як легко впровадити OAuth2 без жодних бібліотек: OAuth2 is easy. Сьогодні — трохи продовження.

Можна уявити, що така відповідальна функція, як авторизація, потребує від нас підписів, криптографії, та інших складних алгоритмів, але ні. Протокол авторизації OAuth2 складається з простісінького обміну токенами: провайдер надає нам тимчасовий код, ми обмінюємо його на сталий токен доступу. Це можливо тому, що криптографію робить за нас протокол HTTPS.

HTTPS не просто робить вебсерфінг “трохи” безпечніше, він розвʼязує дві фундаментальні задачі безпеки: підтверджує автентичність сервера та встановлює надійно зашифрований канал до нього. Тому ми й можемо спокійно надсилати ключі (спільні секрети) “відкритим” текстом, а також довіряти відповідям.

Проблемою OAuth2 було те, що він був настільки простим, що кожний провайдер робив щось своє (про що я згадую у статті.) Тому писати загальну авторизацію було складно чи навіть неможливо. Зараз з цим стало краще, бо є протокол OpenID Connect, який стандартизує поведінку провайдерів. (Та OpenID Connect нічого спільного не має з тим OpenID, який я колись тримав на своєму сервері з phpMyID)

Для себе можна зробити висновок, що й у власних проєктах, зокрема внутрішніх, не потрібно вигадувати складних протоколів авторизації — достатньо переконатися, що ви використовуєте HTTPS (чи просто TLS).


22.02.2025

Проєкти зеленого поля

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

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

Проблема, втім, у розумінні. Поза знайомою галуззю в тебе може взагалі не бути жодної гадки про те, як щось працює (згадую, як при переході з PHP на Ruby мені було дуже дивно, що окремі файли Ruby не є адресованими за HTTP.) Та й взагалі, що існує, які абстракції визначені, які процеси тощо.

Зокрема, ще складніше обʼєднувати декілька продуктів для розвʼязання власної задачі. Навіть коли по кожному є документація, рідко вона передбачає твою комбінацію. (От є бібліотека для JS, але чи працює вона в React Native?) До того ж проблеми можуть виникнути на різних шарах абстракції (А чому Metro не бачить типів тієї бібліотеки та що поміняти, щоб бачив?) Інтеграція не продається, її завжди доведеться збирати власноруч.

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


21.02.2025

Проєкти зеленого поля

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

Ну добре… як ото світло згенерувати в умовах комори? Походив по форумах, дізнався, що зараз всі ставлять електричні лампи. Купив лампу: LED 18W 6500K (як у сонця.) Не працює. Почитав далі — та до них ще джерело живлення потрібно! Купив джерело живлення Energizer AAA. По-перше, як його взагалі підʼєднати? По уму всі друкують плати якісь, але то ще покупати апаратуру… або дроти, це нам більше по бюджету. Все одно щось ніяк, лампу з енерджайзером зʼєднав, а вона не світить.

Роздивився, що в лампи та в батарейки різна напруга? Добре, а де взяти ті 220V? Взагалі бачу, що для того будують електростанції. Зараз як раз є холівар: або ядерну, або сонячну (це наше!), або на газі… це все не зірка, але все одно для комори якось зовсім не той масштаб. А от бензинові електростанції є дуже компактні, поміститься. Тільки треба придумати, що робити з продуктами горіння.

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


20.02.2025

Фічафлаги та рефакторинг

Чистий код та DRY - це гарні принципи, але з них я роблю один виняток: коли працюю з фічафлагом. (Чи це “всім відоме” поняття? Фічафлаг — це перемикач, яким можна наживо обрати між старою та новою поведінкою частини коду. Зазвичай не для всіх, а для конкретного користувача. Таким чином можна не показувати нові фічі всім відразу, але мати можливість їх випробувати.)

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

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

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

Та й не тільки в тестах, а й будь-де в коді краще копіпастити весь той код, де гілки фічафлагу не є простими. А лінтер — сміливо вимикати; почекає.


19.02.2025

Мистецтво назв пакеті в Go

Ще одна унікальна особливість Go - підхід до організації пакетів. Тут пакетом є кожна директорія. Без вкладеності, вкладені — то вже окремі пакети. Я таке бачив ще хіба що в Terraform… а на чому написаний Terraform? На Go, то-то.

Саме пакет визначає межі приватності ідентифікаторів. (Чи знаєте ви, що в Go ідентифікатор з маленької літери є приватним, а з великої — публічним? Причому що типи, що змінні, що константи можуть бути як з маленької, так із великої. Ще одна абсолютно інопланетна особливість.)

За межами пакета імена включають його імʼя: mypkg.Type. (Є ще “імпорт всього”, але він майже не використовується.) Причому хоч назвою пакета є фактично його URL, та кожний імпорт згадує його повну форму: import "github.com/me/mypkg/subpkg", та в коді шлях не згадується. (Можна ще імпортувати з перейменуванням, бо без нього швидко опинишся із конфліктами.)

Це все довгий вступ до того, що в Go до йменування пакетів потрібно ставитися з великою відповідальністю. Зокрема, вони повинні бути стислими, бо постійно згадуються в коді. А тепер — ще стислішими. Два слова? Пиши разом, скорочуй. Звісно, це накладає особливий стиль. httputil, textproto, strconv, slog - це тільки приклади зі стандартної бібліотеки.

Втім, з власними пакетами складніше, бо рідко зустрінеш стале скорочення. Тоді в допомогу стає розділення імені. Наприклад, ніхто не забороняє зробити вкладені директорії: service/queries, api/v1. Це часто буває просто зручно: наприклад, коли пакети service1/config та service2/config будуть використані всередині відповідного сервісу, то з контексту й так зрозуміло, що то за config, а у винятку зробити import service1config "service1/config".

Також є домовленість виносити назву типу в назву пакета. Наприклад, http.Server або service1.Request. Хоча не завжди це виходить очевидно. Краще, коли пакети маленькі та тісно звʼязані (це взагалі краще.)

Взагалі. Успіх проєкту на Go дуже залежить від вірної організації пакетів. Про це, може, іншим разом.


18.02.2025

Три речі, яким я приділяю увагу під час перегляду ПРів

🧩 “Цікавий” код. Більшість коду є нудною та передбачуваною. Я довіряю колегам в тому, що він робить те, що потрібно. Але… інколи дивишся на єдиний змінений рядок (або навіть переставлений місцями з іншим) та підіймаєш брови… що це?

В таких випадках обовʼязково зʼясую, чи зміна навмисна (бо інколи залишається якесь сміття від розробки, або масова заміна не спрацьовує, або ще щось.) Або, може, навмисна, але неправильна. Чи я чогось не розумію. Що веде до наступного пункту…

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

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


17.02.2025

Забиратися на гору

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

Власне, головна теза така, що прогрес через повторення має межу. Якщо кожен день робити фічі на React, то можна набити руку, досконало вивчити весь синтаксис та бібліотеку, але залишитися на тому ж рівні майстерності.

Ця модель “забирання на гору сходами” дає раду: розрізняти практику заради можливостей (знань) та практику заради навичок. Потрібні обидві.

Щоб отримати знання, потрібно вийти з зони комфорту, зробити щось нове (або новим чином.) Це не буде ефективна робота, бо навичок ще немає. Мета — набути нову можливість.

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

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

А от коли б для власних проєктів обирати такі технології чи підходи, які можна запровадити у роботу — тоді можна вибудовувати в себе нові рівні майстерності. (Або ж робити це на axe friday, певно, ще краще.)


16.02.2025

LLM, Obsidian та Windows - щось таке

Вчора спало на думку / згадали в коментарях, що можна було б використовувати базу знань з Obsidian як вхідні дані для чат-моделі, та таким чином отримати пошук з кращим розумінням понять, ніж в прямого порівняння рядків.

Про цю ідею взагалі багато всього зроблено, бо на базовому рівні тут наче типова для LLM задача. З серйозних проєктів знайшов Khoj - в нього є плагін для Obsidian, можливість запускати сервер локально та використовувати локальні моделі. Але сьогодні так і не вдалося запустити його для Obsidian; тільки в режимі дослідження вебу.

Багато часу відняло поєднання Khoj на макбуці з Ollama на Windows; через такі базові речі, як вибір у Windows режиму “приватна мережа” та відкриття фаєрволу для Ollama - бо без того він не був видимий назовні. Також потрібно вказати OLLAMA_HOST=0.0.0.0; для мене найпростіший спосіб це зробити — це з NSSM зробити з Ollama сервіс, а заодно й змінну оточення вказати.

Також виявилося, що моделі для Khoj вже повинні бути завантажені та запущені в Ollama, інакше Khoj тихо відмовлявся працювати. Оце мене у всій цій AI-кухні найбільше дратує — зазвичай в проєктах мінімум зручностей на той випадок, коли щось йде не за планом.

Тепер застряг на тому, що документи з Obsidian ніяк не зʼявляються в Khoj.

А ще, найлегший спосіб погратися з локальними LLM - це LM Studio. Бо це кросплатформенний графічний застосунок, готовий до роботи без всяких налаштувань. Тут можна: спробувати різні моделі, а також їхні параметри; побачити та порівняти швидкодію різних машин; та й просто користуватися чатом.


15.02.2025

Як я користуюся Obsidian

Як подивишся на приклади баз Obsidian - наприклад, в топі /r/obsidianmd - то будеш бачити складні, витончені, застилізовані системи. Тут, я гадаю, доцільна аналогія з автомобілями: ті, хто ними діляться — зазвичай ентузіасти, а у більшості власників машини звичайні нудні, втім — незамінні та люблені.

В мене вже бозна скільки років є особиста база знань, що складається з текстових файлів. Для роботи такої бази потрібна програма зі зручним пошуком. Колись це був Bear, а до того - nvALT, а ще раніше — здається, Vimwiki. Ключовою ідеєю для мене завжди була можливість знайти нотатку через пошук. (Що звучить тривіально, але, наприклад, у VSCode такого пошуку немає: наприклад, коли потрібно знайти два слова, що не стоять поруч.)

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

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

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

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

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


14.02.2025

Obsidian Canvas та Excalidraw

Obsidian Canvas - найбільш успішний з інструментів, що я спробував у 2024. Але в цього доповнення є суттєві недоліки. Головний з них — навіть не брак функціональності (хоча в порівнянні з іншими програмами тут сміховинні можливості стилізації.) А те, що Obsidian Canvas не має відкритих точок розширення. Дарма що це офіційний плагін, документовані тільки його CSS-стилі.

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

Отже, нещодавно я подивився на доповнення Excalidraw. Взагалі Excalidraw це векторний редактор для вебу, а це доповнення інтегрує його в Obsidian (де редактор працює вже з файлами з Obsidian, без жодної привʼязки до якогось сервера). Документи Excalidraw виглядають (примруживши очі) так само як і Canvas. Зате в Excalidraw багатші образотворчі можливості: не тільки вбудована стилізація, а й бібліотека фігур тощо.

Але можливо, головне це те, що в доповнення Excalidraw є відкритий API. Причому, як я розумію, зроблений конкретно для Obsidian.

Також документи Excalidraw зберігаються так, що їхній зміст видно в пошуку Obsidian (а документи Canvas - ні або неповноцінно.) Структура канви й там, і там знаходиться у JSON, з тою різницею, що в Excalidraw він містить більше атрибутів стилю, тому є більшим за розміром.

Я поки не вирішив, чи переїду на Excalidraw. З недоліків: тут немає форматування Markdown прямо на канві та не так зручно робити стрілочки (доводиться кожну створювати окремо, тоді як в Canvas можна одним рухом миші створити вузол, привʼязаний до поточного.)