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

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

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

12.04.2024

З Borland Pascal в браузер

Пʼятничний проєкт: захотілось оживити гру, яку я писав 22 роки тому. Так, щоб можна було поділитися, звісно. Гра була написана на Borland Pascal для MS DOS. (Колись я вже це згадував.

По-перше, як його було запустити або скомпілювати. Переносити код на новішу платформу я точно не хотів — занадто багато зусиль та занадто далеко від оригіналу. Тоді мушу запустити BP, щоб скомпілювати. Як людина, яка багато грає в старі ігри з GOG, знаю, що ДОСівські програми запускають в DOSBox. Але додатково дізнався, що є свіжіша версія - DOSBox-X. З нею я прямо з macOS можу змонтувати в DOS всі потрібні теки, запустити Паскаль та отримати бінарний файл.

Далі можна було б загорнути свою гру в той самий DOSBox, як це робить той же ж GOG, та на цьому зупинитись. Проте на “поділитися” для мене це не витягує. Треба, щоб було в браузері. (От нещодавно син попросив знайти Donkey Kong для Atari 2600, та я швидко знайшов варіант з вебемулятором. Як зараз все просто стало.)

Щоб запустити програму для DOS в браузері, знайшов… той же ж DOSBox, тільки скомпільований у WASM за допомогою Emscripten. Як зараз все просто стало! Майже з першої спроби гра запустилася в браузері.

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


11.04.2024

Експорт даних з OpenSearch

В OpenSearch немає очевидного способу відвантажити зміст бази — такого, як pg_dump, mysqldump або команди \copy. А потреба в такій операції, звісно, є — утворення резервної копії, синхронізація. Нещодавно просто потрібний був експорт даних, щоб проаналізувати їх разом.

Якщо поритися в документації, знайдемо механізм scroll. Він саме і надає можливість забрати з бази не одну сторінку пошуку, а абсолютно всі результати.

Scroll - це особливий режим пошуку; він вмикається опцією scroll в пошуковому запиті. Пошук все одно поверне одну сторінку результатів, але також ми отримаємо вказівник scroll ID, та за наступними сторінками підемо вже в окремий Scroll API.

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

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


10.04.2024

BigQuery Write API як приклад гарного API

Довелося заганяти дані в BigQuery через тамошній Write API. В мене з Google Cloud досвід мінімальний, тому очікувань гарних не було. Був приємно здивований.


09.04.2024

Контексти в Golang, осмислення

Контексти, як і тип error, висвітлюють одну з головних ідіом Go: робити перетік програми очевидним. Навіть в збиток до стислості та легкості написання.

Там, де в інших мовах помилки самостійно “виринають” по стеку механізмом винятків — хтозна-куди — в Go ми примушені перевірити кожну помилку в кожному місці виникнення. Та, в 99% випадків, вручну реалізувати повернення вгору по стеку. (В 1% ми перевіряємо, чи це не io.EOF або ще якась “прийнятна” помилка.) Це найбільше й дратує — що хоч ми робимо перевірки вручну, але практично з єдиним передбачуваним результатом.

Якщо error - це найбільш прозорий спосіб повернути стан з середини назовні, то context.Context - найбільш прозорий спосіб передати зовнішній… контекст всередину коду. Так, це значить, що ми передаватимемо параметр ctx в кожну функцію нашого проєкту, де є бодай одна операція з мережею. Це включає не тільки багато очевидних функцій, але й деякі такі, де, здавалось би, ніякий контекст не потрібен. Наприклад: функція-конфігуратор, яка проміж іншим створює клієнт AWS, повинна передавати контекст. (Ця проблема нагадує поширення async по коду в JavaScript.)

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

Ми всі знаємо, що проблема зависання існує, так само як і проблема несподіваних помилок. Go, на відміну від інших мов, примушує нас не закривати на них очі.


08.04.2024

Бібліотека conc в Golang

Вже другий пост задоволення бібліотекою github.com/sourcegraph/conc. Такі в ній гарні обгортки для типових задач рівночасності.

Цього разу — конкретно про модуль conc/pool. Він реалізує абстракцію “запустити декілька задач рівночасно та почекати на результат”. Ніби для того достатньо стандартного sync.WaitGroup, але то буде примітивне рішення. Доведеться вручну лічити задачі, збирати результати, обробляти помилки…

З conc/pool достатньо запустити необхідні задачі викликом pool.Go(), а потім зачекати — викликом pool.Wait(). Є декілька модифікацій пула залежно від змісту задач: чи повертають вони результат, або помилку; чи потребують вони контекст (з особливою можливістю скасувати контекст після першої помилки.)

conc/pool підходить для ситуацій, коли ми запускаємо різнорідні задачі — приблизно як Promise.all в JavaScript. Та головне, що він робить використання рівночасності легше та простіше. Наприклад, якщо нам потрібно завантажити дві неповʼязані сторінки. Зазвичай така задача надто маленька, щоб розкладати її на горутіни, канали, і все інше. Але з conc/pool майже нічого зайвого писати не доведеться. Просто чудова маленька абстракція.


07.04.2024

Документація

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

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

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

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

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


06.04.2024

Office key у Windows

Колись базовий пакет Windows містив Сапера. У Windows 11 його немає, зате є більш дорослі ігри — в одну з них грав сьогодні, називається “Не увійти в Office 365”.

…Я граю у Windows через Parsec, та мене досить давно дратує, що час від часу в браузері відкривається сторінка “Увійти в Office 365”. Я знав, що вона привʼязана до деякої звичної мені з macOS комбінації клавіш, проте розібрався тільки сьогодні.

Все виявилося ще гірше, ніж я очікував. На клавіатурах для Windows зʼявилася нова клавіша - “Office Key”. Але… чомусь вона не має нового коду клавіші, а емулює натиск Win+Ctrl+Alt+Shift, тобто комбінації, відомої як Hyper key. Але: Hyper key був обраний саме через те, що таких комбінації не зустрічаються у звичайних програмах та можуть бути призначені за власною потребою користувача.

В мене натиск на Hyper (а насправді Caps Lock) перемикає мову на клавіатурі, тобто натискаю я його регулярно, та часто несвідомо. Що, через Parsec, призводить до появи дратівної сторінки.

А тут виходить, що Microsoft вирішили пригребти Hyper key на власні потреби. Та ще й так, що його неможливо перепризначити або вимкнути. (Для порівняння, macOS дає змінити поведінку кожної клавиші-модифікатора окремо.)

Ну як — неможливо… Коли є AutoHotKey, то можливо. Хоча й не очевидно, бо комбінацію обробляє процес Explorer, та просто перехопити її не вийде. Знайшов тред з розвʼязком — я б сам не придумав.


05.04.2024

Як гарантувати імпорт в базу без дублікатів

Є така задача — завантажувати пакети даних в базу. Пакет складається з декількох частин. Інколи програма буде ламатися посередині (а яка не буде?); нам потрібно гарантувати, що жодний пакет не буде пропущений та в базі не зʼявляться дублікати.


04.04.2024

Чому Go вміє форматувати дати "як Ruby?"

Натрапив випадково на те, що в стандартній бібліотеці Go є, проміж різних стандартних форматів, формат дати time.RubyDate. Тільки Ruby - немає всяких PythonDate, JavaDate, або HaskellDate. Хоч це мене, як рубіста, переповнює гордістю, доведеться все ж поставити питання — навіщо?

Щоб відповісти, знаходимо той файл на GitHub та закопуємося в його blame. (Це типова процедура розшуку причини, яку я роблю щоразу, коли бібліотека поводиться незрозуміло.) Корисніше за все тут функція “open blame prior to this change”. Знаходимо коміт, в якому рядок зʼявився, та з нього - PR, в якому той коміт зробили.

Виходить, в далекому 2010 році, за два місяці після випуску мови на публіку, команда Go виявила розбіжність форматування Ruby та стандартного “Unix date”. Як вони її виявили та чому та розбіжність була варта включення в стандартну бібліотеку? Бо в тому форматі повертав дати тогочасний API Twitter. На той час, певно, цього було достатньо, щоб в мові Go зʼявився формат дат “як у Ruby”.

Наразі Twitter API (наскільки він живий?) повертає дати в стандарті ISO 8601. Якого, до речі, в Go немає! Є тільки формат time.RFC3339, який, як я сьогодні дізнався, тільки перетинається з ISO 8601. Бо обидва стандарти пропонують набагато більше єдиного вірного формату. Наскільки більше? Пропоную роздивитись ось цю жахливу діаграму. Форматування часу — це складно!


03.04.2024

Дизайн та юзабіліті скрипту для експорту рецептів

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

Я б хотів його вже опублікувати, але для того доведеться ще попрацювати маркетологом.