Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
09.02.2023
Як приховати ключі AWS та SSH у 1Password
Сьогодні пост про безпеку. Напевно, всі знають, що паролі треба мати довгі, випадкові, та зберігати їх у менеджері паролів. В мене вже 12 років всі паролі лежать у 1Password. Правда, тоді це був приємний додаток для Mac та iOS, а зараз він перетворився в всеплатформенний гігант з фокусом на підприємства. Додаток трохи зіпсувався, чесно, але натомість 1Password набув більше функцій, а в авторів є достатньо інвестицій, щоб підтримувати безпеку. Та це головне - 1Password найбільш надійний менеджер паролів (кажу як людина, яка вивчала їх модель безпеки).
Як одна з функцій — можливість інтеграції в термінал. Утиліта op вміє витягувати зі сховища паролі та підставляти куди треба. А деякі системи авторизації підтримує напряму. Отже,
сьогодні нарешті переніс свої ключі AWS теж у 1Password. Для AWS є плагін, який замінює команду aws на таку, що може забрати ключ з 1Password. На жаль, це працює тільки з командою aws - тобто, наприклад, Terraform ці ключі не знайде. Але в цілому треба розуміти, що як Terraform може знайти твій пароль від AWS, так його може знайти будь-який скрипт — наприклад, скомпрометований пакет NPM.
Також 1Password може виступати як агент авторизації для SSH. Це працює з будь-яким клієнтом SSH, тобто з командою git теж. Замість вводу фрази-пароля доведеться відімкнути сховище та підтвердити використання ключа. До речі, 1Password чомусь не дозволяє зберігати недостатньо надійні ключі. Трошки дивний крок, але немає нічого поганого в тому, щоб перейти на свіжіші стандарти безпеки — наприклад, Ed25519, який я вже бачив у WireGuard.
08.02.2023
Документація по проєкту
Де тримати документацію по проєкту? В мене похмуре передбачення, що як і з системами для керування задачами, тут не знайдеш “приємного” варіанта, бо що не бери — все одно доведеться ту документацію писати. Але все ж дам кілька порад.
Перше та найголовніше — я особисто не довіряю документам, які написані не просто в тексті. Напевно, то інженерна профдеформація. Я розумію, що всі на світі користуються Microsoft Word та всіма його нащадками. Але якщо справа стосується живої проєктної документації, то її я хочу бачити тільки в Markdown. Тільки так можу буту переконаним, що документи можна буде без проблем переносити між інструментами та середовищами, особливо коли вони застаріють та зʼявляться нові. Також, як для мене, просто текст легше редагувати та форматувати. Але одним текстом не обійтися, та треба мати можливість додавати ілюстрації.
Документацію має бути легко писати, бо написання — це вже робота, та до того ж побічна. Тож додати нотатку має бути можливо з мінімумом зусиль. Цю цінність я зрозумів на важкому досвіді, що щоб створювати на кожну зміну Pull Request - ні в кого немає часу. Взагалі Git в прямому вигляді незручно використати — бо треба робити commit, а потім push, а потім може ще й конфлікти вирішувати.
Документацію має бути легко шукати, це не менш важливо. Зміст та навігація — це добре, але на практиці чим більше напишуть (що добре!), тим складніше підтримувати штучну систему організації. Краще, коли можна шукати нотатки за текстом, а також за тегами.
Далі, досить важливо бачити, коли та хто змінював кожний параграф документації. Це потрібно щоб знати, наскільки вона застаріла — бо документація припиняє бути актуальною в момент публікації. А також, добре знати, до кого звернутись за уточненнями.
Документація має бути доступною не тільки інженерам — інакше буде “сіра зона” спільних документів, які житимуть в іншому місці. Наприклад, інструкції для підтримки. Та й взагалі краще не відокремлювати “інженерну” документацію, а тримати все в одному місці.
Ще дуже корисно мати живе редагування документації, щоб додавати нотатки під час нарад та дзвінків.
Який інструмент все це підтримує? Я теж хотів би знати. :)
07.02.2023
Як оптимізація по стеку гуляла
Розповідь про те, як оптимізація по стеку гуляла. Ця історія почалась три тижні тому. Задача стояла покращити швидкодію API (макро)сервісу, тож в таких межах вона й була вирішена. API дійсно став швидше. Про це в минулому пості.
Але, проблеми не закінчились. Проблема раз — метрики швидкодії API стали зіпсовані, бо кожний виклик, де прибраний зайвий запит до бази, зсував середній час виконання вниз. Це не відображало справжнього стану: того, що є такі виклики, які тепер повертають миттєво без запиту, та інші виклики, які тривають так само довго, як і раніше. Проблема два — зайві запити все одно зайві.
Тому пішов далі. Хотів перенести оптимізацію до сервера, що споживає цей API. Це було б досить очевидно. Але якщо відстежити шлях виклику ще далі, то первинне джерело виклику — фронтенд. Тож логічно, що треба припинити запити ще на фронтенді. Ну добре, тут теж можна передати прапорець наявності даних, а потім пропускати виклик, якщо прапорець відсутній. На жаль, просто це зробити не вийшло, оскільки пропущений виклик залишався навічно в стані “Завантаження”. Одне з рішень — можна було б не пропускати, а імітувати виклик.
Проте я вирішив дивитися далі. Чому фронтенд взагалі робить оті виклики, у ситуації, коли акаунт ще не пройшов налаштування? Я подивився на сторінки та зрозумів, що у них відсутній стан порожнього аркуша. Новим користувачам не потрібні сторінки з результатами порожніх викликів. Тож остаточним рішенням оптимізації була реалізація порожнього стану, для якого не потрібно ніяких запитів. Так я не тільки уникнув зайвих викликів, що проходять через декілька сервісів, але й покращив досвід користувачів — як за зручністю, так і за швидкодією.
Зазначу, що таку роботу суттєво спрощує побудова команди з full-stack спеціалістів, тобто саме таких, що володіють контекстом на всіх рівнях. Якби за кожний шар відповідала окрема команда, то системні перетворення були б питанням не кількох годин, а кількох спринтів.
06.02.2023
Як працюють платежі в додатках з Apple App Store
Епловська система платежів працює зовсім не так, як я звик. А до чого я звик? Практично всі платіжні системи, з якими я стикався, працюють за принципом вебхука на довірену адресу нашого сервера. Тобто, спочатку покупець виконує платіж, а потім нам приходить квитанція, яку треба обробити, та надати сплачену послугу. Якщо йдеться про підписку, то потім платіжна система надсилатимете квитанцію регулярно. Таким чином, від нас залишається тільки оновляти статус підписки при отриманні вебхука.
Але в Apple ніякого вебхуку немає. Напевно, це повʼязано з тим, що серверна частина не обовʼязкова для мобільного додатка. Замість того, це ми маємо питати у сервісу покупок, чи не змінився статус підписки. Для цього під час покупки отримуємо довжелезну квитанцію з підписом. Її маємо зберегти в базу, а потім періодично перевіряти. Як часто — вирішувати нам. Ясно, що статус зміниться тільки якщо черговий платіж не пройшов, або якщо користувач скасував підписку. Але щоб не помилитись, просто перевіряємо статус щодня — поки квитанцій кілька десятків, це підходить.
Власне, зачепив цю тему тому, що епловський сервіс перевірки платежів регулярно та ганебно повертає помилку 502. Поки спробую вирішити повторними спробами. Взагалі це не єдина проблема з In-App Purchases. Головна проблема — що IAP це єдиний дозволений спосіб брати гроші з додатка на iOS. Але навіть якщо головний сервіс ми надаємо з сайту (я про Сінтру, до речі), а додаток сам по собі не працює повноцінно, то все одно примусово мали додати підтримку IAP. Причому спочатку коли додали підписки з сайту, то Епл нічого не сказав. Але через кілька місяців, при випуску чергової версії додатка, раптом відмовили через відсутність IAP. Та після цього в нас не залишилось вибору — тільки додати підписку через Епл, або ніколи не випускати оновлення. Так і вийшло, що в нашому мінімальному додатку до вебсервісу все одно є можливість підписки.
До речі, технічних проблем з тим, щоб платити за вебсервіс підпискою з мобільного додатку, немає; під час оформлення підписка привʼязується до вашого рахунку, та рахунок отримує один та той самий статус активної підписки, незалежно від способу оплати.
05.02.2023
Відображення змін файлів з PRу з GitHub
Продовжуються мої експерименти з інтерфейсом для перегляду повідомлень для GitHub. Здобув всі необхідні дані, залишилось зробити базовий інтерфейс та цього буде достатньо.
Складнощі виникли з переглядом змінених файлів. Весь PR можна забрати з API у вигляді diff-файлу - для цього треба зробити запит з заголовком Accept: application/vnd.github.diff. Це розповсюджений формат, який легко показати з підсвіткою, наприклад, бібліотекою Prism. Але ж просто показати зміни недостатньо. Для мене необхідно додавати коментарі на окремі змінені рядки — без цього ніякого огляду PRу не вийде. Тому знайшов інший підхід — бібліотеку gitdiff-parser, яка розбирає Diff-файл на файли, фрагменти, та рядки. Далі залишається їх тільки відобразити.
Може виникнути логічне питання — а як сам GitHub відображає сторінку змінених файлів, та чи можна підгледіти там якесь більш зручне API. Але ні, бо на моє розуміння, GitHub використовує Server-Side Rendering, та повертає вже готовий код сторінки. Попри це, як на мене, сторінки PR працюють з неприємними затримками. Саме тому я думаю, що зможу зробити додаток, що буде приємніше, хоч і з меншим набором функцій. Також, навпаки, можна додати такі можливості, за якими зараз доводиться ходити на інші сторінки — наприклад, хотів би бачити blame для змінених рядків, тобто коли та хто їх змінював перед поточним PRом.
Дізнався про обмеження запитів до API GitHub з персональним токеном. А саме, це 5000 запитів на годину. Тобто можна зробити відразу багато — це добре — але потім доведеться довго чекати. Обмеження щедре, та я його знайшов тільки через багаторазове перезавантаження свого додатка, хоч він стягує по декілька різних запитів на кожне з моїх поточних 75 повідомлень. Але, мабуть, краще впровадити якийсь кеш — напевно, у LocalStorage.
04.02.2023
RSS-стрічка для новин про війну з Реддіту
📢 Сьогодні нарешті публікую RSS-стрічку з Реддіту, яка збирає пости з сабреддітів про російсько-українську війну. Перелік сабреддітів курується мною, тому там є шановний /r/NCD, в якому проміж грубих жартів публікується як не найкмітливіша аналітика в інтернеті. Колись зроблю й інші стрічки, але почав з головної теми.
З попереднього посту про цю стрічку помінялось небагато. Для того, щоб збирати пости з багатьох сабреддітів, створив мультіреддіт — це вбудований засіб агрегації. Також виявив, що власний RSS реддіту взагалі немає сенсу парсити, коли є формат JSON. А далі — пости з мультіреддіту проходять по тому самому алгоритму, що я вже зробив для Hacker News.
Хотів, щоб мультіреддіт не світився в моєму акаунті; але якщо зробити його приватним, то я не зможу витягувати стрічку без авторизації. Тому звернувся до типового для реддіту механізму — створив анонімний акаунт, який і володіє публічним мультіреддітом, та ніяк зі мною не повʼязаний. (Потім випадково забув не тільки пароль, але імʼя користувача, а також адресу електронної пошти — бо вона була прихована через сервіс Hide My Email. На щастя, приховану адресу можна знайти у системних налаштуваннях iCloud, а за нею відновити все інше.)
03.02.2023
Поради як тримати Terraform в простоті
Terraform, хоч і є декларативною мовою програмування, але все ж таки вміє робити чимало функціональних перетворень над даними. Деякі дуже корисні - formatlist допоможе переформатувати рядки за шаблоном, та я часто їй користуюсь — наприклад, щоб перетворити IP на маски мережі командою formatlist("%s/32", local.ips). Повноцінного програмування все одно не вийде, але можна написати досить складні перетворення. (Варто памʼятати, що замість звичної функції map списки відображаються командою for. )
Так я колись витратив пару днів, щоб генерувати правильну розбивку IP адрес за мережами та машинами. По-перше, це зайняло купу часу. По-друге — як тільки зʼявилися додаткові вимоги, адаптувати код не вийшло. Тому що, по-третє — хоча я намагався наповнити код коментарями, все одно було забув, як воно працює, а головне — чому. Як ілюстрацію пропоную подивитись функцію matchkeys - таку езотерику я в повноцінних мовах не бачив.
Тому моя поточна думка — що краще було б вручну задати на прості вихідні дані, а розгорнутий кінцевий результат перетворень. Так, доведеться більше робити вручну. Але головне, що ця конфігурація буде більше схожа на топологію самих ресурсів, а значить, буде легше зʼясувати, що до чого. Що, на мою думку, краще, ніж коли конфігурація проста, але як з неї створюються ресурси — абсолютно незрозуміло. До того ж конфігурацію можна генерувати не вручну, а скриптом, та передавати у форматі JSON.
А ще, в усіх можливих випадках, раджу адресувати повторювані ресурси ключами, а не індексами. Тобто замість метааргументу count вживати for_each.
02.02.2023
Пост симпатій до бази даних Redis
Пост симпатій до бази даних Redis. Всі знають, як використати Redis у якості кеша. Колись давно цю задачу виконував memcached (який ще досі живий!), але зараз всюди, де я знаю, роль кешу зайняв Redis. Та, без заперечення, цю роль він грає чудово. Але Redis вміє набагато більше. Оскільки Redis тримає всі дані в оперативній памʼяті, правильно буде думати про нього не як базу даних, а як зовнішню оперативну памʼять вашого додатка.
Тому Redis ідеально підходить для даних, потрібних в реальному часі. Лічильники, передача повідомлень, таке інше. Порівняно з внутрішньою памʼяттю, Redis буде доступним з різних машин та збереже дані навіть при перезапуску додатка, а також і при перезапуску сервера Redis теж — хоча гарантії надійності тут слабкі, тож для довготривалого збереження краще обрати справжню базу даних.
Насправді у Redis є сила-силенна команд, які уможливлюють складніші обчислення саме на сервері. Наприклад, мені колись довелось використати команди для роботи над бітовими рядками. Цінним є те, що у кожної команди зазначена її обчислювальна складність, тобто можна напевно розрахувати швидкодію майбутнього рішення. Тож, якщо у вас є додаток, скажімо, на Ruby, та потрібно прискорити якийсь алгоритм, то можливо, Redis та його розширені команди — це все, що потрібно. А далі можна навіть перенести алгоритм прямо у Redis, бо він підтримує скрипти на Lua… По цьому шляху я теж пройшов, але нарешті вирішив переписати все на Go - проте прототип вийшов чудовий.
01.02.2023
Як переконатись, що архітектура витримає? Йти від зворотного.
Продовжуючи тему про стрес-тести — як все ж таки переконатись, що архітектура витримає навантаження, якого у вас зараз немає навіть близько? Я пропоную виходити зі зворотного. Чого ваша архітектура не витримає? На мою думку, це питання менш абстрактне, та тому з ним легше впоратись — та навіть перевірити.
Багато де межі дійсно немає — наприклад, при можливості лінійного масштабування, це просто питання грошей. Тут епоха хмарної архітектури відкрила для нас суцільно нові проєкти, бо до появи AWS та іншого масштабування закінчувалось на одній або декількох машинах, а далі — вже зовсім інші витрати. Також є глобальні хмарні сервіси, такі як AWS Kinesis Firehose, які мають абсолютно космічні межі використання, тому на них можна впевнено покластися (теж за гроші, звісно.)
Інколи рішення працює для будь-яких обсягів, але впирається в фізичну межу. Так, база даних зі зберіганням у памʼяті (Redis) чудово працюватиме, поки влазить в памʼять однієї машини. Проте памʼять машини — це вже не 640Kb з відомої цитати Біла Ґейтса, а, у випадку AWS ElastiCache, до 640 ГІГАбайт. Тож влізти може багато.
Та, нарешті, є багато підходів, які масштабуватись не будуть, а працюють зараз тільки через низький обсяг клієнтів (або ж взагалі до появи справжніх клієнтів.) Наприклад, якщо ми свідомо знаємо, що складність обробки зростає як квадрат кількості користувачів. Так, з 10 тестовими користувачами все працює добре — але ж на 10 тисяч ми ніяк не вийдемо. Сучасні програмісти рідко пишуть щось складне, але ось накоїти проблем в базі даних — це ми можемо.
Коротше, чесному інженеру на відкрите питання “чи все буде добре” відповідати складно. Краще перетворити його на “що піде паскудно”.
31.01.2023
Перший місяць користування блокнотом для самоменеджменту
Вже цілий місяць я веду свої справи по блокноту. Не кинув поки! Що стало несподіваною перевагою — блокнот дуже добре ізолює увагу. Порівняно з телефоном або ноутбуком, коли працюєш з блокнотом, то немає на що відвернутися. Бо, мабуть, у всіх бувало так, що взяв в телефон у руки — а через пʼять хвилин вже згадуєш, для чого. Тому щоранку я роблю каву та сідаю за блокнот писати справи на день, а потім вже лізу в інтернет. А якщо все добре, то щовечора перед сном також записую все, що крутиться в голові. Така собі медитація на блокнот виходить.
Як на мене, то у самоорганізації є етапи. На початку в голові є декілька гострих, важливих задач, заради яких зазвичай і починають щось записувати. Коли з гострими задачами закінчено, раптом виявляється, що в тебе купа ідей, які припинили бути репресованими теми гострими, і також хочуть бути записаними та зробленими. На цьому етапі в мене ідеї просто фонтанують десятками. Далі, третій етап — все, що записано, вже неможливо зробити ані сьогодні, ані завтра; тут зʼявляється список проєктів та набирає чинності якесь розставляння пріоритетів. (Я зараз тут.) А після того, як здобуваєш певну кількість результатів, стає питання вищого порядку: навіщо все це, і куди я рухаюсь? Тут вже треба розбиратись з довгостроковими цілями, а також зонами відповідальності. На цьому моє розуміння поки закінчується.

