Канал
У Льоні сьогодні
Нотатки архітектора систем та майстра на всі руки. Що я зробив, що з того вийшло, і що це все значить.
-
DSA для App Store - нарешті пройдено!
Майже рік рівно минув з того дня, як я почав виконувати вимоги для публікації в європейських App Store, а точніше, вимог Digital Services Act. А саме, того, що я повинен публікувати контактну адресу та телефон — щоб обурені користувачі могли написати мені паперового листа. От, нарешті, вчора мені погодили та мої застосунки повернулися в App Store.
З контактним телефоном та тим паче імейлом ніяких проблем немає, як я писав минулого разу. Зате з адресою — проблеми величезні. Справжню адресу я публікувати точно не збирався. Потрібна інша адреса, документально затверджена.
Початковий план був — відкрити абонентську скриню. Укрпошти, звісно, бо іншої офіційної поштової системи в нас немає. На жаль, тут ціла низка проблем. Почнемо з того, що я поки не отримав на неї жодного листа! Хоч і намагався. По-друге, підтримка Укрпошти мало допомагає (і це на місцевому головпоштамті, а не у випадковому відділенні.) За регламентом я можу отримати паперовий договір про оренду. Але його видають не то тільки юрособам, не то тільки в Києві, мені так і не вдалося отримати чітке пояснення. Зрозуміло тільки, що абонентська скриня мені не допоможе.
Дуже хотілося б почути від когось про успішний досвід з цими скринями, та зрозуміти, що ж я упустив.
Якийсь час я шукав варіанти представництва чи посередництва, щоб адреса була не моя, а умовного секретаря десь у Європі. Такої послуги не знайшов.
Тоді, нарешті, здався та пішов прямим шляхом. Спочатку — орендувати офіс. Як виявилося, є така послуга — віртуальний офіс, або юридична адреса. Це справжня фізична адреса, на яку може надходити кореспонденція, але без привʼязаної “житлової площі”. Коштує це кілька тисяч гривень на рік, тобто навіть дешевше, ніж той Apple Developer Account, якщо вже порівнювати.
Головне для мене, що оренда юридичної адреси значить отримання договору, на якому написано, що вона моя. Втім, тут чекав наступний етап квесту: Apple не приймає документи українською. Або принаймні попереджає, що “я беру відповідальність за автоматичний переклад”, але фактично підтримка закривала мій запит без нотаріально завіреного перекладу.
Що ж, йдемо далі прямим шляхом та замовляємо переклад. На то є онлайн-агенції, не потрібно навіть ходити нікуди. Агенція перекладає та навіть надсилає завірену копію Новою Поштою. Хоча мені, звісно, достатньо й PDF, який я й надіслав черговим запитом до Apple.
Якщо думаєте, що того було достатньо, то залишився останній бос: пояснити підтримці, що власне складає з себе документ. Бо якщо я правильно зрозумів, вони не дуже вдивляються. Я навіть подумав, що знову не вдалося… аж от після пояснень мені погодили!
Тепер, сподіваюся, воно того було варте. Потрібно лише відбити витрачені гроші продажами у ЄС. :)
-
Чому я не роблю власних проєктів на Ruby on Rails
Хоч я вже… дай порахую… років 16 чи 17 працюю із Ruby on Rails, всі власні проєкти на цьому фреймворку давно згорнулися. Та починати нові я не сподіваюся. Теж саме стосується й Mastodon та будь-яких інших продуктів OSS.
Все через те, що Rails - дуже “важка” технологія, щоб її хостити. Перше, що помітиш — вона потребує купу оперативної памʼяті. Просто, щоб застосунок був запущений. І це відразу збільшує ціну хостингу, навіть якщо застосунком ніхто не користується. Також до Rails доведеться додати базу даних, яка теж любить памʼять.
Для комерційного продукту хостинг Ruby on Rails цілком прийнятний та з масштабуванням ця проблема памʼяті скоріше зникає, бо памʼять іде на базовий стан застосунку, а не на обробку запитів. Зате для розробки як хобі кожний застосунок на Rails буде бити по кишені. Власне, через це я поступово закинув всі свої проєкти на Rails, або переписав.
А ще мені ніколи не подобалося, що для розгортування Rails потрібно завантажити на сервер вихідний код кожної залежності. Хоча ця проблема шириться на всі інтерпретовані мови. Я, особисто, люблю коли проєкт компілюється в один файл.
Треба зазначити, що останнім часом є покращення - Ruby on Rails 8 минулого року зробили кілька кроків до повноцінної підтримки SQLite; позаминулого зʼявилася офіційна підтримка Docker (краще дуже пізно, ніж ніколи.) Але моя думка залишається незмінною.
-
Як працюють Apple Shortcuts
Трохи вирішив зʼясувати, як воно все влаштоване. Звідки беруться дії в Shortcuts та як додати власні?
(Якщо ти ніколи не бачив Shortcuts: це система візуального програмування, недалека від Scratch. Там є зручності імперативного програмування — змінні, умови, цикли. Але головним чином програма складається з викликів дій різних застосунків та передавання даних між ними.)
Виявляється, під капотом в Shortcuts сидить фреймворк
App Intents. Це повноцінна модель API для твого застосунку. В прямому сенсі — через Intents можна експортувати виклики функцій з параметрами та навіть із власними типами даних. Та ще й документувати їх. Та відповідальні розробники цим користуються.Приємно, що App Intents побудований на Swift, бо минула технологія - AppleScript - потребувала неприємних файлів конфігурації, які я так і не опанував. А також, як і більшість сучасних технологій Apple, код App Intents працює на всіх платформах.
Також App Intents неначе можна викликати ще й через Siri та Spotlight, але я, чесно, ніколи цим не користувався та навіть про це не знав.
Затьмарює тільки те, що застосунки не можуть викликати дії інших застосунків напряму. Це дозволено тільки системним інструментам. Як я розумію, задля безпеки — бо моделі дозволів тут немає (та не потрібно, поки кожна дія викликана користувачем.) Зате застосункам доступні готові скрипти Shortcuts. Ба більше, для них навіть є CLI. Але спочатку користувач мусить сам створити цей скрипт.
-
Система пріоритизації WiLSoN
Вигадав для себе систему пріоритизації задач на заміну старої Must, Should, Could, Won’t. Ну бо не тільки скорочення не подобається, але ще й така схема оцінювання часто дає хибу: наприклад, в проєкті може бути багато задач Must для остаточного випуску, але не потрібних для MVP. Різниця між Should та Could надто розмита та мало корисна. А Won’t хоч звучить красиво, але рідко застосовується за призначенням, бо шкода відмовлятися від непрактичних, зате привабливих смаколиків.
А головне, для мене, що ця система мало казала про порядок виконання задач. За довгі роки практики я ледве можу згадати випадки, де я робив Must перед Should тільки тому, що це Must. Тому у своїй системі я приділив увагу саме порядку виконання.
Wild - дико — це задачі, які може й звучать цікаво, але зовсім нереалістично. Може, це величезна купа роботи. Може, це щось не дуже цінне. Одним словом, балансу “ціна-вигода” тут немає. Такі задачі можна переглядати раз на квартал, бо згодом нереальне може стати досяжним, та й пріоритети змінюються. (Звісно, зовсім зайві задачі немає сенсу зберігати.)
Later - потім — тут те, що ми точно хочемо зробити, але з якоїсь причини незрозуміло, коли. Знову — може, це великий вклад зусиль, а може, зараз ця задача не в пріоритеті та є щось важливіше. Цей список переглядаю раз на місяць — якщо справи рухаються, то його рано чи пізно треба зробити.
Soon - скоро — ці задачі ми готуємо до виконання, бо час для них настав. Але вони не горять та можуть почекати, поки звільниться ресурс. Власне, наявність цього списку каже, що ресурс в нас не нескінченний, та краще не починати нових справ, доки не закінчиш початі. Втім, має сенс детально планувати ці задачі вже зараз, зокрема щоб більше про них зрозуміти… та можливо, відкласти на потім? Або переглядати раз на тиждень, щоб поступово починати.
Now - зараз — це або те, що ми вже робимо, або те, що мусимо почати негайно. Звісно, хотілося б щоб задачі починалися тільки заплановано, але всі знають, що щодня на тебе звалюється щось нове та негайне. Як писав вище, важливо розрізняти, що дійсно потрібно вже почати, а що почекає своєї черги.
А разом ці категорії складаються в красиву назву WiLSoN. По-перше, порядок літер тут вірний. По-друге, голосні навіть правильно продовжують слова (
WildтаSoon.) По-третє, Wilson навіть має непоганий тематичний зміст: “народжений волею”. Ще б перекласти влучно українською — та я був би повністю задоволений. -
Робота з Apple Reminders через Shortcuts
Вже писав, що користуюся Apple Reminders. Зокрема, для сповіщень за геолокацією. Гадаю, краще нехай це вже робить вбудований застосунок.
Сьогодні мав думку використати сповіщення за локацією, щоб не забувати про особливо злу яму на дорозі. В теорії, Reminders з цим легко впораються. Є тільки одна проблема: чомусь в застосунку немає можливості вказати довільну локацію. Тільки пошуком за адресою. Вибору на мапі теж немає. Ну і як мені вказати випадкову точку на трасі?
(Ситуація доволі безглузда, бо нагадування будуть працювати з будь-якою адресою. Я б зрозумів, якщо було б тільки нагадування “вдома” чи “на роботі”, але ж ні! Чому тоді не можна вказати координати?)
Нарешті знайшов рішення: Apple Shortcuts! Бо тут є дія “Перетворити текст на URL Apple Maps”. Зокрема, і координати вона підтримує. (Адресу чи інший пошуковий запит — теж.)
А потім той URL Apple Maps можна передати в дію “Створити нагадування” та… створити нагадування. Тут все логічно. І все! Нагадування створено. А напряму через застосунок Reminders вказати URL локації не можна, я перевіряв.
Ось така дивна ситуація - UI продукту Apple не дотягує, зате автоматизація від тих же ж Apple заповнює діри та робить неможливе можливим.
-
Зони відповідальностей
Раджу провести таку вправу: перелічити власні зони відповідальностей. Зона відповідальності — не обовʼязково значить, що ти єдина особа, відповідальна за цю зону. Таке визначення більш корисно для менеджменту. А для мене (та за GTD) ці зони ділять не підприємство, а твої власні турботи та прагнення. Тобто зони відповідальності — це вичерпний перелік всіх сфер життя (в даному разі — робочого), де можуть виникати нові справи (проєкти).
Ось (неповний) перелік моїх зон з роботи:
-
Розробка нового функціоналу. Це як найбільш очевидне та те, на що формально мене наймали.
-
Третя лінія підтримки. Дослідження проблем клієнтів, які виявилися достатньо складними та ймовірно викликані помилками. А може, браком можливостей, про що теж треба зробити опосередкований висновок.
-
Інструменти та середовище розробників. Швидкість та стабільність CI, зручність та повнота локального запуску. Розгортування. Всілякі лінтери-шмінтери.
-
Якість коду. Оновлення залежностей. Впровадження логування та метрик. Безпека коду. Спостереження та оптимізація.
-
Виправлення технічного боргу. Широка категорія, куди я відношу задачі типу “воно повинно бути так, але поки є сяк.” Не обовʼязково це щось свідомо “недороблене” - часто вже після розробки виявляється, що можна було зробити краще. Для кожного підпроєкту власний список.
-
Лідерство. Підтримка роботи інших розробників, перегляд планів та коду, консультації. Розшук та впровадження нових підходів та технологій.
Аксіомою роботи є те, що тебе наймають робити одне, але зрештою перелік обовʼязків розширяється. Тому корисно інколи робити такий “аудит”.
-
-
Коли не треба очікувати впорядкованості
Є такий момент у програмуванні, що оскільки ми можемо перелічити колекцію, то це натякає на наявність порядку. Бо перелік завжди відбувається в якомусь порядку! Важливо памʼятати, що не всяка колекція має порядок, та знати, які приклади з твого середовища його не мають (або навпаки, мають.)
Проблема ускладнюється тим, що рідко яка колекція повертає елементи у випадковому порядку. Навпаки, більшу частину часу ми будемо бачити саме той порядок, який очікуємо. Наприклад, порядок, в якому ми додавали елементи. Аж поки у підступний момент не випаде інший та не зіпсує нам всю логіку.
Наприклад: структура даних словник (вона ж
hash) наче зазвичай не є впорядкованою. Але в ній можна перебрати елементи. Та скоріше за все, вони повернуться в порядку додавання. Тільки покладатися на це не можна. Чи можна? В Ruby та Python цей порядок гарантований мовою! А в JavaScript чи Go - ні. Ото й кажу — знай своє оточення.Також реляційні бази даних не мають ніякого “порядку за замовчуванням”, а вертають результат запиту в довільному, зручному для бази порядку. Може це в порядку за ключем. А може, це лише збіг, бо насправді — в порядку додавання. А взагалі не варто відгадувати, треба явно задавати порядок командою
ORDER BY, якщо він тобі потрібний.Коли архітектор серйозно ставиться до цієї проблеми, то порядок перебору буде дійсно випадковий, щоб на нього ніколи не можна було покластися. Мені відомо, що саме так робить Go - ось живий приклад, де кожен запуск дасть інший порядок ключів.
-
Модуль encoding/json/v2 в Go
…А головне що мені, щоб читати довільні атрибути JSON, довелося ще й використати новинку.
Місяць тому вийшов Go 1.25. Проміж іншим, там зʼявився новий модуль для роботи з JSON -
encoding/json/v2. За домовленостями Go це як той самий модуль, тільки другої версії — але технічно як раз ця версійність і дозволяє повністю змінити не тільки реалізацію, а й інтерфейси. (Та, по-правильному, поки не впровадиш нову версію, модуль мусить зберігати повну сумісність, хоча на практиці це постійно порушують.)Я вже до того спробував замінити
jsonнаjson/v2в іншому проєкті, але як раз зіткнувся з несумісністю деяких інтерфейсів та відклав, бо великої потреби в оновленні не було. Та й модуль поки експериментальний та потребує особливих параметрів компіляції.А тут раптом виявляється потреба прочитати невідомі атрибути. Звісно, це легко зробити, якщо прочитати JSON у
map[string]interface{}. Проте потім доведеться вручну зчитувати відомі атрибути. Ну або можна власнийUnmarshalJSON()реалізувати — теж вручну. Це мені не до вподоби. Я хотів би все, що знаю, прочитати у типізовану структуру, а потім решту вже вmap.Та, виявляється, це одна з можливостей нового пакета. Якщо в структурі присутній атрибут з потрібною анотацією
json:",unknown"- він й отримає всі невідомі значення. Ото й все, що треба було зробити!Цікаво, що я не бачу такої можливості в жодному сторонньому модулі. Хіба що є відомий підхід з іншого боку — модуль mapstructure, яким можна з нетипізованого
mapутворити структуру.А ще важлива причина чекати
json/v2- там зʼявилося справжнє читання та запис потоком. Бо як я дізнався, стандартний модульjsonзавжди буферизує весь текст об’єкта — тут можна почитати. Це, прямо кажучи, бентежить. Хоча, звісно, є багато інших модулів, які це вирішують. Мені, поки що, завжди вистачало стандартного. -
JCT 0.1.0 - краще перетворення JSON Canvas на Markdown
На вихідних розширив можливості JSON Canvas Tools… бо мені було треба. А саме, почав перекладати власні канви на списки, та виявилося, що наївного перетворення замало.
Взагалі воно й так не було зовсім наївним — я принаймні знаходив кластери вузлів зі звʼязками та перетворював їх у вкладені списки. Але того мало.
По-перше, хоч всіх нюансів розташування в просторі не передати, є один зрозумілий: групи. В JSON Canvas група — це лише спеціальний тип вузла
group, явної вкладеності немає. Зате цю вкладеність легко обчислити за координатами вузлів — що, я гадаю, й робить Obsidian, коли ти перетягаєш всі вузли в групі разом із самою групою. А в мене тепер кожна група стає заголовком в Markdown.Друге, та досить просто, на канві можуть бути зображення. Для них немає особливої розмітки — лише вузли типу
file- для локальних зображень, абоlink- для URL. Можна, звісно, залишити їх в Markdown посиланнями, але щоб було зручніше, я перевіряю розширення посилання, та виводжу з відповідною розміткою.Нарешті, багато в кого канва доповнена нестандартними атрибутами — в мене ось такі. Щоб їх не загубити, я виводжу всі нестандартні атрибути у Markdown. Спочатку хотів показати їх просто JSONом, але не так зручно мати JSON всередині тексту. Тому натомість виводжу у вигляді
key=value. Потім я можу звичайною заміною тексту перекласти їх в щось красиве. -
Мій місяць з монітором глюкози
Десь із місяць тому сестра нахвалила мені монітор глюкози FreeStyle Libre 3 Plus. Це, звісно, в першу чергу рішення для хворих на діабет. Але для здорової людини монітор відкриває цікавий погляд на один з важливіших біохімічних процесів в нашому тілі. Сьогодні — розповідь про технічну сторону.
Що з себе складає монітор глюкози? Це розміром з монету біла шайбочка, яка наклеюється на задню поверхню плеча. Від неї під шкіру йде волосина міліметрів пʼять — вона й “бачить” рівні глюкози. Монітор живе два тижні, потім ставиш новий. Ніякого іншого обслуговування не потребує. Ніяких обмежень не накладає, я, наприклад, спокійно собі плавав.
Наліпити його дуже просто. Для того монітор продається вже в спеціальній касеті. Притискаєш її до чистої шкіри, всередині відстрілює за долі секунди голка, вживляє датчик та наліпляє сам пристрій. Процедура буквально моментальна та не потребує ніякого досвіду. Після вживлення може кілька хвилин трохи поболіти та й усе. Коли знімаєш, сліду практично не залишається, хіба що від клею.
Окремо продається круглий пластир, який можна наклеїти для захисту зверху. Я два тижні ходив з ним, два — без. Не відклеювалося ані так, ані так. Пластир в кілька разів більше за площею, зате не має твердого краю. Отже, вже точно ніде не зачепишся — бо пристрій такий непомітний, що ти про нього просто забуваєш. До речі, неочевидний факт: місце вживлення датчика є відкритим назовні — бо ж він вживляється голкою. Тож в моніторі є для цього маленький отвір, і в цей отвір затікає вода та й усе інше. Тому мені, мабуть, більше сподобалося накрити все пластиром.
Для перегляду інформації сучасні датчики підʼєднуються просто до телефону. І тут виявляється, що в Україні офіційно вони недоступні, бо застосунку в нашому App Store немає. Де ж я брав датчик? А на Промі — їх прямо багато. Тож очевидно, що люди користуються. Як вони знають, що треба звернути увагу на країну походження датчика та встановити застосунок з App Store тільки цієї країни? (Наприклад — Німеччини.) Перед цим зареєструвати окремий обліковий запис Apple? Вийти зі свого запису тільки для App Store, зайти в новий, встановити застосунок та повернутися назад? Я чесно не уявляю.
Із застосунку створюєш обліковий запис, підносиш телефон до вже вживленого монітору, він його підʼєднує та за годину починає видавати показники в реальному часі. А про те, що там він показує - вже наступного разу.
PS. Виправив підписку на Патреоні - як виявилося, щомісячна підписка там можливість відносно нова.