Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
09.06.2023
PostgreSQL vs Elasticsearch
Поступив запит: чим Elasticsearch краще за PostgreSQL. Спробую сформулювати. Наперед скажу, що питання скоріше не чим, а де або для чого.
Постгрес — це база даних загального призначення. Вона вміє все. Та з кожною новою версією ще більше. Якщо порівнювати суто по можливостях, то з PostgreSQL можна робити що завгодно. В цьому його головна перевага. Якщо з чогось починати проєкт, то Постгрес найкращий вибір, завжди (якщо в бюджеті є місце для сервера бази даних, звісно.)
Єдине, що PostgreSQL робить гірше — це масштабується. Рішення для горизонтального масштабування існують, проте коли вертикальне (збільшення машини) не розв’язує задачу, то, на моєму досвіді, всі обирають поміняти базу. Наскільки вистачить однієї машини — залежить від того, що потрібно зберігати. Для облікових записів користувачів — напевно, вистачить назавжди. А для, скажімо, щосекундних аналітичних метрик — може й для старту буде мало. Бо як БД загального призначення, у PostgreSQL доволі обмежені здібності оптимізувати під задачу.
Як я вже писав, для вирішення сучасних потреб в масштабуванні зʼявилися бази даних NoSQL. В їхньому числі й Elasticsearch (так, як я вже писав, Elasticsearch - справжня база даних.) В серці кожної NoSQL бази сидить компроміс: так, вона масштабується, але характер використання буде обмежений. Тому, при виборі NoSQL бази, треба дуже уважно дивитись, що вона вміє, та чи не буде вам потрібно щось інше.
Elasticsearch вміє класний складний пошук та агрегації. При цьому його легко масштабувати як на запис, так і на читання. Як приклад того, що він робить погано: поєднання документів на кшталт JOIN
. Тобто в базі мають сидіти документи, які нас цікавлять самі по собі.
Такий режим використання гарно себе показав для всілякої журнальної інформації, тому зараз більше можна побачити Elasticsearch як базу даних для журналів, ніж як пошуковий рушій (бо, якщо все, що вам потрібно — це повнотекстовий пошук — то його чудово вміє робити Postgres.)
На останнє, не раджу читати абстрактні порівняння вигляду “знайди 10 відмінностей”. “PostgreSQL - реляційна база даних. Elasticsearch - документна” і так далі. З таким підходом в сучасних базах (та й взагалі технологіях) швидко загубишся. Щоб обрати базу, треба розуміти, що вона робить краще інших, та може ще важливіше — чого ніяк не робить. А якщо є сумніви — беріть PostgreSQL. :)
08.06.2023
Кілька думок про Docker Compose
Сьогодні був день Docker Compose. Як я вже писав, в нас багато на нього навішано. Взагалі, як на мене, якщо вам доводиться працювати над системою складніше, ніж класичний LAMP-стек, то варто опанувати Docker Compose та відтворити на ньому архітектуру.
-
Софт, запакований в Docker, не завжди працює так, як написано в документації. Різні постачальники Docker-образів можуть по-різному налаштовувати один та той самий софт — інколи це буває корисно, інколи шкодить, але головне памʼятати, що розбіжності існують та поглядати на вихідний Dockerfile. Є й софт, який взагалі на Docker не розрахований та працюватиме погано або ніяк.
-
Цілком можливо мати декілька проєктів в одній великій мережі сервісів. Для цього треба явно задати мережеві налаштування. Це зручно, коли маємо справи з декількома репозиторіями, та хочеться
docker-compose.yml
тримати біля проєкту. -
Відкриття дня — в графічному інтерфейсі Docker для macOS надзвичайно зручний інспектор запущених контейнерів. Тут не тільки можна фпереглянути логи та налаштування, а й навіть зазирнути в файлову систему — причому кращого способу це зробити я не знаю. Реально вже сьогодні дізнався нового про свої контейнери (а саме, що варто вичищати логи після збірки.)
07.06.2023
Kafka
Тиждень тому я писав про важливість перенесення навантаження з критичного шляху. А також про те, що це вирішується чергами. Черга надає можливість передати роботу з одного сервісу до іншого. Але є проблема — черга це труба о двох кінцях. Нам обовʼязково доведеться створювати споживача “в пару”. Черга створює жорстку звʼязку сервісів.
Apache Kafka розв’язує цю проблему. Це дещо середнє між чергою та базою даних. Як в черзі, дані організовані в послідовність повідомлень. Як в базі даних, ці повідомлення надійно зберігаються миттєво після приймання, та не видаляються після їх прочитання та обробки. Категорія сервісів, до яких належить Kafka, називається брокер повідомлень. Один сервіс (або сервіси) повідомлення пише, інший (або інші) читають - все з надійним посередником посередині.
Як на мене, то в першу чергу Kafka корисна тим, що дозволяє високонавантаженому сервісу максимально швидко писати дані, без того, щоб відразу розробляти архітектуру їх обробки. Це й спрощує розробку, й підвищує надійність, і взагалі в наш час Big Data розкриває нові можливості збирати те, що незрозуміло як використати.
Але є й інші переваги. Kafka може роздавати одній й ті самі повідомлення декільком споживачам — наприклад, сьогодні вони потрібні тільки в базі, а завтра, може, зʼявиться сервіс аналітики.
Також є прості, але можливості обробляти дані всередині Кафки, наприклад, рахувати їх, або обчислювати кінцевий стан сутності по журналу змін - Kafka Streams. Та Kafka Connect - інструмент для завантаження даних з Кафки до звичайної бази даних або ще кудись.
Єдине, що мені не подобається — все воно написане на Java, з усіма особливостями конфігурації та розміщення сервісів на Java.
06.06.2023
Перша засада гарної доповіді — думай про аудиторію
Сьогодні слухав на роботі презентацію про те, як робити презентації. Причому фокус був на робочих дзвінках, які є повсякденністю для нас всіх. Задумався, які поради я можу додати зі свого боку.
На мою думку, головне, про що треба думати при плануванні доповіді (формальному плануванні, чи в голові за пʼять хвилин — це вже як піде) - це аудиторія. Бо предмет робочої доповіді нам зазвичай добре відомий. Але що з нього розказати? Я нерідко бачу, як люди закопуються в деталі, які нікому окрім них не зрозумілі, або навпаки, зазначають, що за два тижні рівно нічого цікавого не відбувалось. Тому, щоб підготувати себе, пропоную пару питань:
-
Що аудиторія знає? Наскільки вона володіє контекстом? Чи це люди, з якими ти працював вчора, або навпаки, далекі від проєкту? Чи знають слухачі місцевий жаргон? До якої спільної бази можна привʼязати предмет доповіді?
-
Чого аудиторія хоче? Тут може бути багато варіантів, як не дивно. Може хочуть більше деталей та обґрунтувань. Або отримати загальну картину. Або відчути, що є прогрес та ситуація під контролем. Так чи інакше, наша доповідь має відповідати потребі слухача, або нас просто не будуть слухати, свідомо або несвідомо.
З таким фокусом в голові вже можна підходити до предмета доповіді та планувати, на яких аспектах можна зупинитись. А ще зорієнтованість на аудиторії сприяє рапорту більше, ніж правильний кут камери або уникнення слів-паразитів.
Раніше: про логічні ланцюги.
05.06.2023
Що робити з валютами
В продовження теми про зберігання фінансових значень, розповім трохи про валюти.
Наївне уявлення про валюти досить просте. Є одна валюта, є інша, є курс. Пазури програміста вже тягнуться до StackOverflow, щоб знайти там зручний API. Та й нескладно знайти багато джерел поточного курсу валюти. Є безплатні, є за підписку — гроші зазвичай беруть за частоту оновлень.
Проте така модель не проходить базової перевірки. Єдиного курсу валюти немає. Є міжнародний курс, є курс Нацбанку, є курс твого банку чи обмінника на куті. Який правильний? Відповіді немає. Точніше, реальний курс валюти існує тільки в момент обміну.
Тому що робити з валютою, залежить від конкретного застосунку та його бізнес-логіки. Якщо треба просто приблизно показати суму в іншій валюті — підійде один з API з курсами. Якщо це магазин — то у платіжної системи можна дізнатись точний курс. А якщо маємо справи зі справжніми банківськими операціями — то курс є властивістю операції та має бути вказаний явно.
В Сінтрі до розділу “Накопичення” валюта була суто косметичним елементом. Та поки не треба переводити з однієї валюти в іншу, цього достатньо. Але накопичення можливі не тільки в валюті бюджету, як всім нам знайомо. Ми вирішили під час створення внеску в накопичення відразу питати дві суми — скільки (умовно гривень) пішло з бюджету, та скільки (умовно євро) зайшло як внесок. З першого погляду, це можна було б автоматизувати, але насправді ні — коли відкладаєш гроші, потрібна реальна сума на руках, а ніяке не наближення.
04.06.2023
Зберігайте гроші в цілочисельних значеннях
Ми в Сінтрі зберігаємо всі грошові суми у цілочисельній формі, тобто як значення в копійках. Це важливо не тільки для проведення арифметичних операцій, а й для збереження та відтворення значень. Дробові числа ніколи не можна використовувати для точних обчислень, спробую пояснити, чому.
На перший наївно-освічений погляд, яка там різниця — адже 1.23 гривні
це теж саме що й 123e-2
, в науковій нотації. Але це тільки абстракція про людські очі. Насправді дробові числа зберігаються у двійковому вигляді, з двійковою експонентою, а ніяк не десятковою. (З 2008 існує десятковий стандарт, але на практиці його ніде не побачиш.)
Чому це має значення? Для цілих чисел двійкове зображення нічого не змінює, та ми можемо практично про нього не знати. Але з дробами все не те що гірше, воно дуже погано. Десяткові дроби, як правило, не перекладаються в красиві та акуратні двійкові дроби (пояснення виходить за рамки цього короткого оповідання.) Навпаки, типовий десятковий дріб стає періодичним двійковим. Так що ті 1.23
гривні у двійковій системі мають вигляд 1.00111010111...
. При запису нескінченного дробу в скінченну памʼять ми обовʼязково втрачаємо точність.
При цьому при перетворенні округленого значення в десятковий вигляд ми можемо отримати вже інше значення: 1.23046875
. Принаймні все двійкові дроби стають скінченними десятковими (хоча це мало нам допомагає.) Також добре, що такий десятковий дріб вже нормально вкладається у двійковий… якщо його не округлити в десятковому вигляді. Також точність втрачається на будь-якій арифметичній операції, навіть на додаванні.
Так на кожній операції значення поступово псуються, або, як то кажуть, гниють. Це не якесь теоретичне занепокоєння — ми стикнулись з ним вже на перших місяцях внутрішнього тестування. Після цього всю математику перевели на цілі числа, які стають дробами тільки для відображення їх в інтерфейсі.
Звісно, ми не можемо зберігати дробові значення копійок. Проте, як виявляється, реальні дробові копійки не існують. Та, хоч теоретично можна, скажімо, рівно поділити 1000 гривень на 7 днів та забюджетувати 142.85714286… на день, практично це не має жодного сенсу; фактично ми округляємо до 142.86 та коректуємо останній день, щоб вписатися в початкову суму.
03.06.2023
Поєднання HomeAssistant, Firebase та SwiftBar: коли системи працюють на тебе
Приємне: віддалений геймінг з Parsec працює краще, ніж я міг собі уявити. В локальній мережі з дротовим підключенням взагалі непомітно, що граєш віддалено. Але не тільки — навіть за 200 км від дому та по вайфаю все ще можна грати із задоволенням! Так, час від часу підключення гальмує, але достатньо рідко щоб це не шкодило. Рекомендую.
Є тільки одна проблема: той самий компʼютер може використовуватись й напряму. Та Parsec не пропонує способу дізнатись, чи зайнятий він, чи ні. Щоб уникнути незручних ситуацій, вирішив зробити для себе індикатор.
-
Стан компʼютера, а точніше, стан медіацентру, до якого він під’єднаний, знає Home Assistant. Чого я точно не хочу робити, так це відкривати розумний дім в інтернет. Кількість вразливостей неможливо осягнути. Тому замість того обираю інший підхід — нехай Home Assistant сповіщає зовнішній сервіс про стан медіацентру. Для цього є інтеграція RESTful Command. Якщо дуже спрощено, то я створив пару автоматизацій, що спостерігають за джерелом зображення, та роблять відповідні HTTP виклики.
-
Куди підуть виклики? Для цього перевірене рішення - Firebase. Він надає відразу й функції, й сховище, та все це безплатно. В мене навіть проєкт вже готовий з минулого разу. Зробити функцію, яка записує в Cloud Firestore стан компʼютера — справа на пʼять хвилин. До речі, для такого проєкту на одного користувача для авторизації мої функції просто мають секретні назви з кодом всередині.
-
Нарешті, як перевірити поточний статус? Сам інтерфейс Firestore його показує — до речі, як я виявив, він навіть оновляється наживу, що допомогло в тестуванні, бо я міг перемикати налаштування медіацентру та миттєво спостерігати за результатами. Та заходити щоразу в вебконсоль Firebase - незручно. Тому зробив ще одну простеньку HTTP-функцію, та скрипт для Swiftbar, що її викликає. Знайшов, що якщо у Swiftbar вжити суфікс
|refresh=true
, то по клацу елемент просто оновлюватиметься. Дуже зручно.
Тепер я можу легко перевірити, чи не зайнятий компʼютер, перед тим як підключатись в Parsec. І на це пішло небагато часу, бо рішення складалося з частин, що в мене вже були, та треба було тільки поєднати їх між собою.
02.06.2023
Корисні оповіщення
Сьогодні читав статтю DevEx: What Actually Drives Productivity та мою увагу звернув один проблемний робочий момент. Читав я тому, що чекав завершення задачі (в Terraform.) А коли вона завершиться — не знав; треба було не забути поглядати в термінал. Так можна забутися та надовго полишити роботу. В контексті статті — це поламаний Feedback loop.
Ба — та це ж ідеальна ситуація для застосування оповіщень! Нехай коли команда в терміналі завершується, то система мені нагадає. Я не люблю оповіщення, бо вони відвертають від роботи, але в цьому випадку навпаки, допоможуть до неї повернутись.
На щастя, я не перший таке придумав. Для моєї улюбленої оболонки fish
є плагін done Для zsh є аналогічний zsh-notify, але я сам не перевіряв. Ще VSCode вміє видавати звуки на закінчення команди, та мені віконце оповіщення більш до вподоби.
До речі, самі оповіщення уможливлює утиліта terminal-notifier, яку можна легко застосувати у своїх скриптах. Єдине, що вона потроху старіє, а надійної заміни я не бачу.
Взагалі цікава стаття, на мою думку кожна команда може сформувати для себе набір KPI-індикаторів, щоб не ходити по колу нескінченних проблем на кшталт “доводиться довго чекати схвалення ПРів”, які виправляються, та через місяць-два підіймаються наново. Якби були показники, то можна стежити постійно та не доводити до критичного стану.
01.06.2023
Коротке розслідування в те, як Facebook збирає інформацію
Цікава подія трапилася: показав дружині крісло (до речі, безплатна реклама - home-club.com.ua - надійний спосіб замовити щось з Ікеї в Україні.) А ввечері то саме крісло зʼявилося у дружини в рекламі на Фейсбуці. При тому, що показував я на своєму компʼютері та ніякої очевидної передачі даних не було.
Що за екстрасенсорні здатності проявляє фейсбук в цьому випадку? Чи почув нашу розмову, наприклад? Мені здається, можна пояснити й простішими технологіями.
На сторінках Home-Club є скрипт фейсбуку. (Що логічно, раз вони запускають там рекламу.) Тобто фейсбук знає, що я дивлюся цю сторінку. Але до чого тут дружина? Тут є нюанс. Я взагалі фейсбуком не користуюся та активного сеансу не маю. Тому приєднати відвідування сторінки до мене не вийде. Але ж на той самій домашній IP адресі сидить дружина. На мою думку, тому подія записується на той обліковий запис, що можна привʼязати до IP адреси, та далі сприяє появі товару в рекламі.
Я б хотів звернути увагу на те, що збір аналітики йде далі, ніж просто “записати, які сторінки ти відвідував”. Вони збирають максимум даних та колупаються в них, щоб вичавити корисну інформацію. Щоб запобігти цьому, треба користуватись блокувальником трекерів та реклами (реклама та трекери йдуть рука об руку.)
До речі, в мене взагалі мають бути заблоковані всі трекери, аж два рази — або вбудованим захистом Safari, або 1Blocker. Але з усім тим вкладка “Мережа” інструментів розробника чітко вказувала на взаємодію з фейсбуком. Виявилось, що після оновлення 1Blocker необхідно відкрити один раз сам додаток, щоб він завантажив правила. Бо сучасні блокувальники реклами не втручаються в роботу браузера, а передають йому інструкції про те, які ресурси блокувати. Такий підхід практично не витрачає додаткових ресурсів.
31.05.2023
Оптимізація критичного шляху
Трохи міркувань з приводу дизайну архітектури навколо критичного шляху. Це така ділянка коду, який викликається найчастіше та містить головну бізнес-логіку вашого сервісу. Наприклад, в Телеграмі критичний шлях — це відправлення повідомлення. Чи є він у вас? Варто замислитись, якщо не знаєте.
-
Критичний шлях має проходить через якнайменшу кількість компонентів. Це звучить трохи тривіально. Проте насправді такий підхід йде всупереч класичному дизайну, де відповідальності розподілені по сервісах. Раджу критичний шлях зафіксувати як неподільне ціле, а все інше вже можна розкладати, як зручно. Також критичний шлях — гарний кандидат на винесення в стислий сервіс швидшою мовою програмування, такою, як Golang.
-
Все, звідки відбувається читання на критичному шляху, має бути закешоване. Або мати швидкодію та здатність до масштабування, порівняну з кешем. Кеш не обовʼязково має бути довготривалим — навіть кешування на 1 хвилину здатне перетворити високе навантаження в помірне. Потреба тут не стільки у швидкості, навіть, а в надійності.
-
Всі некритичні операції запису мають бути приховані за чергою. Взагалі черги — гарний механізм перенесення “тиску” між сервісами. Більш звично бачити чергу у випадку довгих задач. Але на критичному шляху навіть запис в базу може бути надто повільною операцією. Особливо коли потрібно спочатку прочитати старі дані, щоб їх оновити… якщо воно не потрібно для відповіді на запит, прибираємо в чергу.
На останок, не треба всього цього робити з MVP. Достатньо заздалегідь усвідомити, де той критичний шлях пролягатиме. Окрім витрат на передчасну оптимізацію, доробляти вже зоптимізований код завжди складніше.