{"version":"https://jsonfeed.org/version/1.1","title":"Engineer — Software — Портфоліо та нотатки","home_page_url":"https://software.engineer.company/uk/","feed_url":"https://software.engineer.company/uk/feed.json","description":"Engineer ApS — розробка програмного забезпечення та IT-консалтинг у Копенгагені, Данія. Портфоліо підтверджених інженерних досягнень у даних, хмарі та IT.","language":"uk","icon":"https://software.engineer.company/assets/images/brand/card.webp","favicon":"https://software.engineer.company/assets/icons/apple/apple-touch-icon.png","authors":[{"name":"Engineer ApS","url":"https://software.engineer.company/uk/"}],"items":[{"id":"https://software.engineer.company/uk/portfolio/designed-a-comprehensive-infrastructure-framework-for-a-research-institute-3/","url":"https://software.engineer.company/uk/portfolio/designed-a-comprehensive-infrastructure-framework-for-a-research-institute-3/","title":"Спроєктувала комплексну інфраструктурну систему для науково‑дослідного інституту, що охопила 14 департаментів, з гнучкими модулями, уніфікованими пайплайнами даних та структурованими стратегіями підтримки для довгострокового впровадження.","summary":"Отриманий план інфраструктури виявився і технічно обґрунтованим, і стратегічно узгодженим із дослідницькими цілями інституту.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e У науково‑дослідному інституті, що об\u0026rsquo;єднував 14 різнопрофільних дослідницьких груп, кожна група працювала з різними джерелами даних, форматами, масштабами та програмними інструментами. Технічна експертиза та доступні ІТ‑ресурси суттєво відрізнялися між групами. Хоча декільком групам вдалося створити й розгорнути власні ІТ‑рішення, багато інших стикалися зі складністю власних потреб у сфері дата‑інфраструктури, що відволікало цінний час і увагу від основної дослідницької роботи.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб розробити рішення, яке дозволило б дослідникам зосередитися на науковій роботі, а не на ІТ‑проблемах. Метою було спроєктувати та впровадити масштабовану дата‑інфраструктуру для всього інституту, здатну задовольнити широкі та відмінні одна від одної вимоги більшості дослідницьких груп.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Було розроблено надійний, перспективний план інфраструктури, що збалансовував гнучкість і стандартизацію. План окреслював ключові компоненти, такі як модульна архітектура, шляхи інтеграції різноманітних джерел даних, зручні для користувача інтерфейси, адаптовані до різного рівня технічних навичок, а також масштабовані рішення для зберігання та обробки даних. Він також охоплював стратегії впровадження, підтримки та управління, покликані забезпечити прийняття рішення й довгострокову стійкість.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Отриманий план інфраструктури виявився і технічно обґрунтованим, і стратегічно узгодженим із дослідницькими цілями інституту. Він об\u0026rsquo;єднав бачення управління даними в межах усієї організації, окреслив чіткий шлях до зменшення ІТ‑навантаження на дослідників і заклав основу для спільного, ефективного та готового до майбутнього дослідницького середовища даних. План отримав високу оцінку за інклюзивність, чіткість та адаптивність, задавши чіткий напрям трансформації дата‑інфраструктури інституту.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Data Governance","Архітектура платформи","Архітектура рішень","Документація","Інженерія даних","Інфраструктура","Пайплайни даних (ETL/ELT)","Стейкхолдери та звітність","Технічне лідерство","Data Governance та якість даних","Архітектура платформи та рішень","Розробка пайплайнів даних (ETL/ELT)","Технічна документація","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/accelerated-geographical-data-pipeline-performance-by-50x-by-5/","url":"https://software.engineer.company/uk/portfolio/accelerated-geographical-data-pipeline-performance-by-50x-by-5/","title":"Прискорила продуктивність пайплайну географічних даних у 50 разів, вдосконаливши SQL‑програмування та моделювання даних у PostgreSQL, MS SQL та Google Cloud BigQuery.","summary":"Ці комплексні оптимізації прискорили продуктивність пайплайну географічних даних у 50 разів, суттєво скоротивши час обробки даних.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Організація стикалася зі значними затримками в обробці великих обсягів географічних даних, що впливало на ефективність процесів прийняття рішень на основі даних та аналітичної звітності.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Мета полягала в тому, щоб оптимізувати пайплайн географічних даних для підвищення продуктивності та скорочення часу обробки, забезпечивши можливість ефективнішого проведення аналітики даних у режимі реального часу.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Було ретельно проаналізовано наявні структури SQL‑програмування та моделювання даних у PostgreSQL, MS SQL і Google Cloud BigQuery, що виявило вузькі місця, пов\u0026rsquo;язані з неефективними стратегіями індексації, неоптимальним дизайном запитів та відсутністю належних обмежень. Для вирішення цих проблем:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eМоделі даних було перепроєктовано для нормалізації критично важливих наборів даних, а також впроваджено стратегії партиціонування для скорочення часу отримання даних.\u003c/li\u003e\n\u003cli\u003eЗастосовано розширені техніки індексації, зокрема B‑tree та GiST індекси для PostgreSQL, фільтровані індекси в MS SQL і кластеризацію в BigQuery.\u003c/li\u003e\n\u003cli\u003eОптимізовано складні SQL‑запити шляхом рефакторингу підзапитів, скорочення операцій з\u0026rsquo;єднання та впровадження матеріалізованих подань там, де це доречно.\u003c/li\u003e\n\u003cli\u003eВстановлено обмеження цілісності даних, такі як зовнішні ключі та обмеження перевірки, для забезпечення узгодженості даних без шкоди для продуктивності.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Ці комплексні оптимізації прискорили продуктивність пайплайну географічних даних у 50 разів, суттєво скоротивши час обробки даних. Це покращення уможливило аналітику в режимі реального часу, розширило можливості звітності та надало зацікавленим сторонам своєчасні дані для прийняття рішень, що зрештою сприяло ухваленню більш обґрунтованих стратегічних рішень.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Data Governance","GIS / геопростір","PostgreSQL","SQL","Бази даних","Інженерія даних","Оптимізація продуктивності","Пайплайни даних (ETL/ELT)","Сховища даних","GIS та геопросторові рішення","Оптимізація продуктивності баз даних","Проєктування сховищ даних","Розробка пайплайнів даних (ETL/ELT)"]},{"id":"https://software.engineer.company/uk/portfolio/improved-geographical-map-application-performance-by-10x-through-6/","url":"https://software.engineer.company/uk/portfolio/improved-geographical-map-application-performance-by-10x-through-6/","title":"Підвищила продуктивність застосунку географічних карт у 10 разів завдяки стратегічному переходу бази даних з MSSQL на PostgreSQL, включно з data cutover, оптимізувавши обробку та безпеку даних.","summary":"Досягнуто підвищення продуктивності просторових запитів у 10 разів, скоротивши середній час відповіді з 2,5 секунди до менш ніж 250 мілісекунд.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Географічний картографічний застосунок організації, що підтримував просторові запити в реальному часі для багатьох користувачів, зазнавав серйозних проблем із продуктивністю. Затримки при рендерингу картографічних шарів і виконанні запитів до даних на основі місцезнаходження впливали як на користувацький досвід, так і на надійність бекенд‑сервісів. Система працювала на застарілій базі даних Microsoft SQL Server (MSSQL), яка не мала нативної геопросторової індексації.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Підвищити продуктивність, масштабованість і безпеку картографічного застосунку, з конкретною метою скоротити затримку запитів і збільшити пропускну здатність для просторових операцій.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Здійснено стратегічну міграцію бази даних з MSSQL на PostgreSQL із розширенням PostGIS для забезпечення нативної підтримки геопросторових даних.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eСпроєктовано нову схему, оптимізовану для просторових даних, з упровадженням індексів GIST та SP‑GiST на стовпцях geometry та geography для пришвидшення запитів.\u003c/li\u003e\n\u003cli\u003eВизначено суворі обмеження зовнішніх ключів і обмеження перевірки для забезпечення реляційної цілісності та застосування правил валідації даних для просторових координат.\u003c/li\u003e\n\u003cli\u003eМігровано понад 50 мільйонів просторових записів за допомогою ETL‑пайплайнів із кроками трансформації даних для відповідності новим стандартам SRID (EPSG:4326).\u003c/li\u003e\n\u003cli\u003eНалаштовано параметри конфігурації PostgreSQL (наприклад, work_mem, effective_cache_size) для оптимальної продуктивності вводу‑виводу за умов паралельного доступу.\u003c/li\u003e\n\u003cli\u003eВпроваджено рольове керування доступом (RBAC) та безпеку на рівні рядків для забезпечення політик захисту даних для кількох груп користувачів.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Досягнуто підвищення продуктивності просторових запитів у 10 разів, скоротивши середній час відповіді з 2,5 секунди до менш ніж 250 мілісекунд. Навантаження на CPU бекенду знизилося на 65%, а доступність системи покращилася в періоди пікового навантаження. Рівень безпеки також посилено завдяки деталізованим політикам доступу та обмеженням валідації даних, що зменшило ймовірність пошкодження просторових даних.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","GIS / геопростір","PostgreSQL","SQL","Бази даних","Безпека","Інженерія даних","Міграції та модернізація","Оптимізація продуктивності","Пайплайни даних (ETL/ELT)","GIS та геопросторові рішення","Міграція та модернізація баз даних","Оптимізація продуктивності баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/resolved-1-000-issues-in-geographical-data-and-7/","url":"https://software.engineer.company/uk/portfolio/resolved-1-000-issues-in-geographical-data-and-7/","title":"Вирішила 1 000 проблем у географічних даних та часових рядах, використовуючи GDAL, ArcGIS, PostGIS, Mapbox, QGIS, SQL (PL/pgSQL, Transact‑SQL), Bash, забезпечивши високоякісну обробку великих даних.","summary":"Завдяки цим зусиллям було усунено понад 1 000 критичних проблем, що суттєво покращило точність даних і швидкість обробки.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Під час роботи над масштабним проєктом геопросторової аналітики команда виявила численні невідповідності й аномалії в географічних наборах даних і часових рядах. Ці проблеми впливали на точність просторового аналізу та інструментів прийняття рішень, що використовувалися в кількох підрозділах.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Відповідальність полягала в тому, щоб виявити, усунути та оптимізувати понад 1 000 проблем якості даних у цих складних наборах даних для забезпечення цілісності та продуктивності подальших застосунків і візуалізацій.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Просторові помилки систематично діагностувалися та виправлялися за допомогою комбінації інструментів, зокрема GDAL, QGIS та ArcGIS, а автоматизовані робочі процеси на Bash дозволяли пришвидшити повторювані завдання з очищення даних. PostGIS забезпечував виконання складних просторових запитів і просторову індексацію, а надійні процедури на PL/pgSQL і Transact‑SQL використовувалися для управління та трансформації географічних і часових даних у базах даних PostgreSQL та SQL Server. Крім того, очищені дані було інтегровано в інтерактивні візуалізації за допомогою Mapbox, що підвищило доступність даних для кінцевих користувачів.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Завдяки цим зусиллям було усунено понад 1 000 критичних проблем, що суттєво покращило точність даних і швидкість обробки. Це безпосередньо сприяло скороченню часу виконання просторових запитів на 35% і уможливило проведення командою надійнішого просторового аналізу. Робота забезпечила постійну доступність якісних, готових до використання даних для аналітики та звітності, підтримуючи стратегічні рішення в межах усієї організації.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Data Governance","GIS / геопростір","PostgreSQL","SQL","Автоматизація та CI/CD","Бази даних","Інженерія даних","Оптимізація продуктивності","Пайплайни даних (ETL/ELT)","Data Governance та якість даних","GIS та геопросторові рішення","Розробка пайплайнів даних (ETL/ELT)"]},{"id":"https://software.engineer.company/uk/portfolio/designed-implemented-and-administered-6-etl-elt-pipelines-8/","url":"https://software.engineer.company/uk/portfolio/designed-implemented-and-administered-6-etl-elt-pipelines-8/","title":"Спроєктувала, реалізувала та адмініструвала 6 пайплайнів ETL/ELT, використовуючи Google BigQuery, MSSQL, PostgreSQL, Shell scripting, PL/pgSQL та Transact‑SQL, інтегрувавши дані для ефективної обробки через Python API.","summary":"Ці автоматизовані пайплайни суттєво скоротили ручні витрати та час обробки — з понад 3 годин ручної роботи до менш ніж 20 хвилин наскрізно, водночас покращивши…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Організації потрібно було консолідувати та обробляти великі обсяги структурованих даних із віддаленого сховища даних, розташованого за IPSec VPN. Ці дані мали критичне значення для роботи внутрішніх аналітичних дашбордів і зовнішніх Python API, якими користувалися клієнти й партнери.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Мета полягала в тому, щоб спроєктувати, реалізувати та підтримувати набір надійних автоматизованих ETL/ELT‑пайплайнів для безпечного отримання, трансформації та завантаження даних у Google BigQuery, забезпечуючи точність даних, продуктивність і масштабованість у всіх системах.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Було спроєктовано, реалізовано та адміністровано 6 наскрізних ETL/ELT‑пайплайнів на основі кількох технологій, включно з Google BigQuery, MSSQL, PostgreSQL, Shell‑скриптами, PL/pgSQL та Transact‑SQL.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eНалагоджено захищені з\u0026rsquo;єднання з віддаленим сервером, захищеним IPSec VPN, для автоматизації отримання даних.\u003c/li\u003e\n\u003cli\u003eЗаплановано та виконано завантаження стиснутих архівів даних, що містили файли Parquet, CSV та .bak.\u003c/li\u003e\n\u003cli\u003eРозроблено скрипти на Bash і Python для витягування та класифікації файлів за типом і схемою.\u003c/li\u003e\n\u003cli\u003eДля файлів .bak резервні копії відновлювалися в локальному екземплярі MSSQL Server за допомогою робочих процесів RESTORE DATABASE, а цілісність схеми перевірялася.\u003c/li\u003e\n\u003cli\u003eЗавантажено структуровані дані в проміжні схеми в MSSQL і PostgreSQL за допомогою інструментів bcp, psql та SSIS, залежно від формату джерела.\u003c/li\u003e\n\u003cli\u003eНаписано модульні та придатні для повторного використання процедури PL/pgSQL і T‑SQL для очищення, нормалізації та збагачення даних відповідно до бізнес‑логіки.\u003c/li\u003e\n\u003cli\u003eЕкспортовано впорядковані набори даних і таблиці в проміжні формати, стиснуто їх за допомогою gzip і безпечно передано в бакет Google Cloud Storage.\u003c/li\u003e\n\u003cli\u003eАвтоматизовано процеси завантаження та зіставлення схем у Google BigQuery за допомогою bq CLI та скриптів для завантаження даних на основі Python.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Ці автоматизовані пайплайни суттєво скоротили ручні витрати та час обробки — з понад 3 годин ручної роботи до менш ніж 20 хвилин наскрізно, водночас покращивши актуальність даних із щотижневої до щоденної синхронізації. Python API, що споживали ці дані, отримали приріст продуктивності на 30%, а покращена прозорість допомогла бізнес‑аналітикам швидше надавати інсайти зацікавленим сторонам. Рішення залишається масштабованим і легко розширюваним для підключення нових джерел даних у міру зростання бізнесу.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Cloud","PostgreSQL","Python","SQL","Автоматизація та CI/CD","Бази даних","Інженерія даних","Мережі та VPN","Пайплайни даних (ETL/ELT)","Сховища даних","Backend- та API‑розробка","Проєктування сховищ даних","Проєктування та моделювання баз даних","Розробка пайплайнів даних (ETL/ELT)"]},{"id":"https://software.engineer.company/uk/portfolio/delivered-8-power-bi-projects-with-comprehensive-manuals-10/","url":"https://software.engineer.company/uk/portfolio/delivered-8-power-bi-projects-with-comprehensive-manuals-10/","title":"Реалізувала 8 проєктів Power BI з докладними посібниками, інтегрувавши інструменти Microsoft Power BI з NodeJS API та Python FastAPI для ефективної аналітики та візуалізації даних.","summary":"Успішно реалізовано 8 проєктів з аналітики даних, підвищивши ефективність формування звітів на 60% і давши змогу міжфункціональним командам ухвалювати швидші…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Організації потрібні були динамічні візуальні уявлення про складні набори даних, що охоплювали продуктивність електромереж і показники географічного розподілу, для підтримки прийняття рішень у технічних і стратегічних командах.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Розробити інтерактивні дашборди та рішення для звітності, здатні ефективно подавати як дані в реальному часі, так і історичні географічні та електричні дані, даючи змогу зацікавленим сторонам швидко виявляти тренди, аномалії та показники продуктивності.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Інтегровано Microsoft Power BI з власним бекенд‑стеком на основі NodeJS API та Python FastAPI для оптимізації приймання, трансформації та візуалізації даних. Спроєктовано й реалізовано дашборди з картографічними візуалізаціями, показниками споживання енергії, відстеженням відключень та індикаторами ефективності електромережі. Розроблено багаторазові шаблони та детальну документацію для підтримки масштабованості та зручності використання.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Успішно реалізовано 8 проєктів з аналітики даних, підвищивши ефективність формування звітів на 60% і давши змогу міжфункціональним командам ухвалювати швидші рішення на основі даних. Зацікавлені сторони повідомили про суттєве покращення розуміння регіональної продуктивності електромереж і точності планування ресурсів.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","GIS / геопростір","Python","Аналітика даних","Документація","Інженерія даних","Продукт і вимоги","Backend- та API‑розробка","Аналітика даних та BI‑дашборди","Технічна документація"]},{"id":"https://software.engineer.company/uk/portfolio/released-500-electricity-and-gis-data-analysis-reports-11/","url":"https://software.engineer.company/uk/portfolio/released-500-electricity-and-gis-data-analysis-reports-11/","title":"Випустила 500 звітів з аналізу даних електроенергетики та GIS, застосовуючи поглиблені дослідження та усунення несправностей для забезпечення точної аналітики географічних і часових великих даних.","summary":"Звіти стали стандартним довідковим матеріалом у різних підрозділах, допомагаючи в балансуванні регіонального навантаження, плануванні енергоефективності та…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Команда управляла величезними наборами даних, що генерувалися розумними лічильниками, встановленими в кількох географічних регіонах. Ці розумні лічильники виробляли деталізовані часові ряди даних про споживання електроенергії, які використовували енергетичні аналітики, інженери та регіональні планувальники для операційних і стратегічних рішень.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Відповідальність полягала в тому, щоб готувати якісні, прозорі та відтворювані аналітичні звіти, здатні виявляти патерни у споживанні енергії, виявляти аномалії та визначати регіональні тренди використання, водночас гарантуючи, що нетехнічні зацікавлені сторони зможуть легко інтерпретувати й повторно використовувати результати.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Було створено та надано понад 500 детальних аналітичних звітів, використовуючи чистий SQL для виконання всіх завдань з видобування, трансформації та аналізу даних, працюючи безпосередньо в хмарних середовищах, таких як PostgreSQL і BigQuery. Дані включали геолокаційні координати, ідентифікатори лічильників, дані про споживання енергії з часовими мітками та метадані про довкілля. SQL‑скрипти використовували CTE, віконні функції, підзапити та геопросторові з\u0026rsquo;єднання, що забезпечувало масштабовану та ефективну обробку.\u003c/p\u003e\n\u003cp\u003eКожен звіт містив анотований SQL‑код, що давало змогу колегам і співавторам повністю відтворити й перевірити дослідження, що суттєво скорочувало час, необхідний для подальшого аналізу. Також додавалися нотатки з усунення несправностей і документувалися типові проблеми якості даних, такі як відсутні GPS‑координати або пошкоджені значення лічильників, разом із рекомендованими процедурами їх обробки.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Звіти стали стандартним довідковим матеріалом у різних підрозділах, допомагаючи в балансуванні регіонального навантаження, плануванні енергоефективності та виявленні аномалій. Забезпечуючи повну прозорість і відтворюваність, ця робота допомогла підвищити довіру зацікавлених сторін до даних і сприяла створенню точніших прогнозних моделей та покращенню ефективності операційного планування на 10–15%.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Data Governance","GIS / геопростір","PostgreSQL","SQL","Аналітика даних","Бази даних","Документація","Стейкхолдери та звітність","Сховища даних","Data Governance та якість даних","GIS та геопросторові рішення","Аналітика даних та BI‑дашборди"]},{"id":"https://software.engineer.company/uk/portfolio/architected-created-and-managed-100-postgresql-ms-sql-12/","url":"https://software.engineer.company/uk/portfolio/architected-created-and-managed-100-postgresql-ms-sql-12/","title":"Спроєктувала, створила та керувала 100 базами даних сховищ даних на PostgreSQL, MS SQL та Google BigQuery, переважно з GIS‑даними та часовими рядами, оптимізувавши продуктивність і масштабованість.","summary":"Ці ініціативи призвели до суттєвих покращень: - Приріст продуктивності: час відповіді на запити для GIS-даних і часових рядів скоротився на 40–60%, що…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e У технологічній компанії, що стрімко зростала, виникла критична потреба створювати, керувати та оптимізувати різноманітний портфель зі 100+ баз даних у PostgreSQL, Microsoft SQL Server та Google BigQuery. Ці бази даних переважно оброблювали складні набори даних, включно з даними геоінформаційних систем (GIS) (наприклад, просторові координати та аналітика на основі місцезнаходження) і часовими рядами (наприклад, показання сенсорів, логи та метрики в реальному часі). Наявна інфраструктура стикалася з проблемами масштабованості, продуктивності запитів і узгодженості даних, особливо в міру експоненційного зростання обсягу даних. Організації була потрібна надійна архітектура для забезпечення надійності даних і скорочення операційних витрат.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Основна мета полягала в тому, щоб спроєктувати, реалізувати та підтримувати масштабовану, високопродуктивну екосистему сховища даних, адаптовану для GIS‑даних і часових рядів. Це включало:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eУсунення вузьких місць продуктивності в складних просторових і часових запитах.\u003c/li\u003e\n\u003cli\u003eЗабезпечення масштабованості для обробки зростаючих обсягів даних при збереженні економічної ефективності.\u003c/li\u003e\n\u003cli\u003eСпівпрацю з міжфункціональними командами (наприклад, дата‑сайєнтистами, продукт‑менеджерами) для узгодження дизайну бази даних з бізнес‑потребами.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Для досягнення цих цілей:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eСпроєктовано масштабовані архітектури:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003eСтворено нормалізовані та денормалізовані схеми для PostgreSQL і SQL Server із застосуванням просторової індексації (наприклад, PostGIS для PostgreSQL) і партиціонування часових рядів для оптимізації продуктивності запитів.\u003c/li\u003e\n\u003cli\u003eВикористано таблиці BigQuery з розбиттям за часом та кластеризацією для ефективної обробки великомасштабних часових рядів.\u003c/li\u003e\n\u003c/ul\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003eВпроваджено стратегії оптимізації:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003eЗастосовано техніки оптимізації запитів, такі як індексація, матеріалізовані подання та кешування, для скорочення затримки GIS‑запитів і запитів до часових рядів.\u003c/li\u003e\n\u003cli\u003eЗастосовано стиснення даних і колонкове зберігання в BigQuery для мінімізації витрат на зберігання й підвищення швидкості сканування.\u003c/li\u003e\n\u003c/ul\u003e\n\u003col start=\"3\"\u003e\n\u003cli\u003eЗдійснено співпрацю щодо міжплатформної інтеграції:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003eЗадокументовано найкращі практики моделювання GIS‑даних і часових рядів для орієнтування команд у майбутніх проєктах.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Ці ініціативи призвели до суттєвих покращень:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eПриріст продуктивності: час відповіді на запити для GIS‑даних і часових рядів скоротився на 40–60%, що уможливило швидшу аналітику та прийняття рішень.\u003c/li\u003e\n\u003cli\u003eОпераційна надійність: автоматизований моніторинг скоротив час простою на 50%, тоді як стандартизовані процеси підвищили продуктивність команди та зменшили кількість помилок.\u003c/li\u003e\n\u003cli\u003eВплив на бізнес: оптимізована інфраструктура дала змогу компанії запустити нові продукти на основі даних (наприклад, дашборди аналітики в реальному часі) і виконати нормативні вимоги щодо управління даними (data governance).\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eЦя робота зміцнила здатність організації розв\u0026rsquo;язувати складні проблеми, пов\u0026rsquo;язані з даними.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Data Governance","GIS / геопростір","PostgreSQL","SQL","Архітектура платформи","Бази даних","Інженерія даних","Надійність і резервне копіювання","Оптимізація продуктивності","Сховища даних","GIS та геопросторові рішення","Адміністрування баз даних (DBA)","Оптимізація продуктивності баз даних","Проєктування сховищ даних","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/","url":"https://software.engineer.company/uk/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/","title":"Автоматизувала розгортання GIS SaaS‑застосунку, обробку даних та систему звітності за допомогою GitHub Actions CI/CD, Python, Bash та SQL.","summary":"Розгортання, обробка даних та звітність стали автоматизованими й надійними, ручна рутина зникла з плеча команди, а цикл релізів скоротився.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Розгортання GIS SaaS‑застосунку, обробка його даних та формування звітів були повністю ручними кроками — а ручні кроки одночасно й повільні, і тихо небезпечні. Кожен реліз забирав час інженерів і ніс ризик помилки, а повторювана робота з даними та звітністю сиділа там, з\u0026rsquo;їдаючи потужність тиждень за тижнем.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завданням була автоматизація всього шляху від коду до продакшну, а також повторюваної обробки даних і звітності — з метою отримати релізи, які були б швидкими, безпечними та відтворюваними, а не ретельним ручним ритуалом щоразу.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Весь шлях було автоматизовано. Пайплайни GitHub Actions взяли на себе цикл test‑build‑deploy, тож реліз перестав залежати від того, чи хтось пам\u0026rsquo;ятає всі кроки. Повторювана обробка даних та звіти перейшли в заплановані завдання на Python, Bash та SQL, тож вони просто виконувалися, а не були чиєюсь рутинною роботою. А конфігурація та секрети були стандартизовані так, щоб кожне середовище поводилося однаково — саме це усуває несподіванки на кшталт «у мене на машині працює», бо не залишається «моєї машини», яка відрізняється від продакшну.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Розгортання, обробка даних та звітність стали автоматизованими й надійними, ручна рутина зникла з плеча команди, а цикл релізів скоротився. Команда змогла зосередити увагу на продукті, а не на операціях, що його оточували.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Cloud","DevOps","GIS / геопростір","Python","SQL","Автоматизація та CI/CD","Інженерія даних","Надійність і резервне копіювання","Пайплайни даних (ETL/ELT)","DevOps та автоматизація CI/CD","GIS та геопросторові рішення","Розробка пайплайнів даних (ETL/ELT)"]},{"id":"https://software.engineer.company/uk/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/","url":"https://software.engineer.company/uk/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/","title":"Автоматизувала постачання 20 пайплайнів GIS‑даних та ETL‑процесів даних застосунку, оптимізувавши автоматизацію інфраструктури та звітність.","summary":"Усі двадцять пайплайнів та їхній ETL працювали автоматично й передбачувано, а вся картина автоматизації інфраструктури та звітності стала охайнішою.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Платформа працювала на великій кількості GIS‑пайплайнів даних та ETL‑процесів для даних застосунку, які постачалися й контролювалися вручну. Ручні пайплайни створюють вузькі місця, вони втрачають узгодженість, і найгірше — вони несуть постійний невеликий ризик того, що один із них тихо відмовить, і ніхто цього не помітить, доки дані далі за потоком уже не стануть неправильними.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завданням була автоматизація постачання цих пайплайнів та ETL‑процесів — щоб дані надходили надійно та передбачувано без того, щоб хтось їх супроводжував.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Двадцять GIS‑пайплайнів даних та ETL для даних застосунку перейшли на автоматизоване постачання, від початку до кінця. Планування, логування та обробку відмов було стандартизовано, тож кожен пайплайн поводився однаково і, що важливо, було видно, коли якийсь із них поводився інакше — тиха відмова залишається тихою, лише якщо ніхто не стежить. І їх було вбудовано в наявну автоматизацію інфраструктури та звітність, тож вони стали частиною однієї узгодженої системи, а не шухляди зі скриптами, які хтось мусив пам\u0026rsquo;ятати запустити.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Усі двадцять пайплайнів та їхній ETL працювали автоматично й передбачувано, а вся картина автоматизації інфраструктури та звітності стала охайнішою. Бізнес отримав надійні, актуальні дані без того, щоб хтось проводив їх вручну — і без ризику тихої відмови, що висів над цим.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["DevOps","GIS / геопростір","Автоматизація та CI/CD","Інженерія даних","Моніторинг та observability","Надійність і резервне копіювання","Пайплайни даних (ETL/ELT)","DevOps та автоматизація CI/CD","GIS та геопросторові рішення","Розробка пайплайнів даних (ETL/ELT)"]},{"id":"https://software.engineer.company/uk/portfolio/led-the-software-development-of-a-gis-map-24/","url":"https://software.engineer.company/uk/portfolio/led-the-software-development-of-a-gis-map-24/","title":"Очолила розробку програмного забезпечення GIS‑картографічного застосунку, збільшивши дохід у 10 разів та позиціонувавши продукт як основний актив даних.","summary":"GIS-застосунок став наріжним каменем SaaS-платформи, забезпечивши зростання доходу у 10 разів завдяки допродажам, ліцензуванню даних та залученню нових…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Основним викликом була побудова платформи, здатної відстежувати, моніторити та оптимізувати активи відновлюваної енергетики, такі як сонячні панелі та вітрові турбіни. Проте початкове рішення не мало надійних геопросторових можливостей, через що клієнтам було важко візуалізувати розташування активів, аналізувати просторові дані чи отримувати практичні висновки. Розпізнавши цю прогалину, керівна команда пріоритизувала розробку GIS‑застосунку (Geographic Information System) для карт, щоб підвищити цінність платформи та відповідати потребам клієнтів, що змінювалися.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завданням було очолити розробку GIS‑застосунку — критичного компонента для диференціації продукту на конкурентному ринку зеленої енергетики. Роль виходила за межі розробки програмного забезпечення, охоплюючи технічного лідера, DevOps‑інженера, інженера даних та SRE (Site Reliability Engineer), забезпечуючи узгодженість рішення з траєкторією зростання компанії. Метою було створити масштабований, інтуїтивно зрозумілий GIS‑інструмент, що безшовно інтегрувався б із SaaS‑платформою, даючи змогу користувачам візуалізувати розташування активів, відстежувати показники продуктивності та використовувати просторові дані для прийняття рішень. Це вимагало балансування технічних інновацій з обмеженнями зростаючого стартапу, забезпечуючи водночас можливість продукту розвиватися разом із компанією.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Почалося зі співпраці із зацікавленими сторонами для визначення основних функцій GIS‑застосунку, з фокусом на інтеграцію з наявною SaaS‑платформою та візуалізацію даних у реальному часі. З огляду на невеликий розмір команди, було спроєктовано модульну архітектуру з використанням бібліотек GIS з відкритим кодом, щоб система залишалася легкою й масштабованою. Також були впроваджені пайплайни CI/CD, автоматизоване надання інфраструктурних ресурсів та інструменти моніторингу для забезпечення надійності. У міру зростання команди нових інженерів наставляли, налагоджували міжфункціональну співпрацю та пріоритизували зворотний зв\u0026rsquo;язок від користувачів для ітеративного вдосконалення застосунку. З часом GIS‑інструмент еволюціонував від базового прототипу до складної платформи, включаючи розширену аналітику та кастомні дашборди для задоволення потреб клієнтів.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e GIS‑застосунок став наріжним каменем SaaS‑платформи, забезпечивши зростання доходу у 10 разів завдяки допродажам, ліцензуванню даних та залученню нових клієнтів. Його здатність візуалізувати активи зеленої енергетики в реальному часі підвищила операційну ефективність для клієнтів, а безперервне вдосконалення інструменту закріпило за ним статус основного інформаційного активу. Успіх проєкту не лише зміцнив репутацію компанії в секторі відновлюваної енергетики, а й продемонстрував цінність міждисциплінарного підходу в динамічному стартап‑середовищі. Поєднання технічної експертизи зі стратегічним баченням зробило GIS‑застосунок ключовим диференціатором, що підживлював довгострокове зростання та інновації.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["DevOps","Full‑Stack розробка","GIS / геопростір","Архітектура платформи","Архітектура рішень","Керівництво командою","Менторство та коучинг","Надійність і резервне копіювання","Продукт і вимоги","Технічне лідерство","Full‑Stack продуктова розробка","GIS та геопросторові рішення","Архітектура платформи та рішень","Продуктова стратегія та вимоги","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/directed-full-stack-gis-map-development-overseeing-postgresql-25/","url":"https://software.engineer.company/uk/portfolio/directed-full-stack-gis-map-development-overseeing-postgresql-25/","title":"Керувала full‑stack розробкою GIS‑карт, наглядаючи за PostgreSQL, Mapbox, ReactJS та NodeJS, щоб постачити інтегроване рішення.","summary":"У результаті вийшов єдиний інтегрований картографічний застосунок, у якому дані, рендеринг та інтерфейс нарешті тягнули в один бік.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e На цьому етапі GIS‑карта перестала бути просто функцією і стала причиною, чому клієнти взагалі заходили в систему. Проблема полягала в тому, що вона розросталася фрагментарно. Просторові дані зберігалися в PostgreSQL, саму карту малював Mapbox, а застосунок навколо неї складався з ReactJS на фронтенді та NodeJS на бекенді. Кожна частина працювала сама по собі. Просто їх не було побудовано так, щоб вони поєднувалися одна з одною, і шви вже почали розходитися.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Роль охоплювала full‑stack розробку карти та відповідний технічний напрям: модель даних, рендеринг, API та React‑фронтенд. Метою було перетворити чотири речі, які випадково опинилися в одному репозиторії, на єдиний продукт, за який не соромно.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Спочатку було визначено архітектуру, а далі робота велася близько до коду, а не з відстані. З боку даних просторову модель у PostgreSQL підтримували в порядку, щоб запити не сповільнювалися до повзання зі зростанням наборів даних. Mapbox відповідав за малювання; завдання полягало в тому, щоб подавати йому правильні дані на правильних рівнях масштабування, а не все одразу. З боку застосунку код на ReactJS і NodeJS проходив перевірку, команду підштовхували до спільних конвенцій, а відповідальність постійно повертали на той рівень, якому вона належала, щойно вона починала протікати в сусідній. Значна частина цієї роботи була неефектною: виловлювати дрібні неузгодженості, доки вони не застигли в архітектурі.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e У результаті вийшов єдиний інтегрований картографічний застосунок, у якому дані, рендеринг та інтерфейс нарешті тягнули в один бік. Він став ключовою частиною платформи — тим, що команда могла й далі розширювати, не побоюючись, що все ламатиметься щоразу, коли додається новий шар.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Frontend‑розробка","Full‑Stack розробка","GIS / геопростір","PostgreSQL","Архітектура платформи","Бази даних","Оптимізація продуктивності","Технічне лідерство","Backend- та API‑розробка","Full‑Stack продуктова розробка","GIS та геопросторові рішення","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/optimized-forecasting-and-investment-strategies-for-11-electricity-27/","url":"https://software.engineer.company/uk/portfolio/optimized-forecasting-and-investment-strategies-for-11-electricity-27/","title":"Оптимізувала стратегії прогнозування та інвестування для 11 операторів електромереж, підвищивши операційну ефективність за допомогою GIS‑рішень на основі даних.","summary":"Оператори отримали прогнози, яким можна довіряти, та інвестиційні рішення, спрямовані на конкретну мету, а не засновані на сподіваннях.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Оператори електромереж живуть і гинуть рішеннями про те, де підсилювати мережу і куди вкладати гроші, а одинадцять із них ухвалювали ці рішення майже без геопросторового аналізу під ними. У них були операційні дані. Чого в них не було — це способу побачити ці дані на карті, там, де насправді живуть закономірності.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб за допомогою GIS загострити їхнє прогнозування та інвестиційні стратегії — перетворити таблиці показників на щось, що показувало б, де потужність стає обмеженою, де накопичується ризик і куди найдоцільніше спрямувати наступні кошти.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Їхні операційні дані було об\u0026rsquo;єднано з геопросторовим моделюванням так, щоб вони підсилювали одне одного. Замість абстрактного прогнозування мережу можна було розглядати просторово й ставити конкретні запитання: які ділянки наближаються до своїх меж, які території виправдовують інвестиції в першу чергу. Для одинадцяти операторів це означало підганяти аналіз під те, як кожен із них фактично керує своєю мережею, а не пропонувати всім один шаблон у надії, що він підійде.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Оператори отримали прогнози, яким можна довіряти, та інвестиційні рішення, спрямовані на конкретну мету, а не засновані на сподіваннях. Прив\u0026rsquo;язка планування до того, що показувала карта, зробила весь процес ефективнішим — гроші та увага спрямовувалися туди, куди вказували дані, а не туди, куди вела звичка.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["GIS / геопростір","Аналітика даних","Інженерія даних","Продукт і вимоги","Стейкхолдери та звітність","GIS та геопросторові рішення","Аналітика даних та BI‑дашборди","Продуктова стратегія та вимоги"]},{"id":"https://software.engineer.company/uk/portfolio/presented-200-ui-ux-improvements-for-the-gis-28/","url":"https://software.engineer.company/uk/portfolio/presented-200-ui-ux-improvements-for-the-gis-28/","title":"Представила 200 покращень UI/UX для GIS‑картографічного застосунку, збільшивши дохід у 10 разів завдяки вдосконаленим функціям програмного забезпечення.","summary":"Інтерфейс став помітно зручнішим у використанні, а цінність продукту зросла відповідно: ця робота сприяла зростанню доходу у 10 разів.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Інтерфейс карти став потужним і водночас — ускладненим. Були місця, де було відчутно, що клієнти не отримують цінність, яка лежала прямо перед ними, — хороша функціональність, замкнена за незграбними взаємодіями. Цей розрив між тим, що продукт умів робити, і тим, що людям було легко робити, непомітно коштував бізнесу грошей.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб знайти ці розриви і провести виправлення до кінця: роботу з юзабіліті, яка мала зробити продукт простішим для отримання цінності і, не випадково, комерційно ціннішим.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Замість того, щоб здогадуватися, що не так, робота велася на основі зворотного зв\u0026rsquo;язку та даних про використання, і з цього утворився беклог із 200 конкретних покращень UI/UX. До них не ставилися як до рівнозначних — їх ранжували за впливом, а ті, що мали значення, відстоювалися і проводилися через команду, щоб бути випущеними як реальні функції, а не як список побажань, що застарівав у документі.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Інтерфейс став помітно зручнішим у використанні, а цінність продукту зросла відповідно: ця робота сприяла зростанню доходу у 10 разів. Це приклад, вартий того, щоб до нього повертатися, бо він чітко доводить думку — ретельна робота над UX не є косметикою, вона позначається на рахунку.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Аналітика даних","Дизайн‑системи та UI","Продукт і вимоги","Стейкхолдери та звітність","UI/UX‑дизайн та дизайн‑системи","Продуктова стратегія та вимоги"]},{"id":"https://software.engineer.company/uk/portfolio/managed-the-execution-of-30-successful-gis-projects-32/","url":"https://software.engineer.company/uk/portfolio/managed-the-execution-of-30-successful-gis-projects-32/","title":"Керувала виконанням 30 успішних GIS‑проєктів, продемонструвавши керівництво в постачанні інноваційних рішень у галузі.","summary":"Усі тридцять проєктів було здано. Ця послідовність важила більше, ніж будь-який окремий проєкт, — клієнт, який тридцять разів бачив постачання вчасно, не…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Компанія заробляла на постачанні GIS‑проєктів, і водночас їх виконувалося багато. Зростання компанії трималося на тому, щоб надійно доводити їх до завершення, — не один флагманський проєкт, зроблений блискуче, а стабільний потік проєктів, що здавалися вчасно й трималися купи, а це можливо лише тоді, коли координація в команді дійсно працює.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Відповідальність полягала в тому, щоб забезпечити постачання цього портфеля — тримати обсяг, людей і терміни узгодженими по всьому портфелю та давати команді напрямок для випуску.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e За ці роки через цю роль пройшло постачання тридцяти GIS‑проєктів. На практиці це означало утримувати обсяг стабільним, коли він намагався розповзатися, спрямовувати потрібних людей на потрібну роботу і триматися достатньо близько до кожного проєкту, щоб ловити проблеми, поки вони ще були малими. Якщо щось мало зірвати терміни, краще було дізнатися про це рано й перегрупуватися, ніж дізнатися про це на дедлайні. Значна частина роботи полягала просто в тому, щоб утримувати всі тарілки в повітрі та чесно інформувати клієнта про те, що і коли буде готове.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Усі тридцять проєктів було здано. Ця послідовність важила більше, ніж будь‑який окремий проєкт, — клієнт, який тридцять разів бачив постачання вчасно, не хвилюється за тридцять перший, і ця репутація значною мірою пояснює, чому компанія продовжувала зростати.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Agile та Scrum","GIS / геопростір","Керівництво командою","Стейкхолдери та звітність","Управління проєктами","GIS та геопросторові рішення","Управління проєктами (Agile)","Формування команди та менторство"]},{"id":"https://software.engineer.company/uk/portfolio/led-the-development-deployment-and-support-of-over-35/","url":"https://software.engineer.company/uk/portfolio/led-the-development-deployment-and-support-of-over-35/","title":"Очолила розробку, розгортання та підтримку понад 30 GIS‑проєктів, продемонструвавши експертизу в технологіях PostgreSQL, Bash, Python, JavaScript, GDAL, ArcGIS, PostGIS та Mapbox.","summary":"Понад тридцять проєктів було побудовано, розгорнуто і підтримувано в усьому цьому діапазоні. Відповідальність за весь життєвий цикл, а не лише за побудову, —…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Увесь випуск компанії становив GIS «на замовлення» — кастомна картографія та просторові системи, побудовані під конкретну проблему клієнта, а потім підтримувані в роботі після запуску. Побудувати систему — це лише половина справи; геопросторовий проєкт, який запускається, а потім падає в продакшені, насправді не було доставлено.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Ці проєкти проходили через цю роль від початку до кінця — розробка, розгортання та підтримка після запуску — з технічним керівництвом у доволі широкому стеку технологій.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Постачання охопило понад тридцять GIS‑проєктів, з практичною роботою по всьому стеку. PostgreSQL із PostGIS в основі для просторових даних, GDAL/OGR для перенесення їх між форматами — shapefiles, GeoJSON, GeoTIFF, KML, vector tiles — а також QGIS і JOSM для самої роботи з даними. На фронті — вебкарти, побудовані на Mapbox GL і Leaflet, іноді з використанням API ArcGIS чи HERE, з рівнем застосунку на JavaScript, Python, PHP і SQL. Робота охоплювала діапазон від 2D- і 3D‑цифрової картографії через обробку LiDAR, георектифікацію та векторизацію до карт приміщень і навігації в них. І відповідальність не закінчувалася на моменті запуску — розгортання та подальша підтримка в продакшені теж входили до неї, тож проблеми не передавалися комусь іншому; з ухваленими рішеннями доводилося жити.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Понад тридцять проєктів було побудовано, розгорнуто і підтримувано в усьому цьому діапазоні. Відповідальність за весь життєвий цикл, а не лише за побудову, — саме те, що тримало якість чесною: проєктування відбувається інакше, коли знаєш, що саме тобі дзвонитимуть, якщо щось зламається.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Full‑Stack розробка","GIS / геопростір","PostgreSQL","Python","SQL","Бази даних","Веброзробка","Інженерія даних","Керівництво командою","Надійність і резервне копіювання","Технічне лідерство","Backend- та API‑розробка","Full‑Stack продуктова розробка","GIS та геопросторові рішення","Розробка пайплайнів даних (ETL/ELT)","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/contributed-to-user-interface-design-processes-ensuring-intuitive-36/","url":"https://software.engineer.company/uk/portfolio/contributed-to-user-interface-design-processes-ensuring-intuitive-36/","title":"Долучилася до процесів проєктування користувацьких інтерфейсів, забезпечивши інтуїтивні, візуально привабливі та зручні для користувача інтерфейси проєктів.","summary":"Інтерфейси стали інтуїтивнішими та відшліфованішими, що кінцеві користувачі відчували безпосередньо, і це підняло загальну якість того, що випускалося.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Інтерфейси в проєктах компанії були нерівномірними за якістю. Деякі були непогані, деякі явно були побудовані інженерами, які думали про модель даних, а не про людину, якій доведеться цим користуватися, і рішення щодо дизайну не завжди ухвалювалися з думкою про кінцевого користувача. Особливо на вебкартографічному продукті карта — це найпростіша частина; саме в елементах керування, фільтрації та потоці навколо неї люди губляться.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Участь у процесі UI‑дизайну була частиною ролі — допомагати робити інтерфейси такими, що люди справді вважали б їх інтуїтивними та приємними у використанні, а не просто функціональними.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Роль не була роллю дизайнера, але вона була присутня в процесі дизайну і привносила інженерну перспективу — акцентуючи увагу на розкладці, на потоці проходження завдання, на тому, чи справді екран був зрозумілим, чи лише звичним для тих, хто його побудував. Це були фронтенди на React, Angular і Vue поверх карт Mapbox і Leaflet, і значна частина юзабіліті полягала в деталях: як фільтрувався набір даних, як відбувався перехід між поверхами на карті приміщення, чи повідомляла система, що саме вона робить. Здебільшого це означало ставити «наївні» запитання від імені користувача рано, поки їх було ще дешево виправити, а не після релізу, коли плутанина поверталася у вигляді звернень у підтримку.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Інтерфейси стали інтуїтивнішими та відшліфованішими, що кінцеві користувачі відчували безпосередньо, і це підняло загальну якість того, що випускалося. Те, що питання юзабіліті ставилися під час дизайну, а не після релізу, — це здебільшого і є те, що визначило різницю.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","GIS / геопростір","UX / UI‑дизайн","Веброзробка","Дизайн‑системи та UI","UI/UX‑дизайн та дизайн‑системи"]},{"id":"https://software.engineer.company/uk/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/","url":"https://software.engineer.company/uk/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/","title":"Реорганізувала внутрішні процеси, заощадивши 8 000 годин завдяки вдосконаленню архітектури програмного забезпечення, систем та ефективності планування.","summary":"Переробка зекономила приблизно 8 000 годин завдяки суттєвому підвищенню ефективності архітектури, систем і планування.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e У внутрішніх процесах накопичилися типові нашарування — архітектура програмного забезпечення, що розросталася стихійно, а не за задумом, системи, які працювали, але неефективно, і планування, через яке люди то простоювали, то були перевантажені. Нічого з цього не «горіло», саме тому це й залишали без змін, але тихо це коштувало багато часу.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Метою було докорінно переглянути ці процеси — знайти витрати й усунути їх, а не продовжувати за них платити.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Внутрішні процеси було перероблено за трьома напрямами: архітектуру програмного забезпечення — так, щоб її можна було логічно осмислювати й розвивати, а не обходити; системи — оптимізовано так, щоб рутинна робота більше не займала більше часу, ніж потрібно; і планування — так, щоб потужності справді відповідали обсягу роботи. Зміни закріпили так, щоб вони прижилися, — вбудували в те, як працює команда, а не залишили у вигляді меморандуму, який усі кивнули й забули, — адже покращення процесів, які не закріплюються, просто відкочуються назад до старого способу роботи.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Переробка зекономила приблизно 8 000 годин завдяки суттєвому підвищенню ефективності архітектури, систем і планування. Це потужності, які пішли безпосередньо на роботу з вищою цінністю, а не на накладні витрати, які раніше ніхто навіть не ставив під сумнів.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Автоматизація та CI/CD","Архітектура платформи","Архітектура рішень","Інфраструктура","Оптимізація продуктивності","Технічне лідерство","Управління проєктами","DevOps та автоматизація CI/CD","Архітектура платформи та рішень","Технічне лідерство та консалтинг","Управління проєктами (Agile)"]},{"id":"https://software.engineer.company/uk/portfolio/developed-a-data-analytics-reporting-system-increasing-quarterly-44/","url":"https://software.engineer.company/uk/portfolio/developed-a-data-analytics-reporting-system-increasing-quarterly-44/","title":"Розробила систему звітності Data Analytics, збільшивши квартальний дохід від програмного забезпечення на 400% завдяки PDF‑звітам на базі Python.","summary":"Саме ця звітність спричинила зростання квартального доходу від програмного забезпечення на 400%. Покращення й пришвидшення аналітики не було просто зручністю…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Зацікавлені сторони не отримували аналітику у своєчасній, зрозумілій формі. Дані існували, але перетворення їх на щось, на основі чого справді можна ухвалювати рішення, відбувалося повільно й вручну, тож видимість того, як усе працює, відставала, а разом із нею відставали й комерційні рішення.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завданням було побудувати систему звітності з аналізу даних — таку, що перетворювала б необроблені дані на чіткі, регулярні висновки без ручного складання щоразу.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Систему звітності, яка генерувала PDF‑звіти на Python, було побудовано так, щоб автоматизувати весь ланцюжок: вибірку даних, проведення аналізу та представлення результатів у чіткому, узгодженому форматі, який зацікавлені сторони справді могли прочитати. Суть полягала в регулярності та ясності — той самий професійний звіт з\u0026rsquo;являвся передбачувано, тож цифри стали тим, на що люди дивилися як на звичну справу, а не тим, що доводилося самостійно розшукувати.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Саме ця звітність спричинила зростання квартального доходу від програмного забезпечення на 400%. Покращення й пришвидшення аналітики не було просто зручністю для бек‑офісу — коли перед людьми, які ухвалюють комерційні рішення, з\u0026rsquo;являються чіткі й своєчасні цифри, рішення стають кращими, і тут це напряму позначилося на доході.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Python","Автоматизація та CI/CD","Аналітика даних","Інженерія даних","Продукт і вимоги","Стейкхолдери та звітність","Backend- та API‑розробка","Аналітика даних та BI‑дашборди","Продуктова стратегія та вимоги"]},{"id":"https://software.engineer.company/uk/portfolio/developed-100-web-applications-using-html-html5-css-51/","url":"https://software.engineer.company/uk/portfolio/developed-100-web-applications-using-html-html5-css-51/","title":"Розробила 100 вебзастосунків за допомогою HTML/HTML5, CSS/SCSS, Django, WordPress та Joomla, забезпечивши різноманітну онлайн‑присутність.","summary":"Сто застосунків дали клієнтам різноманітну, дієву присутність онлайн, кожен реалізований на технології, яка справді йому підходила.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Клієнти хотіли вебзастосунки, і хотіли вони дуже різні речі — різні масштаби, різні бюджети, різні рівні від «просто виведіть мене онлайн» до «зробіть мені щось індивідуальне». Відповідати цьому означало бути універсальним, а не заганяти кожного клієнта в межі однієї й тієї самої технології.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб створювати вебзастосунки, які давали б кожному клієнту різноманітну й ефективну присутність онлайн.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Було створено сто вебзастосунків, і суть полягала в тому, щоб підбирати інструмент під завдання, а не мати улюблений. Там, де клієнту потрібне було щось індивідуальне, у хід ішли HTML/HTML5, CSS/SCSS та Django; там, де потрібне було щось більш стандартне, з чим клієнт міг би впоратися і самостійно, швидшою й розумнішою відповіддю ставали WordPress або Joomla. Частина майстерності полягала саме в тому, щоб розрізняти ці випадки — відмовити клієнту в індивідуальній розробці, яка йому не потрібна, або переконати в тій, яка потрібна.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Сто застосунків дали клієнтам різноманітну, дієву присутність онлайн, кожен реалізований на технології, яка справді йому підходила. Саме підбір підходу під клієнта, а не навпаки, зробив їх ефективними, а не просто зданими в експлуатацію.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Frontend‑розробка","Full‑Stack розробка","Python","Веброзробка","Full‑Stack продуктова розробка","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/designed-30-websites-delivering-unique-and-flexible-solutions-52/","url":"https://software.engineer.company/uk/portfolio/designed-30-websites-delivering-unique-and-flexible-solutions-52/","title":"Спроєктувала 30 вебсайтів, надавши унікальні та гнучкі рішення завдяки перетворенню дизайнів Photoshop на HTML.","summary":"Тридцять сайтів відповідали своїм дизайнам і залишалися придатними до роботи — самобутні, вишукані вебсайти, які не ламалися від першого ж редагування…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Клієнти приходили з бажаним виглядом сайту — часто це вже був готовий візуальний дизайн — і потребували, щоб вебсайт був побудований точно за ним. Розрив між файлом дизайну та робочим сайтом — це саме те місце, де здебільшого виграється або втрачається якість: легко здати щось приблизно правильне, але з непомітними відхиленнями.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб проєктувати сайти й перетворювати дизайни на точні, гнучкі реалізації.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Спроєктовано тридцять вебсайтів, і дизайни з Photoshop вручну перетворено на HTML. Точність була стандартом — відступи, типографіка, деталі, які насправді мав на увазі дизайнер, а не їх наближення — але так само важливою була і гнучкість, адже сайт, який збігається з макетом піксель у піксель, а потім розвалюється щойно змінюється контент, насправді побудовано погано. Тож мета полягала в розмітці, яка залишалася вірною дизайну і водночас лишалася придатною до подальшої підтримки.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Тридцять сайтів відповідали своїм дизайнам і залишалися придатними до роботи — самобутні, вишукані вебсайти, які не ламалися від першого ж редагування контенту. Вірність дизайну при збереженні придатності до підтримки — саме той баланс, що мав значення, і саме до нього прийшли ці сайти.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Веброзробка","Дизайн‑системи та UI","UI/UX‑дизайн та дизайн‑системи","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/","url":"https://software.engineer.company/uk/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/","title":"Адмініструвала 40 вебсайтів на хостинг‑серверах Ubuntu Linux з Apache та Nginx, забезпечивши високу доступність і продуктивність.","summary":"Усі сорок сайтів працювали з високою доступністю та гарною продуктивністю, що дало клієнтам хостинг, про який не треба було думати.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Існував портфель робочих вебсайтів, які мали залишатися онлайн і швидкими — а хостинг це ще одна з тих робіт, які непомітні, доки сайт не впаде, і от тоді про нього думають усі й нічого більше.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб адмініструвати ці сайти та підтримувати їхню високу доступність і швидкість.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Сорок вебсайтів працювали на хостинг‑серверах Ubuntu Linux, на поєднанні Apache та Nginx — конфігурація, налаштування продуктивності, постійне обслуговування для підтримання надійності під реальним трафіком. Саме реальний трафік тут ключовий: сайт, який нормально почувається, коли ним ніхто не користується, і падає, щойно ним починають користуватися, насправді не адмініструвався — його просто залишили без уваги. Тож робота полягала в тому, щоб підтримувати їхню справність під фактичним навантаженням.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Усі сорок сайтів працювали з високою доступністю та гарною продуктивністю, що дало клієнтам хостинг, про який не треба було думати. Стабільність і надійність під реальним використанням — це вся суть хостингу, і саме це забезпечили ці сайти.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Linux та сервери","Веброзробка","Інфраструктура","Надійність і резервне копіювання","Оптимізація продуктивності","Системне адміністрування","Надійність та моніторинг (SRE)","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/","url":"https://software.engineer.company/uk/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/","title":"Спроєктувала, розробила, впровадила та підтримувала інфраструктуру, обробку даних і картографічний застосунок безперервно протягом 2 років без вихідних, свят чи відпустки, по 10–14 годин на день.","summary":"Платформа залишалася безперервно доступною та еволюціонувала від крихкого раннього прототипу до надійного хребта продукту, підтримуючи компанію протягом…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Стартап у сфері зеленої енергетики на ранній стадії розвитку залежав від єдиної платформи для відстеження, моніторингу та оптимізації активів відновлюваної енергетики, проте не мав ані окремої інфраструктурної команди, ані сформованої інженерної організації для її побудови й експлуатації. Усю технічну основу — хмарну інфраструктуру, пайплайни обробки даних і клієнтський GIS‑застосунок з картою — потрібно було створити й підтримувати в безперервній роботі на ринку, де будь‑який простій чи розрив у даних напряму підривав довіру клієнтів і дохід.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб одноосібно спроєктувати, побудувати та експлуатувати всю систему наскрізно, охоплюючи інженерію платформи й даних, DevOps та забезпечення надійності (site reliability). Окрім написання коду, це означало відповідальність за продакшн: розгортання та убезпечення інфраструктури, проєктування рівня обробки даних, що живив карту, і гарантування безперервної доступності застосунку для зростаючої бази клієнтів — і все це в межах обмежень і невпинного темпу стартапу, що стрімко розвивався.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Протягом двох років інфраструктура, пайплайни даних і картографічний застосунок проєктувалися, впроваджувалися та підтримувалися без перерв — без вихідних, свят чи відпусток, часто по 10–14 годин на день. Було обрано прагматичну, модульну архітектуру, щоб зберегти придатність до підтримки одноосібної експлуатації, з автоматизованим розгортанням, моніторингом та сповіщеннями, аби проблеми виявлялися й вирішувалися швидко. Обробка даних постійно донастроювалася для надійності та продуктивності, релізи випускалися поступово, і кожен рівень — від серверів до карти, орієнтованої на користувача, — підтримувався та вдосконалювався особисто, у відповідь на реальне використання клієнтами.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Платформа залишалася безперервно доступною та еволюціонувала від крихкого раннього прототипу до надійного хребта продукту, підтримуючи компанію протягом критичної фази зростання завдяки одноосібній відповідальності одного інженера. Таке безпосереднє, практичне управління забезпечувало достатню надійність інфраструктури, даних і картографічного застосунку для підтримки допродажів, ліцензування даних і залучення нових клієнтів, а також продемонструвало рідкісний рівень відданості, широти охоплення й наскрізної відповідальності на всіх рівнях стеку.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Full‑Stack розробка","GIS / геопростір","Архітектура платформи","Інженерія даних","Інфраструктура","Надійність і резервне копіювання","Пайплайни даних (ETL/ELT)","Full‑Stack продуктова розробка","GIS та геопросторові рішення","Архітектура платформи та рішень","Надійність та моніторинг (SRE)","Розробка пайплайнів даних (ETL/ELT)"]},{"id":"https://software.engineer.company/uk/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/","url":"https://software.engineer.company/uk/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/","title":"Оптимізувала бюджетні витрати у 10 разів без втрати продуктивності для міжнародного клієнта, переосмисливши загальну інфраструктуру, усунувши непотрібні сервіси та перенісши систему з хмари AWS.","summary":"Бюджетні витрати скоротилися приблизно у 10 разів, без жодної втрати продуктивності — та сама спроможність за частку тієї суми, яку сплачували раніше.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Міжнародний клієнт ніс на собі суттєво роздуті інфраструктурні витрати. Її налаштування AWS було надлишково забезпечене ресурсами й накопичило сервіси, якими вже ніхто не користувався, тож рахунок за хмару повністю вийшов з будь‑якої пропорції до того, що бізнесу дійсно було потрібно. Історія звична — ніхто не планує перевитрачати, це просто накопичується, коли ніхто не стежить за лічильником.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб суттєво скоротити витрати без жодної втрати продуктивності, а це означало по‑справжньому переосмислити інфраструктуру, а не підрізати по краях — підрізання по краях рідко відчутно змінює рахунок, який структурно є занадто великим.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Тож робота велася наскрізно. Спочатку проведено аудит того, що фактично використовувалося — саме тут проявляють себе дубльовані та непотрібні сервіси — і їх було прибрано. Потім усе, що залишилося, приведено у відповідність до реального попиту замість розрахунків на найгірший сценарій, закладених у початкове налаштування. А головним кроком стало повне перенесення навантажень з AWS на більш економічно вигідний варіант хостингу — виконане обережно, поетапно, так, щоб діючий бізнес жодного разу не відчув, як під ним відбувається міграція.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Бюджетні витрати скоротилися приблизно у 10 разів, без жодної втрати продуктивності — та сама спроможність за частку тієї суми, яку сплачували раніше. Це вивільнило реальну суму коштів, яка місяць за місяцем тихо витікала у надто великий рахунок за хмару, а для бізнесу це означало гроші, що напряму повернулися до чистого прибутку.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Cloud","DevOps","Архітектура платформи","Архітектура рішень","Інфраструктура","Міграції та модернізація","DevOps та автоматизація CI/CD","Архітектура платформи та рішень","Хмарна інфраструктура та міграція"]},{"id":"https://software.engineer.company/uk/portfolio/architected-a-layered-maritime-platform-separating-a-next-57/","url":"https://software.engineer.company/uk/portfolio/architected-a-layered-maritime-platform-separating-a-next-57/","title":"Спроєктувала багаторівневу морську платформу, розділивши фронтенд Next.js PWA, API на Go (Huma/Fiber) та рівень функцій PostgreSQL, зберігши всю бізнес‑логіку в базі даних.","summary":"Систему й далі було легко тримати в голові. Бізнес-логіка розташована в одному місці, яке справді можна перевірити, API — нудний у хорошому сенсі адаптер, а…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Продукт мав стати морською платформою — професійні мережі, відгуки про компанії, спонсорована освіта — і це був молодий продукт, що є ввічливим способом сказати, що вимоги мали суттєво змінюватися. Чого варто було уникнути — це архітектури, у якій зміна бізнес‑правила означала одночасне втручання у фронтенд, API та базу даних. На невеликій кодовій базі, яка швидко росте, саме такий рівень зв\u0026rsquo;язаності перетворює зміну у два рядки коду на роботу на ціле пообіддя.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Як архітектору, першим рішенням, яке треба було ухвалити, було те, де мала жити кожна логіка, з межами, достатньо чіткими, щоб витримувати тиск, а не розмиватися, щойно хтось поспішав.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Усе усталилося у три рівні, кожен зі своєю роллю. Фронтенд на Next.js відповідає за представлення й інтерактивність і більше ні за що. API на Go — Huma поверх Fiber — навмисно тонкий: він маршрутизує, валідує запит, застосовує фільтрацію безпеки та оркеструє, але не містить жодної бізнес‑логіки. Уся бізнес‑логіка живе у функціях PostgreSQL, які збирають повний результат і повертають його, щоб API просто передав далі. Тож коли правило змінюється, воно змінюється в одному рівні, у SQL, а решта двох про це навіть не знають. Межі було зафіксовано письмово, а потім закріплено через код‑рев\u0026rsquo;ю, адже конвенція, яку ніхто не контролює, перестає бути конвенцією.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Систему й далі було легко тримати в голові. Бізнес‑логіка розташована в одному місці, яке справді можна перевірити, API — нудний у хорошому сенсі адаптер, а фронтенд не переймається, коли схема змінюється під ним. Саме це розділення дало продукту змогу й далі нарощувати функціональність без тихого гниття архітектури.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Frontend‑розробка","Full‑Stack розробка","PostgreSQL","Архітектура платформи","Архітектура рішень","Бази даних","Технічне лідерство","Backend- та API‑розробка","Full‑Stack продуктова розробка","Архітектура платформи та рішень","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/designed-a-json-passthrough-architecture-where-postgresql-functions-58/","url":"https://software.engineer.company/uk/portfolio/designed-a-json-passthrough-architecture-where-postgresql-functions-58/","title":"Спроєктувала архітектуру наскрізної передачі JSON, у якій функції PostgreSQL повертають повний JSON, що дослівно пересилається через Go API, усунувши проміжний unmarshalling та унезалежнивши фронтенд від змін схеми.","summary":"Код обробників став суттєво коротшим, а що важливіше — фронтенд перестав бути прив'язаним до Go. Достатньо змінити те, що повертає функція, і нова форма даних…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Звичний шлях даних від бази до браузера — це естафета трансформацій. База даних передає API рядки, API десеріалізує їх у структури (structs), переформатовує, серіалізує назад у JSON, і лише тоді дані йдуть далі. Кожен із цих переходів — це код, який потрібно написати, код, який потрібно протестувати, і ще одне місце, де уявлення API про дані та уявлення бази даних про них можуть розійтися.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Ідея полягала в тому, щоб прибрати цю естафету. Якщо база даних могла б повертати готову відповідь, API міг би просто передавати її далі, а фронтенд міг би залежати безпосередньо від форми даних бази даних замість її вручну підтримуваної копії, що живе в Go.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Тож це було побудовано як пряму передачу без проміжних перетворень. Функції PostgreSQL збирають усю відповідь у вигляді JSON — формування є завданням SQL, виконуваним там, де дані вже є. Обробник на Go отримує це назад як json.RawMessage і передає далі без змін; він ніколи не розкладає це на частини, ніколи не перекодовує. Невеликий допоміжний метод QueryJSON перетворив цей патерн на шлях найменшого опору, а не на те, про що щоразу треба пам\u0026rsquo;ятати окремо. Випало все проміжне обладнання, яке зазвичай накопичує традиційний шаруватий API — DTO, мапери, структури відповідей.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Код обробників став суттєво коротшим, а що важливіше — фронтенд перестав бути прив\u0026rsquo;язаним до Go. Достатньо змінити те, що повертає функція, і нова форма даних напряму доходить до клієнта без редагування жодного рядка коду обробника. Менше рухомих частин, і цілий клас розбіжностей між рівнями тут просто не існує.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","PostgreSQL","SQL","Архітектура платформи","Бази даних","Оптимізація продуктивності","Backend- та API‑розробка","Архітектура платформи та рішень","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/designed-an-organization-context-switching-system-with-client-59/","url":"https://software.engineer.company/uk/portfolio/designed-an-organization-context-switching-system-with-client-59/","title":"Спроєктувала систему перемикання контексту організації з клієнтським localStorage та серверним дзеркалюванням cookie, що дозволила користувачам діяти від імені керованих організацій, забезпечуючи авторизацію за принципом найменших привілеїв.","summary":"Користувач може діяти від імені будь-якої організації, якою керує, без жодних перешкод, а інтерфейс залишається синхронізованим і на клієнті, і на сервері.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e На платформі морський фахівець може керувати організаціями — компаніями, академіями — які не мають власних облікових записів для входу. Обліковим записом є сама людина; організація — це те, від імені чого вона діє. Тож користувачу потрібно переміщуватися по всьому застосунку як будь‑яка з організацій, якими він керує, вільно перемикаючись між ними, і ця зручність не повинна перетворюватися на діру в авторизації.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Перемикання контексту мало бути швидким і непомітним для користувача, і водночас потрібно було гарантувати, що активний контекст сам собою ніколи не надасть доступу, на який немає прав.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e За це відповідає OrganizationContext зі зберіганням стану на обох сторонах. На клієнті джерелом істини щодо того, від імені якої організації користувач наразі діє, є localStorage, тож перемикання відбувається миттєво — без звернення до сервера. Серверний cookie дзеркалить цей стан, щоб сторінки, що рендеряться на сервері, визначали той самий контекст під час SSR; на сервері є getServerViewMode, який його зчитує. Важливо, що жодне з цього не використовується для ухвалення рішень щодо доступу. Авторизація повторно перевіряється на сервері під час кожного запиту. Контекст на фронтенді існує заради досвіду користування — показати саме те, що потрібно, — а сервер є єдиним джерелом істини щодо того, що дозволено робити.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Користувач може діяти від імені будь‑якої організації, якою керує, без жодних перешкод, а інтерфейс залишається синхронізованим і на клієнті, і на сервері. Але оскільки права щоразу перевіряються на сервері, ця зручність жодним чином не послаблює безпеку. Втручання у вміст localStorage змінює лише те, що бачить власний інтерфейс користувача, і нічого більше — сервер усе одно відмовить.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Frontend‑розробка","Full‑Stack розробка","Архітектура платформи","Безпека","Backend- та API‑розробка","Архітектура платформи та рішень","Безпека та керування доступом"]},{"id":"https://software.engineer.company/uk/portfolio/migrated-the-http-api-from-fiber-to-huma-60/","url":"https://software.engineer.company/uk/portfolio/migrated-the-http-api-from-fiber-to-huma-60/","title":"Мігрувала HTTP API з Fiber на Huma v2 — 649 шляхів і 760 операцій — досягнувши та втримавши 100% відповідність між маршрутами, які реєструє сервер, і описом OpenAPI, який він публікує.","summary":"Нові ендпоінти отримують валідацію та актуальну документацію без додаткових зусиль, а цілий клас помилок обробки запитів — на кшталт «ой, а тут ми забули…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e API розпочинав своє життя на Fiber, із валідацією запитів, написаною вручну для кожного ендпоінта окремо. Це нормально, коли ендпоінтів жменька. Але перестає бути нормальним, коли поверхня API розростається: рукописна валідація перетворюється на податок на підтримку, а дрібні неузгодженості накопичуються, бо перевірки кожного ендпоінта — це своя окрема сніжинка. І ніде не було жодного єдиного опису форми API.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Метою було отримати валідацію, що походить із типів, а не з рукописних перевірок, і справжній контракт, який описує API, — без зупинки на повномасштабне переписування.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e HTTP‑рівень перенесено на Huma v2 поверх Fiber, тож наявний рантайм зберігся. Кожен ендпоінт отримує вхідні та вихідні структури (structs), а Huma генерує валідацію запитів і моделювання відповіді на основі цих типів. Опис OpenAPI виходить із цього безкоштовно, а це означає, що документація йде в ногу з кодом, а не застаріває десь у вікі. Усе нове писалося під Huma, а наявні маршрути перенесено, залишивши рівно два ендпоінти на чистому Fiber — це WebSocket‑ендпоінти, де справді потрібен саме сокет, а модель запиту/відповіді Huma не підходить. Те, у що це виросло, — 649 шляхів із 760 операціями та перевірка в CI, яка порівнює маршрути, що їх сервер справді реєструє, з тими, що їх декларує опис OpenAPI. Паритет становить 100%, і він там і лишається, бо маршрут, який не описано, завалює білд.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Нові ендпоінти отримують валідацію та актуальну документацію без додаткових зусиль, а цілий клас помилок обробки запитів — на кшталт «ой, а тут ми забули перевірити це поле» — зник. На 760 операціях цей опис — єдиний практичний спосіб, у який хтось узагалі читає API, тож гарантія його повноти важить більше, ніж важила на п\u0026rsquo;ятдесяти. Типізований контракт зробив API одночасно безпечнішим для змін і простішим для передачі іншій людині, адже типи самі повідомляють, чого очікує ендпоінт.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Архітектура платформи","Документація","Міграції та модернізація","Тестування та QA","Backend- та API‑розробка","Архітектура платформи та рішень","Технічна документація"]},{"id":"https://software.engineer.company/uk/portfolio/built-a-request-schema-validation-contract-with-automated-61/","url":"https://software.engineer.company/uk/portfolio/built-a-request-schema-validation-contract-with-automated-61/","title":"Згенерувала контракт API з бази даних назовні — OpenAPI, типізований TypeScript‑клієнт на 44 076 рядків, 61 mock‑обробник та обмеження, які застосовує UI, — з перевіркою на кожній ланці, що падає при розходженні.","summary":"Поле не може змінитися лише з одного боку — воно завалюється на першому ж переході, який це помічає, у білді, за кілька хвилин після зміни.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Фронтенд і бекенд розвиваються у власному темпі, і їхні уявлення про payload запиту можуть непомітно розходитися. Зазвичай про це дізнаються за 422 у браузері — вже після того, як розбіжність потрапила в продакшн, а це найдорожчий момент, щоб про неї дізнатися. Написання обох сторін вручну за одним документом цього не виправляє: воно лише переносить розбіжність на того, хто забув перечитати документ.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Обидві сторони мали генеруватися з одного джерела, а не узгоджуватися між двома, і кожен крок цієї генерації мав перевірятися, а не братися на віру.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Ланцюг починається з бази даних і йде назовні. Схема та її функції визначають структури даних; типи Go визначають API; Huma формує з них опис OpenAPI; з цього опису генерується типізований клієнт TypeScript — 44 076 рядків; поряд із ним генерується 61 mock‑обробник, тож власні тести фронтенду виконуються проти реального контракту, а не проти рукописної фікстури; а обмеження, які UI застосовує до форми, походять із того самого місця, замість того щоб їх перенабирали у валідаторі. Кожен перехід має запобіжник. Перевірка контракту в CI порівнює те, що надсилає фронтенд, із тим, що очікує API, і завалює білд за розбіжності, а під нею є перевірка схеми, яка звіряє реальну структуру даних, а не її опис. Вона свідомо охоплює місця, де розбіжності люблять ховатися: опціональні поля тіла запиту, де плутають «відсутнє» і null, та enum‑и query‑параметрів, де обидві сторони можуть тихо розійтися в допустимих значеннях.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Поле не може змінитися лише з одного боку — воно завалюється на першому ж переході, який це помічає, у білді, за кілька хвилин після зміни. Це усунуло повторюваний і по‑справжньому набридливий клас багів: непомітний під час code review і такий, що проявляється лише в рантаймі. Ціна — крок генерації посеред усього: перегенерація є рутиною, а ланцюг вартий довіри рівно настільки, наскільки надійна його найменш захищена ланка, — тому запобіжник отримав кожен перехід.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","DevOps","Автоматизація та CI/CD","Надійність і резервне копіювання","Тестування та QA","Backend- та API‑розробка","DevOps та автоматизація CI/CD"]},{"id":"https://software.engineer.company/uk/portfolio/built-email-as-a-platform-capability-with-failover-62/","url":"https://software.engineer.company/uk/portfolio/built-email-as-a-platform-capability-with-failover-62/","title":"Побудувала електронну пошту як можливість платформи — три провайдери з резервним перемиканням, webhooks доставки, логування надсилання й доставки, шаблонізацію та кампанії — за перевіркою під час запуску, яка не дасть застосунку стартувати без жодного з них.","summary":"Ціла категорія тихих збоїв перейшла зі стану «користувач помічає це через кілька днів» у стан «розгортання зупиняється», а невдалий день у провайдера став…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Електронна пошта відіграє значну роль на платформі — верифікація, сповіщення, дайджести, кампанії, усе те, на що користувач насправді чекає. А поштовий провайдер — це саме той тип залежності, що тихо ламається: конфігурація виглядає нормально, застосунок запускається, і про проблему дізнаються лише тоді, коли реальна людина так і не отримує обіцяного листа. Це найгірший спосіб про це дізнатися. З одним провайдером усе ще гірше, бо збій є повним, а виправляти його — комусь іншому.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Пошту потрібно було трактувати як спроможність, якою володіє платформа, а не як клієнтську бібліотеку, яку вона викликає, — здатну пережити збій провайдера, здатну сказати, що сталося з конкретним листом, і голосну під час запуску в тих середовищах, де мовчання небезпечне.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Три провайдери стоять за одним інтерфейсом — SendGrid як основний, а SMTP2GO та Azure Communication Services позаду нього, — і перемикання між ними автоматичне, а не є зміною конфігурації, зробленою під тиском. Доставка не вважається даністю: вхідні webhooks повідомляють, що кожен провайдер зробив із листом, і обидві сторони записуються — у журнал надсилань і таблицю подій доставки, — тож «чи отримала ця людина свій лист із верифікацією» є запитом, а не здогадом. Шаблонізація тримає тіла листів поза кодом, а окрема схема broadcast — 5 таблиць і 24 функції — доставляє кампанії сегментам користувачів, і це інша задача, ніж транзакційна пошта, тож її й будували як іншу. Перед усім цим стартова перевірка надсилає реальний лист через увесь стек, за прапорцем: у середовищі розробки це просто логує попередження й продовжує роботу, бо ніхто не хоче, щоб ноутбук відмовлявся запускатися через прострочений ключ пісочниці, а в staging і production збій є фатальним і процес завершується, а не розгортає білд, який не може надсилати пошту. Сам шлях надсилання проходить через клієнт із захистом від SSRF і тайм‑аутом 30 секунд, а асинхронний шлях доставки має retries і backoff, тож короткочасний збій не втрачає повідомлення.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Ціла категорія тихих збоїв перейшла зі стану «користувач помічає це через кілька днів» у стан «розгортання зупиняється», а невдалий день у провайдера став деградованим шляхом, а не аварією. Ціна — три інтеграції, які треба підтримувати робочими замість однієї, і журнали доставки, що ростуть і потребують чищення; обидві прийнятні, бо пошта — це канал, який платформа не може обійти.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Cloud","Безпека","Надійність і резервне копіювання","Backend- та API‑розробка","Безпека та керування доступом","Надійність та моніторинг (SRE)"]},{"id":"https://software.engineer.company/uk/portfolio/designed-a-postgresql-function-first-data-layer-across-63/","url":"https://software.engineer.company/uk/portfolio/designed-a-postgresql-function-first-data-layer-across-63/","title":"Спроєктувала рівень даних PostgreSQL, побудований насамперед на функціях — 1 275 збережених функцій у 34 схемах — щоб кожне читання й кожен запис проходили через функцію, на яку база даних може видати права, а не через таблицю.","summary":"Логіка живе в одному місці, яке справді можна перевірити, API лишається тонким і нудним у хорошому сенсі, а межу доступу забезпечує сам Postgres, а не те, що…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Бізнес‑логіка має звичку просочуватися. Частина потрапляє в API, частина — у якийсь SQL, що виконується прямо в обробнику, і незабаром те саме правило виявляється записаним двома‑трьома трохи різними способами, і немає жодного місця, на яке можна вказати й сказати: «ось що система робить зі своїми даними». Так у систему потрапляють баги й діри в безпеці.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Метою було одне місце для всього цього: кожне читання й запис проходить через базу даних, API залишається тонким адаптером, який не знає бізнес‑правил, а все разом можна щільно замкнути.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Рівень даних побудовано за принципом function‑first. Схему поділено за доменами — identity, organization, review, message, notification і ще 29 інших, 34 разом, — і кожна операція, яку може виконати застосунок, є однією з 1 275 функцій PostgreSQL, які він викликає; прямого доступу до таблиць із Go взагалі немає. Далі це забезпечує сама база даних. Роль, під якою логіниться API, mariner, має EXECUTE на функціях застосунку та USAGE на схемах — і нічого більше: жодного SELECT, жодного INSERT, жодного способу торкнутися таблиці напряму — а це виходить приблизно 4 000 явних грантів, а не один загальний. Функції виконуються як SECURITY DEFINER, належать окремій non‑login ролі function_owner із зафіксованим search_path, а обліковий запис суперкористувача лишається зарезервованим для міграцій і cron, подалі від застосунку, що працює.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Логіка живе в одному місці, яке справді можна перевірити, API лишається тонким і нудним у хорошому сенсі, а межу доступу забезпечує сам Postgres, а не те, що всі пам\u0026rsquo;ятають правила. Якщо API раптом буде скомпрометовано, воно все одно не зможе зробити нічого, чого не дозволяють функції. На 1 275 функціях ця дисципліна коштує чогось реального — нове поле означає міграцію та зміну функції, а не рядок у запиті, — і це тертя є ціною того, що межа тримається.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Data Governance","PostgreSQL","SQL","Архітектура платформи","Бази даних","Безпека","Backend- та API‑розробка","Data Governance та якість даних","Архітектура платформи та рішень","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/implemented-a-catalogue-driven-deep-merge-for-stored-65/","url":"https://software.engineer.company/uk/portfolio/implemented-a-catalogue-driven-deep-merge-for-stored-65/","title":"Впровадила deep‑merge на основі каталогу для збережених JSON‑налаштувань, запобігши збоям через відсутні ключі при еволюції схеми.","summary":"Налаштування можуть зростати без побоювань. Додавання параметра більше не ризикує крашем через undefined-поле на клієнті, а фронтенд перестав потребувати…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Платформа зберігає JSON‑налаштування — налаштування сповіщень і подібне — як збережені значення користувача, накладені поверх набору значень за замовчуванням. Початкове злиття робило це на одному рівні. Проблема виявляється пізніше: додається новий ключ до значень за замовчуванням, а рядки, збережені до появи цього ключа, просто його не мають. Тоді якийсь клієнтський код читає це поле, отримує undefined і падає — саме для тих користувачів, які тут найдовше.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Розвиток схеми налаштувань мав бути безпечним, щоб додавання нового параметра ніколи не ламало людей, які зареєструвалися до того, як він з\u0026rsquo;явився.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Однорівневе злиття замінено на deep‑merge, керований значеннями за замовчуванням як каталогом. Значення за замовчуванням розглядаються як авторитетний перелік усіх ключів, які мають існувати; збережені значення користувача рекурсивно накладаються зверху, тож усе, що є в каталозі, гарантовано присутнє на виході — незалежно від того, чи було воно в збереженому blob. Додається ключ до значень за замовчуванням — і він автоматично з\u0026rsquo;являється в ефективних налаштуваннях кожного наявного рядка, включно з вкладеними ключами. Це впроваджено через міграцію, тож наявні дані отримали перевагу одразу, а не чекали на переписування.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Налаштування можуть зростати без побоювань. Додавання параметра більше не ризикує крашем через undefined‑поле на клієнті, а фронтенд перестав потребувати захисних перевірок, розкиданих у кожному місці, де він читає налаштування. Це також дало решті платформи надійний спосіб розширювати будь‑який збережений JSON‑blob — не лише окреме виправлення, а й сам патерн.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Data Governance","PostgreSQL","Бази даних","Міграції та модернізація","Backend- та API‑розробка","Data Governance та якість даних","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/modeled-the-maritime-domain-professionals-companies-ships-jobs-67/","url":"https://software.engineer.company/uk/portfolio/modeled-the-maritime-domain-professionals-companies-ships-jobs-67/","title":"Змоделювала морський домен — фахівців, компанії, судна, вакансії, відгуки та решту — у 348 нормалізованих таблицях у межах 34 схем PostgreSQL, з довідниками SMALLINT та ключами UUID v7.","summary":"Результатом стала модель даних, яка є послідовною і швидкою, а працювати з нею передбачувано, бо ті самі правила діють усюди — немає особливих випадків, які…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Серцем платформи є щільний морський домен — фахівці, компанії, судна, вакансії, відгуки, — і всі ці сутності постійно посилаються одна на одну. Фахівець ходить у рейси на суднах, працює в компаніях, залишає відгуки; компанія володіє суднами й публікує вакансії. Майже кожна функція — це запит через усю цю мережу зв\u0026rsquo;язків, тож від того, наскільки добре змодельовані дані, залежить, наскільки добре працює більшість застосунку і наскільки розумно його розширювати.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Цей домен потрібно було змоделювати так, щоб він лишався швидким і зберігав цілісність, а додавання наступного типу сутності не перетворювалося на боротьбу зі схемою.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Дані організовано як нормалізовані схеми PostgreSQL, згруповані за доменами, — 348 таблиць у 34 схемах на цей момент. Численні дрібні стабільні переліки — статуси, типи, категорії — перетворено на довідкові таблиці SMALLINT, що робить рядки компактними, а джойни дешевими, замість того щоб зберігати текстові коди всюди. Сутності отримують первинні ключі UUID v7, тож вони глобально унікальні, але водночас часово впорядковані в індексі. Крізь усе проходить одна угода про іменування — таблиці в множині всередині схем з іменами в однині, — застосована без винятків, що як бонус дає змогу уникнути багатьох конфліктів із зарезервованими словами. А зв\u0026rsquo;язки підтримуються реальними foreign key та constraints, тож цілісність — це робота бази даних, а не те, що застосунок мусить пам\u0026rsquo;ятати сам.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Результатом стала модель даних, яка є послідовною і швидкою, а працювати з нею передбачувано, бо ті самі правила діють усюди — немає особливих випадків, які треба запам\u0026rsquo;ятовувати. Додавання функції зазвичай означає розширення схеми за наявною логікою, а не боротьбу проти неї, і це єдина причина, чому 34 схеми — це структура, а не розповзання. Це той фундамент, на якому стоїть решта платформи.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Data Governance","PostgreSQL","SQL","Архітектура платформи","Бази даних","Інженерія даних","Оптимізація продуктивності","Data Governance та якість даних","Архітектура платформи та рішень","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/built-the-next-js-16-frontend-with-deliberate-73/","url":"https://software.engineer.company/uk/portfolio/built-the-next-js-16-frontend-with-deliberate-73/","title":"Побудувала фронтенд на Next.js 16 зі свідомими стратегіями SSR, SSG і CSR та багаторазовою фабрикою prefetched‑server‑page, що усуває каскад N+1 на кожній автентифікованій сторінці, перенесеній на неї.","summary":"Сторінки, перенесені на цю фабрику, піднімаються за одне звернення замість шторму звернень, а оскільки це фабрика, а не патерн, який копіюють вручну, наступна…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Автентифікований дашборд мав відчуватися швидким і водночас залишатися по‑справжньому інтерактивним, а ці дві мети тягнуть у різні боки, якщо підійти до них наївно. Якщо забирати все на клієнті, перше завантаження затягується, а гірше — виникає патерн N+1, коли кожен компонент прокидається і робить власний запит, тож одна сторінка перетворюється на каскад мережевих звернень.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Кожну частину застосунку потрібно було рендерити саме так, як їй насправді підходило, не жертвуючи клієнтською інтерактивністю там, де вона мала значення.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Фронтенд на Next.js 16 використовує для кожної поверхні застосунку той режим, який їй підходить, замість одного рішення на всі випадки. Маркетингові й публічні сторінки генеруються статично — вони не змінюються залежно від користувача, тож рендерити їх на кожен запит немає сенсу. Справді інтерактивні частини лишаються клієнтськими. А там, де каскад N+1 справді дошкуляє, — автентифікований дашборд і великі сторінки‑каталоги — рішення винесли у фабрику, а не робили вручну: createPrefetchedServerPage отримує дані сторінки на сервері й передає їх клієнту вже заповненими, тож компоненти одразу з\u0026rsquo;являються зі своїми даними, а не йдуть по них кожен окремо. Стратегія інвалідації кешу задокументована для кожного запиту, тож дані лишаються актуальними без повторного завантаження того, що застосунок уже має.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Сторінки, перенесені на цю фабрику, піднімаються за одне звернення замість шторму звернень, а оскільки це фабрика, а не патерн, який копіюють вручну, наступна перенесена сторінка успадковує цю поведінку безкоштовно. Решта автентифікованого застосунку досі рендериться на клієнті й стоїть у черзі за нею — це міграція з робочим механізмом і очевидною наступною сторінкою, а не завершений перехід.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","Full‑Stack розробка","Архітектура платформи","Веброзробка","Оптимізація продуктивності","Full‑Stack продуктова розробка","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/delivered-full-progressive-web-app-support-installable-and-74/","url":"https://software.engineer.company/uk/portfolio/delivered-full-progressive-web-app-support-installable-and-74/","title":"Реалізувала повну підтримку Progressive Web App — з можливістю встановлення та офлайн‑роботи — з кешуванням Workbox під час виконання через next‑pwa.","summary":"Користувачі можуть встановити застосунок і продовжувати користуватися ним офлайн, а повторні завантаження швидко повертаються з кешу замість мережі.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Значна частина користувачів платформи перебуває в морі. Моряки та польовий персонал працюють з телефонів, часто офлайн або на нестабільному з\u0026rsquo;єднанні, — це не люди за робочим столом зі стабільним офісним wifi. Якби застосунок будувався так, ніби в усіх є швидка й постійна мережа, це непомітно відсікло б значну частину реальної аудиторії.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Застосунок мав встановлюватися як нативний і залишатися придатним до використання навіть при зникненні мережі.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Продукт постачається як повноцінний Progressive Web App. Він встановлюється на головний екран з коректними іконками різних розмірів, екраном заставки та кольорами теми, тож виглядає і запускається як застосунок, а не як закладка. Service worker налаштовано через плагін next‑pwa, а Workbox для runtime‑кешування використовує стратегію CacheFirst для того, що не змінюється від запиту до запиту, — шрифтів, зображень, аудіо, відео, CDN‑ресурсів, — разом з розумними HTTP‑заголовками cache‑control. Оскільки service worker коректно працює лише через HTTPS, тестування на основі HTTPS підтвердило офлайн- та інсталяційну поведінку на реальних пристроях, замість того щоб просто сподіватися, що все спрацює.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Користувачі можуть встановити застосунок і продовжувати користуватися ним офлайн, а повторні завантаження швидко повертаються з кешу замість мережі. Платформа поводиться як нативний застосунок на пристроях, які реально носять із собою користувачі, а для цієї аудиторії це не приємний бонус — це різниця між тим, чи придатний застосунок до використання в морі, чи ні.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","Full‑Stack розробка","Веброзробка","Надійність і резервне копіювання","Оптимізація продуктивності","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/designed-an-ios-26-liquid-glass-design-system-75/","url":"https://software.engineer.company/uk/portfolio/designed-an-ios-26-liquid-glass-design-system-75/","title":"Спроєктувала дизайн‑систему iOS 26 'Liquid Glass' та канонічний реєстр компонентів, дотримання якого забезпечували правила лінтингу для запобігання розбіжностям UI.","summary":"UI лишається послідовним і відповідним бренду, а одноразові компоненти, які інакше почали б поширюватися, перехоплюються раніше, ніж це стається.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e UI без спільної візуальної мови й фіксованого набору компонентів пливе, і пливе швидко. Кожен новий екран винаходить власні кнопки, бейджі й картки, трохи інакші щоразу, і ці дрібні неузгодженості накопичуються, доки продукт не починає виглядати нецілісним, а будь‑яка зміна означає торкатися п\u0026rsquo;яти саморобних версій одного й того самого.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Дизайн‑система мала бути достатньо цілісною, щоб виглядати продуманою, і достатньо примусовою, щоб не розмиватися в ту мить, коли команда завантажена іншим.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Візуальну мову й систему компонентів було спроєктовано як одне ціле. Мова — це вигляд у стилі iOS 26 «Liquid Glass»: напівпрозорі панелі з розмиттям фону, шаруваті тіні, легка рефракція, пружинні анімації, — побудований на утилітах Tailwind. Над цим стоїть канонічний набір компонентів, з яких має складатися кожен екран: Card, Label, Button, GlassIconButton, DirectoryGrid та інші. Тримається все це завдяки лінтингу: правила відхиляють саморобний бейдж чи чіп і натомість вказують на канонічний компонент, тож систему підтримує інструментарій, а не пам\u0026rsquo;ять того, хто саме цього дня перевіряє код. А документація супроводжується конкретними нотатками «помилка → рішення»: замість абстрактного принципу — приклад неправильного та правильного варіанта.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e UI лишається послідовним і відповідним бренду, а одноразові компоненти, які інакше почали б поширюватися, перехоплюються раніше, ніж це стається. Візуальна узгодженість перестала залежати від дисципліни кожного й стала тим, що утримує інструментарій, — а це єдина версія узгодженості, яка переживає дедлайн.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Дизайн‑системи та UI","Документація","UI/UX‑дизайн та дизайн‑системи"]},{"id":"https://software.engineer.company/uk/portfolio/designed-the-product-s-ui-and-ux-end-76/","url":"https://software.engineer.company/uk/portfolio/designed-the-product-s-ui-and-ux-end-76/","title":"Спроєктувала UI та UX продукту наскрізно — сітки каталогів, подвійні подання картка/таблиця, валідатори вимог у реальному часі та навігацію breadcrumb.","summary":"У результаті вийшов вилощений, послідовний досвід, який робить щільні морські дані доступними для сприйняття та проводить людей крізь складні місця.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Платформа показує людям багато різних сутностей — фахівців, компанії, судна, вакансії, відгуки, — і інтерфейс мав поєднувати дві речі, які суперечать одна одній: привабливий вигляд і справжню зручність. Достатньо щільний, щоб показувати реальні морські дані, але не настільки, щоб перетворитися на стіну, об яку розбиваєшся.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e UI та UX продукту було опрацьовано наскрізно — макети, патерни взаємодії та дрібніші речі на кшталт того, як провести людину крізь форму, не змушуючи її відчувати тиск.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Основну роботу виконали кілька рішень. Сітки каталогів мають перемикач картка/таблиця, тож можна переглядати дані візуально або сканувати щільну таблицю, і застосунок пам\u0026rsquo;ятає обраний варіант. Форми використовують живі валідатори вимог, розташовані над полем вводу: кожне правило показується зеленим, коли воно виконане, і жовтогарячим, коли ні, — тож користувача скеровують під час вводу, а не докоряють йому після відправлення. Навігація — це послідовні хлібні крихти та двоколонкові макети сутностей, тож сторінки відчуваються як один продукт, а не набір непов\u0026rsquo;язаних екранів. А філософія помилок — це підказка замість провалу: жодних червоних стін, редиректи замість глухих кутів, застосунок намагається вести користувача далі, а не зупиняти його.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e У результаті вийшов вилощений, послідовний досвід, який робить щільні морські дані доступними для сприйняття та проводить людей крізь складні місця. Він виглядає продуманим і таким, якому можна довіряти, а на платформі, яку люди використовують для власної кар\u0026rsquo;єри, це не просто косметика: якщо все виглядало б недбало, вони довіряли б даним менше, і мали б рацію.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Веброзробка","Дизайн‑системи та UI","Продукт і вимоги","UI/UX‑дизайн та дизайн‑системи","Продуктова стратегія та вимоги"]},{"id":"https://software.engineer.company/uk/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/","url":"https://software.engineer.company/uk/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/","title":"Посилила захист застосунку за допомогою CSP на основі nonce, HSTS, cookie SameSite, ролей бази даних за принципом найменших привілеїв та серверних повторних перевірок прав доступу.","summary":"Безпека не залежить від того, як поводиться UI. Захист побудовано шарами так, щоб подолання одного рівня не давало проходу через решту, а вся система базується…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Платформа зберігає професійні та організаційні дані — саме ті, які люди очікують бачити захищеними належним чином, тож одного рубежу оборони було апріорі недостатньо. Робоче припущення таке: клієнт вороже налаштований, — усе, що примусово виконує браузер, може бути вимкнене тим, у чиїх руках цей браузер, — і безпека все одно мусить триматися.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Платформу потрібно було захистити на кожному рівні — фронтенд, API, база даних, — так, щоб безпеку забезпечував сервер незалежно від того, що саме дозволяв інтерфейс.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e На фронтенді проксі‑мідлвар Next.js — proxy.ts — встановлює Content‑Security‑Policy з nonce для кожного запиту та strict‑dynamic, а також HSTS і SameSite cookies, тож браузер жорстко обмежений у тому, що він виконає й надішле. На рівні API діють rate limiting, CORS, обмеження розміру запиту, валідація вводу до того, як щось торкнеться бази даних, і логування подій, пов\u0026rsquo;язаних із безпекою. У базі даних API входить під роллю з мінімальними привілеями, яка може лише виконувати (EXECUTE) функції застосунку, самі функції запускаються з SECURITY DEFINER, а все параметризовано. А права доступу — тариф, роль, організація, прив\u0026rsquo;язка до судна — перевіряються сервером повторно на кожен запит, тоді як фронтендні обмеження розглядаються лише як UX. Ці обмеження визначають, що видно; сервер визначає, що дозволено робити.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Безпека не залежить від того, як поводиться UI. Захист побудовано шарами так, щоб подолання одного рівня не давало проходу через решту, а вся система базується на припущенні, що клієнту довіряти не можна, — і це правильне припущення для даних, які люди довіряють платформі.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Frontend‑розробка","Архітектура платформи","Бази даних","Безпека","Backend- та API‑розробка","Безпека та керування доступом"]},{"id":"https://software.engineer.company/uk/portfolio/established-an-english-danish-internationalization-system-with-linter-78/","url":"https://software.engineer.company/uk/portfolio/established-an-english-danish-internationalization-system-with-linter-78/","title":"Створила систему інтернаціоналізації для англійської та данської мов, що несе 12 027 повідомлень на локаль у 458 файлах namespace, зі словником, дотримання якого забезпечував лінтер, та бюджетом у 400 рядків на файл.","summary":"Обидві локалі лишаються коректними й узгодженими на 24 054 повідомленнях між ними, а файли лишаються придатними до підтримки навіть у міру зростання кількості…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Платформа працює англійською та данською, а системи перекладу мають властивість розповзатися в хаос. Файли ростуть без обмежень, ключі протікають — присутні в одній локалі й відсутні в іншій, — а мовно‑специфічні конвенції застосовуються нерівномірно, тож одна з локалей зрештою читається так, ніби її перекладав комітет, учасники якого між собою не спілкувалися. Для професійного продукту це не дрібна вада — це виглядає як недбалість.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Налаштування інтернаціоналізації мало масштабуватися — утримувати обидві мови узгодженими й коректними, а файли — придатними для підтримки людиною навіть через рік.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Систему побудовано на next‑intl з правилами, які інструментарій справді примусово застосовує. Данська сторона має зафіксований словник і стиль — буквальні æøå, неформальне звертання «du», правильні наголоси в наказовому способі та семантичні відповідники для складних іменників, щоб їх перекладали за змістом, а не дослівно, — і лінтер стежить за цим. Діє жорсткий ліміт у 400 рядків на файл namespace, з підходом split‑and‑merge: велика область ділиться на вкладені файли, які потім чисто зливаються назад, замість того щоб один файл ріс нескінченно; саме через цей ліміт 12 027 повідомлень на локаль живуть у 458 файлах, а не в кількох величезних. Лінтер‑перевірка звіряє ключі між локалями, тож нічого не протікає і не губиться. А збережені overrides зливаються на основі каталогу, а не через крихкі фолбеки верхнього рівня — та сама ідея deep‑merge, що використовується для налаштувань.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Обидві локалі лишаються коректними й узгодженими на 24 054 повідомленнях між ними, а файли лишаються придатними до підтримки навіть у міру зростання кількості рядків. Якість мови стала тим, що інструментарій гарантує на кожному коміті, а не тим, що непомітно псується щоразу, коли хтось поспіхом додає рядок. Саме ліміт є несучою конструкцією: без обмеження на файл замість 458 файлів було б дванадцять, і ніхто б їх не відкривав.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","Full‑Stack розробка","Автоматизація та CI/CD","Документація","Інтернаціоналізація","Інтернаціоналізація та локалізація"]},{"id":"https://software.engineer.company/uk/portfolio/set-the-platform-s-founding-decisions-in-november-2025-80/","url":"https://software.engineer.company/uk/portfolio/set-the-platform-s-founding-decisions-in-november-2025-80/","title":"Заклала засадничі рішення платформи в тижні після відкриття репозиторію в листопаді 2025 року — поділ на рівні, доступ до даних передусім через базу даних та планку без жодних попереджень — і вони тримаються дев'ять місяців потому.","summary":"Через дев'ять місяців і кілька тисяч комітів усі три тримаються: рівні не розмилися, жоден обробник не звертається до таблиці напряму, а білд і досі не має…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Репозиторій відкрито 25 листопада 2025 року, і в ньому не було нічого. Те, що вирішується в перші кілька тижнів такого проєкту, має непропорційну вагу: поділ на рівні, місце, де дозволено жити бізнес‑логіці, планка якості. Такі рішення дешево ухвалювати на третій день і майже неможливо скасувати на шостий місяць, бо на той момент усе написане відтоді вже на них спирається.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Засадничі рішення мали бути ухвалені свідомо й рано, причому в такій формі, щоб вони пережили передачу іншим людям і кодовій базі, значно більшій за ту, що існувала на той час.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Основну роботу зробили три рішення. Стек поділено на рівні так, щоб кожна частина мала одну роботу — фронтенд на Next.js, Go API, який валідує й передає далі, рівень функцій PostgreSQL, якому належать бізнес‑правила, — замість того щоб логіка опинялася там, де було зручно того дня. Доступ до даних із самого початку сховано за збереженими функціями, і саме з цього рішення випливає все інше, що стосується бази даних; впровадити його заднім числом означало б переписати кожен обробник. А планку нульових попереджень запроваджено ще до того, як з\u0026rsquo;явилося багато коду, який треба їй підпорядкувати, бо стандарт, уведений на коміті 5 000, — це проєкт із прибирання, тоді як той самий стандарт на коміті 50 — це просто те, як працює репозиторій. Жодне з цих трьох рішень не було легким варіантом на той момент, і всі три коштували темпу в перший місяць.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Через дев\u0026rsquo;ять місяців і кілька тисяч комітів усі три тримаються: рівні не розмилися, жоден обробник не звертається до таблиці напряму, а білд і досі не має жодного попередження. Саме таку перевірку варто застосовувати до засадничого рішення — не чи звучало воно правильно, а чи пережило воно зіткнення з обсягом роботи, що прийшов далі, бо саме в цій точці зручні рішення зазвичай тихо полишають.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","DevOps","Frontend‑розробка","Full‑Stack розробка","Архітектура платформи","Архітектура рішень","Бази даних","Безпека","Керівництво командою","Технічне лідерство","Backend- та API‑розробка","Full‑Stack продуктова розробка","Архітектура платформи та рішень","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/developed-and-maintained-django-web-applications-for-the-84/","url":"https://software.engineer.company/uk/portfolio/developed-and-maintained-django-web-applications-for-the-84/","title":"Розробляла та підтримувала вебзастосунки на Django для IPTV‑платформи, постачаючи нові функції та покращуючи продуктивність і стабільність.","summary":"Застосунки продовжували набувати можливостей, лишаючись при цьому надійними і для внутрішніх команд, і для клієнтів.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Навколо IPTV‑платформи існували вебзастосунки на Django — саме та частина, на яку люди реально натискали, — і вони мали продовжувати рухатися вперед: нові функції, а також продуктивність і стабільність, яких вимагає платформа, що працює цілодобово.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб ці застосунки лишалися багатофункціональними, швидкими й стабільними.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Вебзастосунки на Django розроблялися й підтримувалися — нові функції створювалися, помилки виправлялися, а робота над продуктивністю та стабільністю велася разом з усією командою, а не в окремому кутку. У чомусь, що безперервно обслуговує клієнтів, стабільність — це не приємний додаток до функцій, а обмеження, якому функції мусять підпорядковуватися. Ефектна функція, через яку все хитається, не варта багато, коли хитатися не можна.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Застосунки продовжували набувати можливостей, лишаючись при цьому надійними і для внутрішніх команд, і для клієнтів. Додавати щось нове, не дестабілізуючи систему, — ось баланс, який тут мав значення, і саме його дотримувалася робота.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Frontend‑розробка","Full‑Stack розробка","Python","Веброзробка","Backend- та API‑розробка","Full‑Stack продуктова розробка","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/","url":"https://software.engineer.company/uk/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/","title":"Планувала та впроваджувала нову функціональність інфраструктури для внутрішніх і зовнішніх систем, створюючи рішення, достатньо довговічні, щоб працювати роками з мінімальними змінами.","summary":"Системи залишалися функціональними та ефективними ще довго після їх побудови, працюючи роками майже без змін.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e У міру зростання організації її внутрішні та зовнішні системи постійно потребували нових можливостей, які додавалися нашвидкуруч. Найпростіший спосіб зробити це — обрати те, що найшвидше сьогодні; проблема простого шляху в тому, що вже за півроку доводиться повертатися й усе переробляти.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб спланувати та побудувати інфраструктурну функціональність, яка справді витримає перевірку часом, — не просто працювати зараз, а продовжувати працювати.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Нову інфраструктурну функціональність було сплановано та впроваджено у внутрішніх і зовнішніх системах з розрахунком на довговічність — саме той тип рішень, які будують один раз і правильно, щоб вони роками працювали з мінімальним втручанням, а не вимагали постійної уваги. Це свідомий вибір щоразу: витратити трохи більше часу на роздуми на старті, щоб не приректи себе на вічне «нянькання» з результатом.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Системи залишалися функціональними та ефективними ще довго після їх побудови, працюючи роками майже без змін. Саме така довговічність і є справжнім мірилом інфраструктурної роботи — зробити щось, що працює сьогодні, може будь‑хто; зробити щось, що тихо продовжує працювати через роки, — завдання значно складніше й цінніше.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Архітектура платформи","Архітектура рішень","Інфраструктура","Надійність і резервне копіювання","Системне адміністрування","Архітектура платформи та рішень","Надійність та моніторинг (SRE)"]},{"id":"https://software.engineer.company/uk/portfolio/as-one-of-the-first-hires-designed-and-86/","url":"https://software.engineer.company/uk/portfolio/as-one-of-the-first-hires-designed-and-86/","title":"Як одна з перших співробітниць, спроєктувала та побудувала всю базову інфраструктуру та супутні процеси з нуля для SaaS‑стартапу в зеленій енергетиці, заклавши фундамент для швидкого зростання.","summary":"Стартап отримав міцну технічну основу, і саме вона дала бізнесу змогу згодом швидко зростати. Бути тим, хто будує таку основу з нуля, — це особлива…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Це був SaaS‑стартап у сфері зеленої енергетики — з перспективною ідеєю, але практично без технічної основи під нею. Прихід на посаду одним із перших співробітників означав той етап, коли підтримувати ще нічого, бо нічого ще не існує, — закладання ґрунту, на якому згодом стоятимуть усі інші.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завданням було з нуля побудувати основну інфраструктуру та процеси навколо неї.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Було спроєктовано та побудовано всю базову інфраструктуру й супутні процеси — сервери, мережі, потоки даних, безпеку, операційну складову. У стартапі це означає ухвалення рішень, які потім важко скасувати, тож мета полягала не просто в тому, щоб «щось запрацювало», а в тому, щоб закласти фундамент, здатний витримати вагу швидкого зростання без потреби зривати все й переробляти в момент, коли компанія стане більшою. Ранні інфраструктурні рішення або стають тим, що дає змогу масштабуватися, або тим, що потім рік доводиться розбирати; мета однозначно була в першому.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Стартап отримав міцну технічну основу, і саме вона дала бізнесу змогу згодом швидко зростати. Бути тим, хто будує таку основу з нуля, — це особлива відповідальність: зроби правильно — і ніхто не помітить, зроби неправильно — і помітять усі, — і в цьому випадку основа витримала.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Cloud","DevOps","Архітектура платформи","Архітектура рішень","Безпека","Інфраструктура","Системне адміністрування","DevOps та автоматизація CI/CD","Архітектура платформи та рішень","Хмарна інфраструктура та міграція"]},{"id":"https://software.engineer.company/uk/portfolio/maintained-and-enhanced-the-legacy-hugo-static-site-87/","url":"https://software.engineer.company/uk/portfolio/maintained-and-enhanced-the-legacy-hugo-static-site-87/","title":"Підтримувала та вдосконалювала застарілий сайт на Hugo, водночас долучаючись до покращень UI/UX основного продукту з управління активами.","summary":"Вебсайт залишався актуальним, а не тихо старів, а зручність використання основного продукту зростала завдяки послідовному, усвідомленому вдосконаленню — тому,…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Існував застарілий вебсайт, побудований на Hugo — генераторі статичних сайтів, — який працював паралельно з основним продуктом компанії, системою управління активами. Вебсайт був тим давнім, усталеним елементом; а реальна цінність була зосереджена в продукті.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб підтримувати сайт у робочому стані й водночас покращувати досвід користування продуктом.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Статичний сайт на Hugo підтримувався й вдосконалювався — залишався актуальним і працездатним, — тоді як покращення UI/UX і зворотний зв\u0026rsquo;язок водночас спрямовувалися в основний продукт управління активами. Розподіл уваги між застарілим сайтом і флагманським продуктом — це насамперед про те, щоб не дати старому занепасти, поки увага прикута до нового; обидва так чи інакше представляли компанію перед кимось, тож обидва мали залишатися в належному стані.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Вебсайт залишався актуальним, а не тихо старів, а зручність використання основного продукту зростала завдяки послідовному, усвідомленому вдосконаленню — тому, яке народжується з реального використання й обдумування продукту, а не з одного великого редизайну.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","Full‑Stack розробка","UX / UI‑дизайн","Веброзробка","UI/UX‑дизайн та дизайн‑системи","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/drove-client-web-success-by-combining-custom-website-91/","url":"https://software.engineer.company/uk/portfolio/drove-client-web-success-by-combining-custom-website-91/","title":"Забезпечила успіх клієнтів у вебі, поєднавши розробку та дизайн індивідуальних вебсайтів із SEO, контент‑стратегією та копірайтингом.","summary":"Клієнти отримали вищу видимість і більше залучення — їхні сайти працювали як справжні канали зростання, а не як онлайн-буклети.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Клієнтам насправді потрібен був не вебсайт сам по собі — їм потрібно було те, що вебсайт має для них робити: щоб його знаходили, щоб він приваблював клієнтів, щоб він справді працював як канал. Гарний сайт, який ніхто не може знайти, — це провал, що маскується під успіх.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Завдання полягало в тому, щоб об\u0026rsquo;єднати розробку та зростання в одну пропозицію, а не просто передати клієнту готовий сайт і побажати удачі.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Було об\u0026rsquo;єднано дві складові — розробку та дизайн вебсайтів на замовлення з одного боку, SEO, контент‑стратегію та копірайтинг з іншого, — щоб клієнт отримував продукт, який був водночас якісно побудований і справді помітний у пошуку. Зазвичай це вважають окремими завданнями, тому й з\u0026rsquo;являються то чудові сайти, яких немає в жодній видачі, то добре оптимізовані сайти, якими неприємно користуватися. Поєднання обох напрямів означало, що сайт із самого початку проєктувався так, щоб його знаходили, а не оптимізувався заднім числом.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Клієнти отримали вищу видимість і більше залучення — їхні сайти працювали як справжні канали зростання, а не як онлайн‑буклети. Саме поєднання розробки та пошукової доступності в одному процесі перетворило вебсайт із витрати на те, що дійсно окупало себе.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Бренд і маркетинг","Веброзробка","Продукт і вимоги","UI/UX‑дизайн та дизайн‑системи","Бренд, маркетинг та SEO","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/","url":"https://software.engineer.company/uk/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/","title":"Побудувала багаторівневий набір автоматизованих тестів — 981 тест Go, 543 фронтендні та браузерні специфікації, 494 поведінкові тести SQL — з мутаційним тестуванням, property‑based тестами та обов'язковою перевіркою доступності.","summary":"Змінювати щось структурне перестало бути страшно, а це єдине, що не дає кодовій базі такого розміру закам'яніти.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Платформа, що тримає свою бізнес‑логіку в базі даних, має проблему з тестуванням, якої немає в більшості проєктів. Логіка написана не тією мовою, з якою добре працює тестовий фреймворк, — вона в SQL, за фасадом функцій, а SQL — це саме той код, який лишається непокритим, бо тестувати його незручно. Якщо зверху додати API на Go та фронтенд на Next.js, «важливі частини покрито» тихо перетворюється на «покрито ті частини, які було легко покрити».\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Кожен рівень мав отримати перевірку своєї поведінки там, де ця поведінка насправді живе, а не так, щоб усе перевірялося ззовні через браузер.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Чотири рівні отримали чотири види тестів. API на Go несе 981 тестову функцію в 310 файлах. Фронтенд несе 543 spec‑файли Vitest і Playwright, зокрема 48 end‑to‑end файлів і 30 браузерних spec‑файлів. База даних несе 494 файли поведінкових тестів — 116 876 рядків SQL, які перевіряють свої припущення через 6 654 згенеровані винятки, — тож збережена функція тестується в самій базі даних, а не крізь три рівні застосунку над нею. Над ними стоять тести, що тестують тести: мутаційне тестування Stryker навмисно ламає рядок коду й падає, коли цього ніхто не помічає, а fast‑check генерує вхідні дані, які нікому не спало на думку записати. Гейт на axe‑core вимагає нуля порушень WCAG 2.0 і 2.1 рівнів A та AA, тож доступність стає падінням білду, а не знахідкою аудиту через кілька місяців. Пороги покриття рухаються лише вгору. Увесь набір виконується як 10 задач у workflow на 612 рядків.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Змінювати щось структурне перестало бути страшно, а це єдине, що не дає кодовій базі такого розміру закам\u0026rsquo;яніти. Чесна ціна — це час: набір повільний, він оподатковує кожну зміну, і на такому масштабі сам потребує підтримки. Натомість він дає можливість і далі рухатися швидко, і вона варта більше, ніж ті хвилини, які він забирає.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","DevOps","Frontend‑розробка","PostgreSQL","Автоматизація та CI/CD","Надійність і резервне копіювання","Тестування та QA","Backend- та API‑розробка","DevOps та автоматизація CI/CD","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/built-the-payments-and-entitlements-layer-96/","url":"https://software.engineer.company/uk/portfolio/built-the-payments-and-entitlements-layer-96/","title":"Побудувала рівень платежів і прав доступу — Stripe поряд із внутрішньозастосунковими покупками Apple і Google — обмеживши каталог, пошук та експорт моделлю доступу з 11 таблиць, яку перевіряє сервер.","summary":"Додавання вітрини тепер зачіпає бік payments і лишає гейти в спокої, а питання підтримки про чийсь доступ має одну таблицю, у яку треба зазирнути, замість…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Гроші — це та частина платформи, до якої нікому не дозволено ставитися недбало. Підписка мусить пережити закінчення строку дії картки, повернення коштів, зміну тарифу, вебхук, що прийшов двічі, і вебхук, що прийшов не в тому порядку. Щойно оплата починає відбуватися на трьох вітринах — карткою у вебі, через Apple в одному app store, через Google в іншому, — з\u0026rsquo;являються три різні версії того, що саме людина купила, а продуктові все одно потрібна одна відповідь на одне запитання: що цій людині дозволено робити просто зараз?\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Приймання грошей і надання прав мали стати двома системами, а не однією, щоб додавання ще однієї вітрини не означало переписування кожного гейта в продукті.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Stripe опрацьовує картки й підписки через 18 файлів Go, а in‑app‑покупки Apple і Google приходять через власну перевірку квитанцій. Усі три сходяться в схемі payments із 9 таблиць і 34 функцій — і на цьому спиняються. Те, про що продукт запитує насправді, — це окрема схема access, 11 таблиць і 34 функції, яка відповідає на «чи можна цьому обліковому запису зробити це?», не знаючи й не цікавлячись, яка саме вітрина за це заплатила. Ця відповідь закриває каталог компаній, пошук і експорт даних, і вона перевіряється сервером повторно на кожен запит, бо прихована кнопка — це ввічливість, а не механізм контролю.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Додавання вітрини тепер зачіпає бік payments і лишає гейти в спокої, а питання підтримки про чийсь доступ має одну таблицю, у яку треба зазирнути, замість трьох. Ціна — це дві схеми там, де меншому продуктові вистачило б однієї, плюс перевірка прав на тих запитах, які інакше були б безкоштовними.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","PostgreSQL","Бази даних","Безпека","Продукт і вимоги","Backend- та API‑розробка","Безпека та керування доступом","Продуктова стратегія та вимоги","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/moved-slow-work-onto-a-river-job-queue-97/","url":"https://software.engineer.company/uk/portfolio/moved-slow-work-onto-a-river-job-queue-97/","title":"Перенесла повільну роботу зі шляху запиту в чергу завдань River — 15 модулів воркерів, 8 запланованих задач та 20 завдань pg_cron — щоб запит повертався, поки робота за ним триває.","summary":"Запити повертаються швидко, а повільна робота все одно доходить до кінця — з повторними спробами й видимою історією, коли не доходить.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Частині роботи взагалі нема чого відбуватися, поки користувач чекає. Надіслати лист, перебудувати пошуковий індекс, згенерувати документ, перерахувати рейтинги — якщо робити будь‑що з цього всередині запиту, користувач дивиться на спінер заради того, чого ніколи не просив показувати. А якщо робити це в горутині, воно зникає тієї ж миті, коли процес перезапускається, — а він перезапуститься, посеред розгортання, не лишивши й сліду про те, що це взагалі мало статися.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Фоновій роботі потрібне було довговічне місце для життя: черга, яка переживає перезапуск, повторює невдалу спробу і в яку можна зазирнути, коли щось не сталося.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Вибір упав на River — переважно тому, що він тримає свою чергу в PostgreSQL: база даних і так є авторитетним джерелом даних, тож задача і рядки, яких вона торкається, комітяться або відкочуються разом, і немає другого шматка інфраструктури, який треба запускати й тримати в голові. За ним стоять 15 модулів‑воркерів і 8 запланованих задач. Нижче 20 задач pg_cron виконують ту підтримку, яку базі даних зручніше робити самій: підчищати партиції, ротувати солі, оновлювати агрегати. Усе, що було достатньо повільним, щоб це помітили, перенесено зі шляху запиту на одне з цих двох.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Запити повертаються швидко, а повільна робота все одно доходить до кінця — з повторними спробами й видимою історією, коли не доходить. Тримати чергу в Postgres, а не у виділеному брокері, — це свідоме обмеження: воно не масштабуватиметься вічно, і на якомусь обсязі стає неправильною відповіддю. Для платформи, вузьким місцем якої і так є база даних, на одну рухому частину менше виявилося вартіснішим за запас, яким однаково не скористалися б.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","PostgreSQL","Автоматизація та CI/CD","Бази даних","Надійність і резервне копіювання","Оптимізація продуктивності","Backend- та API‑розробка","Надійність та моніторинг (SRE)","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/built-first-party-error-monitoring-and-tracing-98/","url":"https://software.engineer.company/uk/portfolio/built-first-party-error-monitoring-and-tracing-98/","title":"Побудувала власний моніторинг помилок та трасування OpenTelemetry замість покупних — очищення payload, виявлення сплесків і регресій, символікацію та синтетичний heartbeat — за 11 операторськими поданнями.","summary":"Помилки перетворюються на чергу, яку хтось може розібрати, а регресія оголошує про себе сама, замість того щоб її знайшов користувач.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Різниця між платформою, яка піднята, і платформою, яка працює, полягає в тому, чи хтось про це дізнається. Помилка, на яку користувач наштовхнувся об одинадцятій вечора, на сторінці, яку ніхто не тестує, лишається невидимою, доки щось не піде й не збере її. Звична відповідь — купити хостований трекер помилок, і це хороша відповідь, — а ще вона означає, що власні помилки платформи, стектрейси й контекст користувача їдуть до третьої сторони.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Помилки й трейси треба було збирати, групувати й робити придатними до дії так, щоб нутрощі платформи не залишали платформу.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Побудовано дві частини. OpenTelemetry відповідає за трасування через OTLP, тож повільний запит можна простежити наскрізь через фронтенд, API та базу даних, а не здогадуватися про нього. Поруч стоїть власний пайплайн помилок — сервіс errmon і сервіс ingest, — який санітизує payload перед збереженням, групує помилки у повторювані проблеми замість плаского списку, виявляє сплески й регресії з періодом очікування, щоб один невдалий деплой не смикнув когось сорок разів, перетворює мінімізовані стектрейси фронтенду назад на читабельний код і запускає синтетичний heartbeat, щоб довести, що сам пайплайн живий. Усе це осідає в базі даних як події помилок, групи помилок, inbox, латентність API та семпли стеків, а назовні виходить через 11 операторських подань, зокрема одне для service level objectives.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Помилки перетворюються на чергу, яку хтось може розібрати, а регресія оголошує про себе сама, замість того щоб її знайшов користувач. Побудувати замість купити коштувало реального часу й означає, що це ще одна річ на підтримці, — куплений трекер працював би вже того ж дня по обіді. Натомість це дало те, що нічого чутливого не виїжджає назовні, а правила сповіщень підігнані під цю платформу, а не під якусь загальну.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","DevOps","Безпека","Інфраструктура","Моніторинг та observability","Надійність і резервне копіювання","Backend- та API‑розробка","DevOps та автоматизація CI/CD","Надійність та моніторинг (SRE)"]},{"id":"https://software.engineer.company/uk/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/","url":"https://software.engineer.company/uk/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/","title":"Побудувала засоби протидії зловживанням за принципом fail‑closed — 22 обмежувачі частоти на Redis, Cloudflare Turnstile, ідемпотентність запитів та прив'язку до origin — щоб платформа відсікала ботів і напливи, а не довіряла тим, хто її викликає.","summary":"Зловживання стає дорогим для того, хто зловживає, і дешевим для платформи, а збій у власному сховищі обмежувача деградує до відмови, а не до відчинених дверей.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Публічний каталог компаній і фахівців стає мішенню того самого дня, коли виходить у світ. Скраперам потрібні дані, спам‑акаунтам — охоплення, а ендпоінтом, обслуговування якого коштує платформі реальних грошей — пошук, експорт, будь‑що, що торкається зовнішнього API, — варто зловживати вже тому, що викликати його безкоштовно. Нічого з цього не є злим наміром, спрямованим саме проти цієї платформи; це фонова погода відкритого інтернету.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Дорогим і вразливим до зловживань шляхам потрібні були обмеження, які тримають під тиском, зокрема під тиском недоступності власної залежності обмежувача.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Обмежувачів частоти запитів тут 22, і кожен сконструйований під той шлях, який він захищає, замість одного глобального ліміту, бо спроба входу, пошук і масовий експорт стають зловживанням на кардинально різних швидкостях. Стан живе в Redis, тож ліміт спільний для всіх інстансів, а не існує окремо в кожному процесі, звідки його тривіально обійти. Важливе рішення — що відбувається, коли Redis недоступний: обмежувачі закриваються (fail closed). Трафік відхиляється, а не пропускається помахом руки, — це менш зручна відповідь і єдина, яку можна відстояти. Навколо них стоять Cloudflare Turnstile на шляхах, які варто перевіряти челенджем, 351 рядок мідлвару ідемпотентності, щоб повторений запис не перетворився на два, origin‑lock, що відкидає запити, які прийшли не через парадні двері, і власний челендж на самому каталозі.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Зловживання стає дорогим для того, хто зловживає, і дешевим для платформи, а збій у власному сховищі обмежувача деградує до відмови, а не до відчинених дверей. Закриватися при збої справді означає, що проблема з Redis стає проблемою, видимою користувачам, — і це прийнято свідомо, бо альтернатива в тому, що проблема з Redis стає проблемою з рахунками.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Безпека","Мережі та VPN","Надійність і резервне копіювання","Оптимізація продуктивності","Backend- та API‑розробка","Безпека та керування доступом","Надійність та моніторинг (SRE)"]},{"id":"https://software.engineer.company/uk/portfolio/built-the-operator-back-office-for-the-platform-102/","url":"https://software.engineer.company/uk/portfolio/built-the-operator-back-office-for-the-platform-102/","title":"Побудувала операторський бек‑офіс — близько 40 адміністративних маршрутів та 128 компонентів, що охоплюють заявки на володіння, модерацію, feature flags, кеш і діагностику, — щоб платформою можна було керувати без доступу до бази даних.","summary":"Люди, які керують платформою, справді можуть нею керувати, а кожна дія проходить через ту саму авторизацію й лишає той самий слід, що й будь-яка інша.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Кожна платформа непомітно вирощує другий застосунок, і зазвичай це саме той, якого ніхто не планує. Комусь треба схвалити заявку на володіння, приховати відгук, увімкнути функцію для частини користувачів, очистити кеш або з\u0026rsquo;ясувати, чому один обліковий запис бачить щось дивне. Коли такого застосунку немає, відповіддю стає інженер із консоллю бази даних — а це повільно, ніде не логується і за одну одруківку від інциденту.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Керувати платформою щодня мало бути можливо без shell, щоб операційна робота належала тому, хто на зміні, а не тому, у кого є облікові дані.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Бек‑офіс склав приблизно 40 адміністративних маршрутів, побудованих зі 128 компонентів, і охоплює роботу такою, якою вона реально надходить: розгляд заявок на володіння компаніями, модерація відгуків і дописів, перемикання feature flags, перегляд і очищення кешів, читання діагностики та звітність, яку просить CEO. Він працює на тій самій дизайн‑системі й тому самому згенерованому API‑клієнті, що й публічний продукт, — і це був вирішальний вибір: внутрішній інструмент, побудований на власному стеку, стає тією частиною, яку ніхто не оновлює, а далі — тією, якій ніхто не довіряє.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Люди, які керують платформою, справді можуть нею керувати, а кожна дія проходить через ту саму авторизацію й лишає той самий слід, що й будь‑яка інша. Це велика поверхня, яку треба тримати протестованою й доступною заради невеликої внутрішньої аудиторії, і ця ціна платиться постійно. Вона все одно менша за альтернативу — інженера, який о дев\u0026rsquo;ятій вечора в неділю набирає UPDATE на продакшні.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Frontend‑розробка","Full‑Stack розробка","UX / UI‑дизайн","Продукт і вимоги","Системне адміністрування","Full‑Stack продуктова розробка","Продуктова стратегія та вимоги"]},{"id":"https://software.engineer.company/uk/portfolio/built-company-ownership-claims-end-to-end-103/","url":"https://software.engineer.company/uk/portfolio/built-company-ownership-claims-end-to-end-103/","title":"Побудувала наскрізний процес заявок на володіння компанією — користувач заявляє права на компанію, адміністратор ухвалює рішення, а схвалення переписує граф авторизації, який визначає, кому що дозволено редагувати.","summary":"Компанії можуть перебрати й виправити власні записи без того, щоб хтось редагував базу даних вручну, а кожне надання повноважень має названого схвалювача й…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Каталог, наповнений із публічних джерел, має структурну проблему: компанії опинилися в ньому не з власної волі. Рано чи пізно приходить хтось із такої компанії й хоче виправити її запис — а між цією людиною й цим записом немає жодного зв\u0026rsquo;язку, є лише твердження, що зв\u0026rsquo;язок існує. Надати права надто легко — і вашу сторінку редагує конкурент. Надати надто повільно — і каталог лишається неправильним.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Мав існувати шлях від «це моя компанія» до справжніх повноважень над записом — з людським рішенням посередині й слідом позаду.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Заявки на володіння побудовано наскрізно — 108 комітів і обидва застосунки. Користувач подає заявку з доказами; вона потрапляє в чергу в бек‑офісі; адміністратор розглядає її та схвалює або відхиляє з причиною, яка повертається заявникові. Найцікавіше — що саме робить схвалення: це не прапорець у рядку. Схвалення переписує граф авторизації, тож обліковий запис отримує реальний зв\u0026rsquo;язок з організацією — той самий зв\u0026rsquo;язок, до якого вже звертається кожна перевірка прав на платформі. Воротами є рішення людини, а не гілка в коді, і жодній функції не довелося дізнаватися про заявки, щоб ці ворота поважати.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Компанії можуть перебрати й виправити власні записи без того, щоб хтось редагував базу даних вручну, а кожне надання повноважень має названого схвалювача й прикріплену причину. Людський розгляд є вузьким місцем за задумом; автоматична перевірка доменного імені була б швидшою — і помилялася б саме в тих випадках, які важать найбільше.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Frontend‑розробка","Full‑Stack розробка","Безпека","Продукт і вимоги","Full‑Stack продуктова розробка","Безпека та керування доступом","Продуктова стратегія та вимоги"]},{"id":"https://software.engineer.company/uk/portfolio/built-the-loyalty-and-reputation-system-105/","url":"https://software.engineer.company/uk/portfolio/built-the-loyalty-and-reputation-system-105/","title":"Побудувала систему лояльності та репутації — 67 функцій над реєстром із 31 таблиці, з лігами, бейджами та крамницею обміну — де блокування рядка балансу закриває вікно подвійного витрачання.","summary":"Внесок вимірюється й винагороджується, а баланс — це арифметика, а не наближення. Блокування рядка — повільніша відповідь, і його все одно обрано: конкуренція…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Професійний нетворкінг має проблему холодного старту: платформою варто користуватися тоді, коли нею вже користуються інші, а доти майже немає причин повертатися. Звичний важіль — це система винагород: бали за внесок, статус, що відображає репутацію. Описати її легко, а побудувати підступно, бо щойно бали можна витратити, вони стають грішми, і кожна помилка, якої припускаються з грішми, доступна й тут.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Внесок мав бути вимірюваним і винагороджуваним, а баланс — таким, який не можна витратити двічі.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Схема лояльності налічує 31 таблицю та 67 функцій, статус — ще 5 таблиць і 32 функції, а поруч стоять схеми discovery й персоналізації, які вирішують, що саме бачить конкретний учасник. Над реєстром надбудовані ліги, бейджі та крамниця обміну, де баланс перетворюється на щось реальне. Найбільше уваги забрав найдавніший баг у світі: перевірити баланс, потім списати його — і два запити, що прийшли одночасно, обидва проходять перевірку. Кожна мутація бере блокування рядка гаманця, перш ніж його прочитати, тож другий запит чекає на завершення першого, а не змагається з ним. І те, що гаманець лежить у тій самій базі даних, що й усе інше, — саме це взагалі робить таке можливим: баланс і те, що на нього куплено, комітяться разом або не комітяться зовсім.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Внесок вимірюється й винагороджується, а баланс — це арифметика, а не наближення. Блокування рядка — повільніша відповідь, і його все одно обрано: конкуренція за гаманець — це черга, а альтернатива — учасник, який витрачає ті самі бали двічі, і хтось, хто потім звіряє це вручну.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","PostgreSQL","SQL","Бази даних","Оптимізація продуктивності","Продукт і вимоги","Backend- та API‑розробка","Продуктова стратегія та вимоги","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/built-the-platform-s-social-layer-106/","url":"https://software.engineer.company/uk/portfolio/built-the-platform-s-social-layer-106/","title":"Побудувала соціальний рівень платформи — дописи, стрічку, групи, згадки, граф підписників та дайджест подій — на тому самому рівні даних, побудованому насамперед на функціях, що й решта продукту.","summary":"У платформи з'явилася причина бути відкритою в день, коли нікому не треба шукати компанію, і з'явилася без паралельного стеку, який довелося б підтримувати.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Каталог компаній — це довідник. Люди зазирають у нього й ідуть. Повертатися на професійну платформу змушує присутність інших людей, а це означає дописи, групи й причину повернутися, яка не зводиться до листа з нагадуванням.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Соціальний рівень треба було додати так, щоб він не став другою системою з власними правилами, власними дозволами та власним способом зберігати дані.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Дописи, стрічка, групи, згадки, граф підписників і дайджест подій зайшли в продукт за 188 комітів — усе на тому самому рівні даних, побудованому насамперед на функціях, що й решта платформи. Це обмеження зробило більшу частину роботи: граф підписників — це такі самі таблиці й функції, як усе інше, згадка розв\u0026rsquo;язується через ту саму схему identity, яку використовує каталог, а допис успадковує чергу модерації, уже побудовану для відгуків. Нічому тут не знадобилося власне сховище чи власна модель дозволів. Єдине місце, яке чинило опір, — це стрічка, бо ефективно зібрати персоналізовану стрічку подій справді інша задача, ніж дістати рядок, і саме тут робота з персоналізації та discovery виправдовує своє місце.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e У платформи з\u0026rsquo;явилася причина бути відкритою в день, коли нікому не треба шукати компанію, і з\u0026rsquo;явилася без паралельного стеку, який довелося б підтримувати. Чи є соціальний рівень правильною інвестицією для морського каталогу — це продуктове питання, а не інженерне: він тут, бо цього попросив продукт, і побудований так само, як усе навколо нього.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Frontend‑розробка","Full‑Stack розробка","Бази даних","Веброзробка","Продукт і вимоги","Backend- та API‑розробка","Full‑Stack продуктова розробка","Продуктова стратегія та вимоги"]},{"id":"https://software.engineer.company/uk/portfolio/built-the-hiring-marketplace-and-career-workspace-107/","url":"https://software.engineer.company/uk/portfolio/built-the-hiring-marketplace-and-career-workspace-107/","title":"Побудувала майданчик найму та кар'єрний робочий простір для моряків — 151 збережена функція у 48 таблицях — що охоплюють вакансії, заявки, сертифікати, просування в рангах та підтверджений стаж плавання.","summary":"Вакансію можна зіставити із задокументованою кваліфікацією, а не з назвою посади, яку людина написала про себе сама, — і саме в цьому вся різниця між дошкою…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Комерційний аргумент на користь морської професійної мережі — це найм: компаніям потрібні екіпажі та офіцери, а морякам потрібні посади на суднах. Обидві половини вже існували на платформі, але не в тій формі — компанії були в каталозі, фахівці мали профілі, і ніщо не поєднувало вакансію з людиною, кваліфікованою її закрити. Найскладніше — саме кваліфікація, бо в цій галузі це сертифікати, ранги й задокументований стаж плавання, а не назва посади.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Вакансії, заявки та перевірювані кваліфікаційні документи моряків потрібно було змоделювати належно, а не як вільний текст у профілі.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Побудовано два домени. Сторона найму налічує 32 таблиці та 118 функцій і охоплює вакансії, заявки, формування короткого списку та погляд роботодавця на весь потік кандидатів. Кар\u0026rsquo;єрний робочий простір несе 16 таблиць і 33 функції, у яких зберігаються сертифікати, просування в рангах і стаж плавання, разом із завантаженням документів і чергою ручної перевірки, щоб кваліфікацію було перевірено, а не просто задекларовано. Саме моделювання просування як графа, а не списку, робить зіставлення корисним: одного рангу можна досягти з іншого за наявності певних сертифікатів і достатнього зафіксованого часу в морі, і саме ця структура дає змогу зіставляти вакансію з кар\u0026rsquo;єрою, а не з ключовим словом. Кар\u0026rsquo;єрний робочий простір постачається за feature flag і ще не випущений повністю; сторона найму вже працює.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Вакансію можна зіставити із задокументованою кваліфікацією, а не з назвою посади, яку людина написала про себе сама, — і саме в цьому вся різниця між дошкою оголошень і інструментом найму в цій галузі. Перевірка є вузьким місцем, і це навмисно: черга ручної перевірки не масштабується так, як масштабувалася б автоматична, а автоматична підтверджувала б кваліфікацію тим, кому її підтверджувати не можна.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Data Governance","Full‑Stack розробка","PostgreSQL","Бази даних","Продукт і вимоги","Backend- та API‑розробка","Full‑Stack продуктова розробка","Продуктова стратегія та вимоги","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/ran-the-whole-company-on-one-512mb-host-109/","url":"https://software.engineer.company/uk/portfolio/ran-the-whole-company-on-one-512mb-host-109/","title":"Втримала всю компанію на одному хості з 512 МБ і одним ядром — git‑форж, вебсервер для семи доменів, Tor, два сервери альтернативних протоколів, резервні копії та блокування вторгнень — розглядаючи 464 МБ доступної пам'яті як зобов'язальне архітектурне обмеження.","summary":"Уся компанія працює на машині, що коштує на місяць менше за обід, і задум кращий саме завдяки цій дисципліні, а не просто дешевший.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Робочий хост компанії — це одноядерний хмарний примірник із 512 МБ пам\u0026rsquo;яті та 10 ГБ диска, з яких придатними до вжитку є близько 464 МБ. Усе, що бізнес виконує публічно, стоїть на ньому: вебсервер, що термінує TLS для семи доменів, git‑форджа, onion‑служба Tor, сервер Gemini, сервер Gopher, зашифровані резервні копії та блокування вторгнень. Звична реакція на цей перелік — придбати більшу машину.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Обмеження мало розглядатися як архітектурний вхідний параметр, а не як проблема, на яку витрачають гроші, бо чесне питання полягало не в тому, чи спрацювала б більша машина, а в тому, чи потрібна вона задуму.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Пам\u0026rsquo;ять стала аргументом, що вирішував суперечки. Немає ані агента моніторингу, ані конвеєра метрик, ані панелі — звітність є витягуванням, сім команд, що читають хост і формують Markdown, нічого не змінюючи й запускаючись лише на прохання. Наглядачем є systemd, а не другий менеджер процесів, накладений поверх нього, а контейнерна площина — це модулі Quadlet під тим самим наглядачем, а не демон із власним. Платформи з вебпанелями відкинуто ще на етапі задуму з тієї самої причини. Коли постало питання, чи витримає хост onion‑службу, відповідь надійшла з доби вимірюваних зразків, а не з думки: доступна пам\u0026rsquo;ять ніколи не опускалася нижче приблизно 310 МБ із 464, підкачування трималося на 2,6 відсотка, а процесор був вільним на 99,7 відсотка.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Уся компанія працює на машині, що коштує на місяць менше за обід, і задум кращий саме завдяки цій дисципліні, а не просто дешевший. Коштувало це запасу для будь‑чого недбалого — пошти навмисно немає на цій машині взагалі — її написано як риштування для встановлення, що чекає на власний хост, бо поштовий сервер потребує запасу, який ця машина вже витратила, і це записано, а не виявлено згодом.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Linux та сервери","Архітектура платформи","Архітектура рішень","Інфраструктура","Надійність і резервне копіювання","Оптимізація продуктивності","Системне адміністрування","Infrastructure as Code","Архітектура платформи та рішень","Хмарна інфраструктура та міграція"]},{"id":"https://software.engineer.company/uk/portfolio/deployed-the-companys-own-git-forge-121/","url":"https://software.engineer.company/uk/portfolio/deployed-the-companys-own-git-forge-121/","title":"Розгорнула власний git‑форж компанії на Soft Serve, приватний за замовчуванням і без вебпанелі, з портом SSH, прив'язаним до loopback за хостом‑переходом, і зробила посадкову сторінку перед ним артефактом збірки основного сайту, а не копією, яку тримають руками.","summary":"Компанія тримає власний код на власному обладнанні, а сторінка перед ним успадковує кожну перевірку, яку проходить головний сайт, замість того щоб відходити…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Початковий код компанії жив на сторонній хостинговій службі, що є розумним місцем для нього і поганим для бізнесу, чий аргумент перед клієнтами полягає в тому, що він не передає їхніх даних посередникам. Натомість тримати форджу означає тримати форджу: автентифікація, контроль доступу, сховище, резервні копії та публічне обличчя для всього цього.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Канонічний git‑сервер треба було підняти на наявному хості, з якнайменшою поверхнею атаки й без вебпанелі адміністрування, і поставити перед ним посадкову сторінку, що не гниє.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Форджа — це єдиний двійковий файл під наглядом операційної системи, встановлений із пакункового репозиторію постачальника, свідомо обраний за те, що він передусім працює через SSH і не має адміністративного вебінтерфейсу: що менше інтерфейсу, то менше треба захищати. Він приватний усталено: анонімний доступ відхиляється, доступ без ключа відхиляється, і кожен оголошений репозиторій позначено як приватний, а не покладено на невідомість. Його слухач SSH прив\u0026rsquo;язується лише до інтерфейсу зворотної петлі на порту 23231 і досяжний ззовні через хост‑перехід, тож оголошена поверхня брандмауера не зростає. Мультиплексор протоколів, що поставив би HTTPS і git‑SSH на один публічний порт, оглядаючи перші байти з\u0026rsquo;єднання, написано й готово за головним вимикачем, і цей вимикач вимкнено: багатокористувацький git через публічний порт поки не потрібен, а слухач, яким ніхто не користується, є поверхнею. Посадкова сторінка перед ним була цікавішою задачею. Вона була рукотворною копією оформлення головного сайту у власному репозиторії, і кожна знайдена між ними відмінність виявилася випадковістю, а не рішенням: шкала розмірів, що подавала словесний знак приблизно на дев\u0026rsquo;ять відсотків завеликим, оголошення шрифту, що зводило дві насиченості до однієї на будь‑якій машині зі встановленою гарнітурою, оздоби, приховані нижче певної ширини, тож відсутні на кожному телефоні, насиченість, використана без постаченого для неї шрифту, і жодного головного орієнтира чи заголовка верхнього рівня на жодній сторінці. П\u0026rsquo;ять із п\u0026rsquo;яти, і жодної видимої на знімку екрана. Копію видалено; посадкову сторінку тепер будують власні шаблони головного сайту й доставляють як артефакт.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Компанія тримає власний код на власному обладнанні, а сторінка перед ним успадковує кожну перевірку, яку проходить головний сайт, замість того щоб відходити від нього так, як здатне побачити лише вимірювання. Розходження досі доступне, і тепер його треба записати.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["DevOps","Linux та сервери","Автоматизація та CI/CD","Веброзробка","Інфраструктура","Системне адміністрування","DevOps та автоматизація CI/CD","Infrastructure as Code","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/built-a-multilingual-static-site-in-hugo-126/","url":"https://software.engineer.company/uk/portfolio/built-a-multilingual-static-site-in-hugo-126/","title":"Побудувала багатомовний статичний сайт на Hugo зі 108 файлів шаблонів, з яких 53 партіали, що публікує кожну сторінку у чотирьох представленнях з одного дерева контенту трьома мовами, і ще раз під сімома сфокусованими субдоменами, зібраними з того самого дерева.","summary":"Сайт віддає три мови та чотири подання з одного дерева, не має бекенду для атаки й нічого для оплати, а той єдиний шматок JavaScript у ньому тримається…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Компанії потрібен був публічний сайт, що працює трьома мовами, доводить спроможність, а не заявляє про неї, нічого не коштує в експлуатації й нікому не передає своїх відвідувачів. Більшість із цього — звичайні вимоги. Разом вони відкидають майже кожну систему керування вмістом, бо бекенд часу виконання — це те, що треба захищати, латати, оплачувати й пояснювати на сторінці приватності.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Сайт мав генеруватися цілком під час збирання і все ж поводитися як сучасний — із пошуком, встановлюваний, із стрічками, придатний до друку й читний екранним читачем кожною мовою, якою він виходить.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Це статичний сайт: 108 файлів шаблонів, з яких 53 є частковими шаблонами і 18 — шорткодами, три мови, жодного бекенду часу виконання й один власний скрипт, наданий як обмежений виняток для фільтра портфоліо, чий кожен елемент керування прихований, доки скрипт не запуститься. Спроможність додається під час збирання, а не в браузері, і це продуктове рішення, записане саме як рішення. Кожну сторінку публікують у чотирьох поданнях з одного дерева вмісту — HTML, двійник у Markdown, документ Gemini та пункт меню Gopher, — а головна сторінка додає до цього три стрічки та маніфест встановлюваного застосунку. Таксономій навмисно дві, а не одна, і ця відмінність є несучою: категорія є тематичною позначкою на роботі, послуга є тим, що компанія продає, і злиття їх зробило б каталог переліком навичок замість переліку пропозицій. Те саме дерево потім збирають ще сім разів, по одному на кожен сфокусований субдомен, скеровуючи генератор на інший каталог вмісту, а не відгалужуючи будь‑що.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Сайт віддає три мови та чотири подання з одного дерева, не має бекенду для атаки й нічого для оплати, а той єдиний шматок JavaScript у ньому тримається контракту, який примусово застосовує лінтер. Ціна в тому, що все інтерактивне має розв\u0026rsquo;язуватися під час збирання або ніяк, і це відкинуло кілька речей, що були б легкими із сервером, і є причиною, чому пошуковий індекс оцінили та відклали, а не випустили.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","Full‑Stack розробка","Веброзробка","Дизайн‑системи та UI","Інтернаціоналізація","Оптимізація продуктивності","Full‑Stack продуктова розробка","Інтернаціоналізація та локалізація","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/","url":"https://software.engineer.company/uk/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/","title":"Скоротила керовані браузером ворота якості сайту з 1 636 секунд до 615, плануючи їхні перевірки від найдовшої через пул воркерів, обмежений чотирма смугами, вимірявши, що абеткова черга коштувала 320 секунд проти 224.","summary":"Перевірка пішла з 1 636 секунд на 615, тоді як самі перевірки стали ширшими, а не тоншими — послідовна вартість зросла, а час за годинником упав.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Одинадцять перевірок сайту керують браузером без вікна: розкладка за кожної форми вікна, яку малює дизайн, шкала розмірів, розширення перекладеного тексту, контраст, правила доступності, примусові кольори, розміри маскота, рух, друк у шести комбінаціях паперу, помилки консолі та візуальна регресія. Виконувані по одній, вони брали 1 636 секунд, трохи більш ніж двадцять сім хвилин. Перевірка, що триває двадцять сім хвилин, — це перевірка, яку пропускають, а пропущену перевірку не відрізнити від пройденої.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Час за годинником мав опуститися настільки, щоб їх запуск був усталеним варіантом, а не рішенням, і жодну з них при цьому не можна було послабити.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Робота почалася з вимірювання. Кожну перевірку заміряно окремо на дванадцятиядерній машині: розкладка на 405 секундах, шрифт на 301, переклад на 282, контраст на 189, доступність на 178 і далі вниз аж до сімнадцяти. Відповідь сформували два висновки. Виконувати всі одразу було повільніше, ніж по чотири за раз, — 265 секунд проти 224, — бо кожна перевірка сама є браузером, що виконує паралельну роботу, і надмірне навантаження машини коштує більше, ніж виграє паралельність. А впорядкування за найдовшим часом обробки спершу перемогло абеткове майже на третину, 224 секунди проти 320, і це класичний результат теорії розкладів, який виявляється тут тому, що перевірки різняться у вартості в двадцять разів. Тож виконавцем є обмежений пул робітників, розмір якого береться з кількості ядер із підлогою в два та стелею в чотири, і який годують найдовшим спершу. Поряд із цим перевірки радше розширили, ніж звузили: вони тепер спільно використовують одну таблицю з двадцяти двох форм вікна, виведену з кожного медіазапиту, який насправді містить таблиця стилів, і це саме лише підняло перевірку розкладки з 95 секунд до 405.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Перевірка пішла з 1 636 секунд на 615, тоді як самі перевірки стали ширшими, а не тоншими — послідовна вартість зросла, а час за годинником упав. Вимірювання є тією частиною, яку варто зберегти: два розумні на слух вибори, виконувати все одразу й виконувати в порядку написання, кожен виявився вимірювано гіршим за альтернативу.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["DevOps","Frontend‑розробка","Python","Автоматизація та CI/CD","Оптимізація продуктивності","Тестування та QA","DevOps та автоматизація CI/CD","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/replaced-27-font-sizes-with-a-six-step-scale-129/","url":"https://software.engineer.company/uk/portfolio/replaced-27-font-sizes-with-a-six-step-scale-129/","title":"Замінила 27 відтворених розмірів шрифту, чиї найближчі сусіди різнилися на 0,6%, шестикроковою шкалою Major Third і написала лінтер, який валить двадцять восьмий.","summary":"Шість розмірів там, де було двадцять сім, з оголошеним співвідношенням, оголошеною мірою та перевіркою, що відхиляє наступне незаплановане значення.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Вимірювання поданого тексту сайту виявило двадцять сім різних розмірів шрифту в ужитку. Кілька з них розділяв менш ніж один відсоток — п\u0026rsquo;ять значень між 0,8 і 0,85 від розміру основного тексту були живими одночасно, а це різниця, якої жоден читач не здатен відчути і до якої кожен наступний редактор додасть свою. Два заголовки таблиця стилів не розмічала за розміром узагалі, і вони провалювалися до власних усталених значень браузера, у співвідношення 1,33, що не відповідало нічому іншому на сторінці.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Розміри мали стати шкалою з оголошеним співвідношенням, і щось мало завадити появі двадцять восьмого.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Шкалою є велика терція зі співвідношенням 1,25, шість іменованих щаблів від дрібного шрифту до плакатного, кожен із яких є токеном, а не значенням. Заголовки явно накладено на щаблі замість успадкування того, що думає браузер, і саме це виправило ті два, що не мали власного розміру. Підлогу встановлено лише для найнижчого щабля, тож дрібний шрифт лишається читним на телефоні без прив\u0026rsquo;язування всієї шкали. Логотипи звільнено за іменем, а не випадково. Лінтер є тією частиною, що тримає це разом: він подає сайт і валить збирання на двадцять восьмому різному розмірі. Він уже двічі виправдав своє місце — спіймав заголовок, що прибув на 1,17 від розміру основного тексту, а це не щабель нічого, і назвав співвідношення в повідомленні про відмову; і спіймав вбудований код на 0,9, а це саме той різновид значення, заради запобігання якому шкала й існує. Поряд зі шкалою пішла міра приблизно у сімдесят два символи, що замінила успадковану фіксовану ширину, яка давала дев\u0026rsquo;яносто один символ на сторінці відгуку і сто десять на сторінці контактів.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Шість розмірів там, де було двадцять сім, з оголошеним співвідношенням, оголошеною мірою та перевіркою, що відхиляє наступне незаплановане значення. Обмеження реальне й подеколи незручне: дизайн, що хоче розмір між двома щаблями, мусить перейти на щабель або доводити потребу змінити шкалу, і цю суперечку вже не раз вели й програвали.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Автоматизація та CI/CD","Дизайн‑системи та UI","Документація","Тестування та QA","UI/UX‑дизайн та дизайн‑системи","Бренд, маркетинг та SEO"]},{"id":"https://software.engineer.company/uk/portfolio/took-wcag-2-2-level-aa-across-the-whole-site-130/","url":"https://software.engineer.company/uk/portfolio/took-wcag-2-2-level-aa-across-the-whole-site-130/","title":"Довела WCAG 2.2 рівня AA на 32 представницьких сторінках — по одній на шаблон на мову — в обох колірних темах, плюс два критерії AAA, із задокументованим записом відповідності та перевіркою, що захищає кожне твердження.","summary":"Відповідність заявлено на рівні AA трьома мовами й у двох темах, з двома критеріями AAA понад це та одним, названим як виняток, і за кожною заявою стоїть…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Консультація, що продає інженерну розсудливість і випускає недоступний вебсайт, має проблему з довірою ще до того, як має проблему з доступністю. Сайт до того ж має незвично широку поверхню для цього: три мови, дві колірні теми, повну таблицю стилів для друку, палітру з темною темою як основною, мальовані від руки примітки та ілюстрованого персонажа — і кожне з цього є способом провалити критерій в одній конфігурації, проходячи його в іншій.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Сайт мав відповідати WCAG 2.2 на рівні AA на кожній сторінці, кожною мовою та в обох темах, і цю відповідність мали захищати перевірки, а не заява в документі.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Запис відповідності документує кожен критерій в обсязі, і кожен рядок називає, що його задовольняє і що це перевіряє. Два критерії рівня AAA взято понад ціль — візуальне подання цілком і вигляд фокуса, який радше пропонують, ніж заявляють. Автоматизація запускає рушій правил доступності з увімкненими правилами найкращих практик, а не лише з тими, що стосуються відповідності, а це різниця в тридцять правил, і вона важила одразу: одне з додаткових правил провалилося тієї миті, коли його ввімкнули, бо знак бренду стояв поза всіма орієнтирами на кожній внутрішній сторінці. Друга, повільніша перевірка проганяє тридцять дві представницькі сторінки у двох колірних схемах і двох ширинах, і те, що вона стверджує, є незвичним: фокус доводиться в пікселях, а не в документі, справжнім натисканням клавіші табуляції та порівнянням знімків екрана, бо однакові пікселі означають, що користувач не може сказати, де фокус, хай би що казала розмітка. Вона також обходить усю сторінку в пошуках клавіатурної пастки, застосовує зазначені перевизначення міжлітерних і міжслівних відступів, подвоює кореневий розмір шрифту та вимірює довжину рядка, вирівнювання, центрування та відступи між абзацами.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Відповідність заявлено на рівні AA трьома мовами й у двох темах, з двома критеріями AAA понад це та одним, названим як виняток, і за кожною заявою стоїть перевірка. Найважчою була контрастність над фотографією, яку автоматичний механізм правил позначає як таку, що її не оцінити, і яку сайт захищав аргументом, а не числом: справжні показники — 49 із 64 пар сторінки й теми нижче AA. Причиною виявилися дві поверхні, якими дизайн ніколи не володів, а перевірка, що їх знайшла, тепер є підлогою: кожна пара має витримувати AA над стіною, яку малює збірка, а пара, що не витримує, валить збірку. Те, що сайт каже на власній сторінці подяк, є чесною частиною: жоден автоматичний інструмент не знаходить більш ніж приблизно третину порушень WCAG, підписи, що з\u0026rsquo;являються під вказівником, не можна закрити клавішею, бо для цього потрібен скрипт, а сайт виконує лише один, і випробувань зі справжніми допоміжними технологіями не було — ці межі записано там, де читач їх побачить, а не вилучено із заяви.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Веброзробка","Дизайн‑системи та UI","Документація","Інтернаціоналізація","Тестування та QA","UI/UX‑дизайн та дизайн‑системи","Інтернаціоналізація та локалізація","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/fixed-11-accessibility-defects-the-browser-called-healthy-131/","url":"https://software.engineer.company/uk/portfolio/fixed-11-accessibility-defects-the-browser-called-healthy-131/","title":"Знайшла й виправила 11 дефектів доступності, які браузер звітував здоровими: вісім посилань підвалу, що лишалися в порядку табуляції за pointer‑events, шкалу прокрутки, яка обрізала колофон на трьох сторінках, і механізм правил, що виконував 70 зі своїх 105 правил.","summary":"Одинадцять дефектів виправлено і, що корисніше, чотири правила, які їх переживуть: вартовий, що перевіряє одну вісь, захищає одну вісь; набір правил, що не…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Сайт проходив свої автоматичні правила доступності. Він також мав одинадцять дефектів, яких ті правила не бачили, бо кожен із них був властивістю того, як сторінка подається, а не того, що казала розмітка, — саме той різновид, який валідатор звітує як справний і на який користувач клавіатури натрапляє за секунди.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Дефекти треба було знайти, виправити та описати як реєстр із правилом, яке породив кожен із них, щоб закривався клас дефектів, а не окремий випадок.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Вони поділилися на три групи. Розміри: ключове слово таблиці стилів, ужите так, ніби воно відносне, прив\u0026rsquo;язало цілу ділянку до шістнадцяти пікселів, тоді як основний текст сягав двадцяти двох; елемент нижнього індексу вжито у значенні «менший»; зменшення тексту подовжило рядок так, що заголовок сягнув дев\u0026rsquo;яноста шести символів; а виміряна стеля висоти була переросла саме тим перевизначенням відступів, підтримку якого сайт заявляє. Фокус і обрізання: вісім посилань підвалу лишалися в порядку табуляції за властивістю, що прибирає взаємодію вказівником і більш нічого; правило переповнення створило контейнер прокручування, якого ніхто не хотів; а анімація, керована прокручуванням, яка просто неактивна на сторінці, надто короткій для прокручування, назавжди обрізала підвал на трьох сторінках. І два дефекти в самих вартових, які варто назвати окремо, — кожна форма вікна, яку відкривала перевірка розкладки, мала дев\u0026rsquo;ятсот пікселів заввишки, тож телефон у альбомній орієнтації на 852 на 393 давав сім пікселів між двома елементами, і жодна перевірка туди ніколи не дивилася; а рушій правил виконував сімдесят зі своїх ста п\u0026rsquo;яти правил, тож правила, яке спіймало б відсутній орієнтир, у наборі не було.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Одинадцять дефектів виправлено і, що корисніше, чотири правила, які їх переживуть: вартовий, що перевіряє одну вісь, захищає одну вісь; набір правил, що не містить правила, не може його примусово застосувати; висота є виміром, тож перевіряйте її; і доводьте видимість у пікселях, а не в документі. Коли перевірку розкладки належно відкрили заново, вона провалилася сто двадцять вісім разів трьома мовами, зокрема на вікні завбільшки з телефон, де завершальний рядок головного блоку сидів на двадцять один піксель нижче згину.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Автоматизація та CI/CD","Веброзробка","Дизайн‑системи та UI","Тестування та QA","UI/UX‑дизайн та дизайн‑системи","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/generated-321-achievement-pages-from-a-sqlite-export-132/","url":"https://software.engineer.company/uk/portfolio/generated-321-achievement-pages-from-a-sqlite-export-132/","title":"Згенерувала 495 сторінок досягнень трьома мовами з експорту SQLite лише для читання, де адресу сторінки авторовано як дані, тож виправлення речення більше не пересувало сторінку й не ламало посилання.","summary":"Чотириста дев'яносто п'ять сторінок генерується з одного джерела, виправлення твердження нічого не коштує, а адреси, які цей сайт колись публікував, і далі…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Вміст портфоліо компанії створюється в окремій базі даних — тій самій, що виробляє CV, — і вебсайт має публікувати його як сторінки, трьома мовами, не даючи двом копіям розійтися. Наївний підхід, писати сторінки вручну й тримати їх у злагоді, ламається на першому ж виправленні.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Вебсайт мав генерувати свій вміст із бази даних як вхідні дані збирання, з адресами сторінок, що переживають переписування речень на них.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Експортер читає базу даних лише для читання й пише по одній сторінці на досягнення на мову — 495 сторінок — плюс дані таксономії та послуг, потрібні шаблонам. Він використовує лише стандартну бібліотеку, тож збирання сайту не залежить від середовища генератора, а закомічений вивід означає, що сайт збирається самостійно. Найбільш наслідкове рішення в ньому стосується адрес. Раніше сайт виводив URL сторінки з перших слів її англійського твердження, тож виправлення речення мовчки переносило сторінку й ламало кожне посилання на неї — сайт, чиїм аргументом на власну користь є те, що він виправляє речі, штрафував себе мертвим посиланням щоразу, коли це робив. Адресу тепер створюють як дані: по одному рядку на адресу на досягнення, перша є поточною, а кожна наступна є відставленою адресою, яку сайт видає як перенаправлення. З тієї самої роботи записано ще дві пастки. Порівняння періоду з текстовим стовпчиком мовчки збіглося з усіма тридцятьма двома рядками через те, як база даних призначає спорідненість типів у порівнянні. І перелік мов тепер є єдиною віссю, з якої виводять і цикл запису, і файли даних, і запити, тож додати четверту мову — це один запис у відображенні, а не пошук.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Чотириста дев\u0026rsquo;яносто п\u0026rsquo;ять сторінок генерується з одного джерела, виправлення твердження нічого не коштує, а адреси, які цей сайт колись публікував, і далі відповідають. Експортер також володіє рівно одним рішенням про подання — тим, як послуги групуються в тематичні розділи, — і це навмисно: усе інше, що він пише, належить базі даних, а заголовок групи без якоїсь мови валить експорт, а не подає англійську поверх перекладеного вмісту.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","Python","SQL","Бази даних","Веброзробка","Інтернаціоналізація","Пайплайни даних (ETL/ELT)","Бренд, маркетинг та SEO","Інтернаціоналізація та локалізація","Розробка вебсайтів та CMS","Розробка пайплайнів даних (ETL/ELT)"]},{"id":"https://software.engineer.company/uk/portfolio/closed-the-colour-system-at-28-colours-133/","url":"https://software.engineer.company/uk/portfolio/closed-the-colour-system-at-28-colours-133/","title":"Закрила систему кольорів на 28 задокументованих кольорах із лінтером, який валить значення, намальоване але незадокументоване, задокументоване але ненамальоване, хибно виміряне, переписане як літерал або в межах перцептивної відстані 0,02 від уже наявного.","summary":"Палітра є замкненим виміряним набором, що не може тихо зростати, а два майже однакові написання, які до цього спонукали, зникли.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Колір на сайті з темною темою за усталеним вибором, світлою темою, таблицею стилів для друку, режимом примусових кольорів та ілюстрованим брендом сам собою не лишається малим набором. Він уже почав розходитися так, як завжди: два написання того самого кольору стояли досить близько, щоб ніхто не міг їх розрізнити, значення були перевведені як літерали поруч із токенами, що їх визначали, а задокументовані кольори не фарбували нічого.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Палітра мала стати замкненим набором із оголошеним порогом розрізненності, і щось мало примусово тримати цю замкненість.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Двадцять вісім кольорів, кожен задокументований із коефіцієнтом контрасту, який він показує на поверхні, де з\u0026rsquo;являється, та одинадцять брендових значень, оголошених один раз як токени. Поріг є числовим, а не редакційним: два кольори, ближчі за перцептивну відстань 0,02 в однорідному колірному просторі, є одним кольором із двома написаннями. Лінтер валить збирання п\u0026rsquo;ятьма різними способами — значення пофарбоване, але незадокументоване; задокументоване, але непофарбоване; записане з хибним коефіцієнтом; у межах порога від того, що вже є; або брендове значення, переписане як літерал. Він одразу знайшов два: колір теми, що існував у двох написаннях на відстані 0,018, і колір тла, що заміняв стіну, від якої стояв на 0,021. Прозорість використовує відносний колірний синтаксис, а не функцію змішування, саме тому, що вартовий не бачить крізь суміш, а палітрний вартовий, якого можна обійти, не є вартовим. Правило, що йде з цим, коротке: змінюйте токен, а не правило, додавайте колір лише тоді, коли жоден не пасує, і ніколи не знижуйте задокументований коефіцієнт, щоб дизайн запрацював.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Палітра є замкненим виміряним набором, що не може тихо зростати, а два майже однакові написання, які до цього спонукали, зникли. Це обмеження, що подеколи каже ні: дизайн, який хоче трохи інший синій, мусить узяти той, що існує, або обґрунтувати двадцять дев\u0026rsquo;ятий колір, і це обґрунтування має містити коефіцієнт.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Автоматизація та CI/CD","Дизайн‑системи та UI","Документація","Тестування та QA","UI/UX‑дизайн та дизайн‑системи","Бренд, маркетинг та SEO"]},{"id":"https://software.engineer.company/uk/portfolio/found-the-light-theme-missing-an-overlay-layer-134/","url":"https://software.engineer.company/uk/portfolio/found-the-light-theme-missing-an-overlay-layer-134/","title":"Виявила, що світлій темі бракувало повносторінкового шару накладання від самого дня її написання, стверджуючи, що обидві теми малюють кожну шарувату поверхню однаковою кількістю шарів.","summary":"Шар, відсутній в одній темі, тепер валить коміт, а той, що був відсутнім від дня написання, пофарбовано.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Сайт постачає дві колірні теми. Темна є усталеною і на неї дивляться постійно; світла є перевизначенням, що з\u0026rsquo;являється лише за системною вподобою, а це означає, що її бачать значно рідше і ніхто з тих, хто її перевіряє. Паритет тем є класом дефектів, у якому поверхню будують один раз і переказують один раз, а переказ тихо губить шар.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Паритетові потрібне було твердження, бо єдиною альтернативою є людина, яка пам\u0026rsquo;ятає перемкнути вподобу й подивитися.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Перевірка мала й структурна: для кожної шаруватої поверхні порахувати шари, які фарбує кожна тема, і завалити, коли числа різняться. Вона не порівнює вигляд — теми й мають виглядати по‑різному, — вона порівнює склад, а це та річ, що має бути однаковою. Вона знайшла дефект на першому ж прогоні. Повносторінкова обкладинка сайту має три шари в темній темі, візерунок граней над затінювачем над стіною, а світла тема переказала це двома. Накладення граней було відсутнім у світлій темі від дня її написання, і ніщо про це не сказало, бо сторінка без одного з трьох шарів тла має вигляд дизайнерського рішення, а не вади. Виправленням було одне правило; опис, зроблений згодом, зафіксував, чого накладення коштує в контрасті, тож додавання виміряно, а не вважається безкоштовним.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Шар, відсутній в одній темі, тепер валить коміт, а той, що був відсутнім від дня написання, пофарбовано. Це і є форма дефекту, на яку націлено весь підхід із перевірками: нічого не було зламано, нічого не давало помилки, сторінка подавалася правильно, і вона була хибною місяцями.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Автоматизація та CI/CD","Дизайн‑системи та UI","Тестування та QA","UI/UX‑дизайн та дизайн‑системи"]},{"id":"https://software.engineer.company/uk/portfolio/made-reduced-motion-honest-135/","url":"https://software.engineer.company/uk/portfolio/made-reduced-motion-honest-135/","title":"Зробила зменшений рух чесним, знайшовши одинадцять селекторів, які досі анімувалися під цією настройкою, бо універсальне правило transition‑none програє за специфічністю будь‑якому правилу з класом.","summary":"Уподобу шанують насправді, а не за наміром, і одинадцять живих анімацій, які суцільне правило нібито покривало, покрито справді.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Сайт шанував уподобу зменшеного руху одним правилом, що вимикало кожен перехід. Воно мало вигляд завершеного, воно проходить лінтер чисто, і за емульованої вподоби зменшеного руху одинадцять селекторів усе одно анімувалися.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Уподобу треба було шанувати насправді, а причина, чому очевидне правило не спрацювало, мала стати тим, чого наступна людина не зможе повторити.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Причиною є специфічність. Універсальне правило набирає найнижчий бал у каскаді й програє будь‑якому правилу з класом, тож суцільне вимкнення переходів програє кожній продуманій анімації на сторінці — а це і є кожна анімація, яку варто вимикати. Виправлення було структурним, а не латкою: усе, що рухається, тепер живе в одній пізній частині таблиці стилів, а лінтер валить перехідне перетворення будь‑де інде. Розрізнення, яке проводить правило, є навмисним і вужчим за очевидне: зменшуйте рух, а не колір. Згасання кольору не є рухом, і його вимкнення робить інтерфейси на відчуття зламаними для людей, які цього не просили, тож перехід, що перелічує колірні властивості, проходить, а перехід на русі — ні. Рух також зобов\u0026rsquo;язаний виражатися як перехід, а не як анімація за ключовими кадрами, бо перший тривіально скасовується, а друга — ні. З тієї самої роботи вийшли дві суміжні пастки, записані з вимірюваннями: оздоба меню проходила тридцять один градус із шістдесятиградусного повороту, перш ніж стати наполовину видимою, і оскільки форма періодична, півповорот має однаковий вигляд за третину вартості; і п\u0026rsquo;ять різних властивостей кожна робить елемент вмісним блоком для всього, спозиційованого відносно вікна перегляду, що мовчки зменшило шар закривання до частки екрана.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Уподобу шанують насправді, а не за наміром, і одинадцять живих анімацій, які суцільне правило нібито покривало, покрито справді. Загальний урок записано на початку того документа: правило, що програє за специфічністю, відмовляє мовчки, і кожен звіт називає це якось інакше.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Веброзробка","Дизайн‑системи та UI","Тестування та QA","UI/UX‑дизайн та дизайн‑системи","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/built-a-637-line-print-stylesheet-136/","url":"https://software.engineer.company/uk/portfolio/built-a-637-line-print-stylesheet-136/","title":"Побудувала друкований стиль на 637 рядків проти чотирьох задокументованих поведінок рушія відтворення, зокрема вбудованих заголовків, які друкувалися білим по білому для будь‑якого читача, чий браузер надавав перевагу темному.","summary":"Сайт друкується на невідомому папері в обох темах, а чотири види поведінки рушіїв записано разом із дефектом, який спричинив кожен.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Кейси сайту є тим артефактом, який хтось роздруковує й несе на зустріч. Це робить папір справжнім виходом, а не люб\u0026rsquo;язністю, а папір є іншим носієм, ніж вузький екран — розмір паперу читача невідомий, орієнтація читача невідома, а поведінка браузера під час друку різниться між рушіями так, як жодний екранний перегляд не покаже.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Сайт мав друкуватися правильно на невідомому папері, в обох колірних темах, без окремого документа, який довелося б підтримувати поруч із вебверсією.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Це одна таблиця стилів на 637 рядків з єдиним правилом сторінки й одним блоком друку. Правило сторінки задає поле й навмисно не задає розміру паперу, тож те, що читач обере в діалозі, проходить наскрізь, і все інше до цього пристосовується. Кореневий розмір шрифту закріплено в пунктах, тож кожне відносне вимірювання має фізичний якір, а одну міру приблизно у сімдесят два символи застосовано до чотирьох блоків верхнього рівня — і це аркуш перемагає дизайн, бо альбомна сторінка інакше розганяла б рядок приблизно до ста десяти символів. Чотири види поведінки рушіїв задокументовано як пастки, і кожен спричинив справжній дефект. Одиниці вікна перегляду розв\u0026rsquo;язуються в коробку сторінки в одному рушії й у вікно в іншому, тож сторінка, надрукована з широкого вікна, має третину кожного рядка обрізаною в другому. Елементи з фіксованим положенням малюються на кожному аркуші, тож декоративні прибрано, а два з них перепризначено на бланк і колофон. Палітра усталено бере білий текст, бо усталеною темою є темна, і це друкувало чотири підзаголовки розділів білим по білому — слова просто були відсутні. А сторінковий носій не може розділити гнучку чи сіткову коробку, що дало порожній перший аркуш на сторінці досягнення. Це покриває перевірка з шести частин, що випробовує шість комбінацій паперу й орієнтації, обидві вподоби колірної схеми та справжню кількість сторінок проти тієї, яку передбачає висота вмісту.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Сайт друкується на невідомому папері в обох темах, а чотири види поведінки рушіїв записано разом із дефектом, який спричинив кожен. Відомі межі записано, а не приховано: немає ні номерів сторінок, ні колонтитулів, один рушій ігнорує контроль висячих рядків, а буквиці не є універсальними. Одного разу випадковий термінатор коментаря змусив лінтер CSS проковтнути ціле правило і двічі пройти чисто — помітила це лише перевірка друку.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Веброзробка","Дизайн‑системи та UI","Документація","UI/UX‑дизайн та дизайн‑системи","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/mirrored-the-site-to-gemini-and-gopher-137/","url":"https://software.engineer.company/uk/portfolio/mirrored-the-site-to-gemini-and-gopher-137/","title":"Віддзеркалила весь сайт як 777 документів Gemini і 777 документів Gopher з того самого розгорнутого дерева, з нульовою зміною байтів у HTML.","summary":"Сайт читний чотирма протоколами з одного збирання, по 777 документів на кожен і з нульовою зміною HTML, а альтернативні подання коштують приблизно дванадцять…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Сайт статичний, не має ні стеження, ні бекенду часу виконання, і його аргумент полягає в тому, що документові не потрібен мегабайт JavaScript, аби його прочитали. Цей аргумент легко висловити й важко продемонструвати. Два невеликі інтернет‑протоколи демонструють його безпосередньо, бо жоден із них узагалі не здатен нести скрипт.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Увесь сайт мав публікуватися через Gemini і Gopher із того самого вмісту, без другого дерева вмісту й без змін у HTML.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Обидва є форматами виводу того самого збирання, а не окремим конвеєром. Генераторові сайту надали власні типи носіїв і формати виводу, і кожна сторінка, розділ та термін таксономії дістали ще по два подання поруч зі своїм HTML і двійником у Markdown. Результатом є 777 документів Gemini і 777 меню Gopher, вироблені з того самого джерела, розгорнуті в те саме дерево й віддавані двома невеликими демонами на тому самому хості. Дві властивості зробили це вартим роботи, а не дивиною. Обидва формати позначено як неальтернативні подання, тож у HTML не змінилося нічого — жодного байта, і це виміряли, а не припустили. А формат Gopher не має способу вкласти посилання всередину речення, бо рядок меню є полями, розділеними табуляціями, тож прозу жорстко переносять на шістдесят восьмому стовпчику під час збирання; це обмеження вигострило письмо так, як HTML ніколи не вимагав. Поруч із ними стоїть onion‑дзеркало Tor, і це єдине публічне обличчя, яке платформа могла додати, не відкриваючи порту брандмауера, бо демон додзвонюється назовні, а всередину не дзвонить ніхто.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Сайт читний чотирма протоколами з одного збирання, по 777 документів на кожен і з нульовою зміною HTML, а альтернативні подання коштують приблизно дванадцять відсотків від власної ваги HTML на диску. Лише один із чотирьох вимірюється щодо трафіку, і це зазначено у власному документі статистики платформи, а не тихо проігноровано.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","Автоматизація та CI/CD","Веброзробка","Інтернаціоналізація","Інфраструктура","DevOps та автоматизація CI/CD","Інтернаціоналізація та локалізація","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/replaced-963-structured-data-blocks-with-one-graph-138/","url":"https://software.engineer.company/uk/portfolio/replaced-963-structured-data-blocks-with-one-graph-138/","title":"Замінила 963 анонімні блоки структурованих даних, які переповідали компанію 1 671 раз, одним пов'язаним графом із 16 типів, викарбуваним зі стабільних ідентифікаторів походження.","summary":"Один граф зі стабільною тотожністю замінює 963 анонімні переказування, і сторінки несуть менше, а не більше.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Сайт видавав структуровані дані так, як це робить більшість сайтів: по блоку на сторінку, і кожен описував організацію заново з нуля. На весь сайт це дало 963 блоки, що переказували ту саму компанію 1 671 раз, анонімно — жодного стабільного ідентифікатора ніде, тож ніщо із тих, хто це споживає, не могло сказати, що організація на одній сторінці є організацією на іншій.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Структуровані дані мали стати одним графом зі стабільною тотожністю, а не купою блоків, що випадково містять ті самі слова.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Ідентифікатори тепер карбують із джерела сайту — один для організації, один для сайту, один для особи, — і кожен блок посилається на них, а не переказує їхній вміст. Ідентифікатори є спільними для джерела, а не окремими для кожної мови, бо компанія є тією самою компанією й данською. У грі шістнадцять типів, що охоплюють каталог послуг і його пропозиції, відгуки та роботу, яку вони описують, добірки та їхні навігаційні ланцюжки. Два рішення втримали вагу. Сторінки переліків публікують свої елементи лише за URL, а не вбудовують їх, і це виміряли: назвати їх на індексі портфоліо означало б 107 повних тверджень і зростання стиснутої сторінки на 52 відсотки. А перевірка, що це стереже, не просто підтверджує синтаксис — вона стверджує, що кожен блок розбирається, що кожен ідентифікатор розв\u0026rsquo;язується і що кожну URL‑адресу, яку називає граф, справді було зібрано, тож граф, що вказує на неіснуючу сторінку, валить перевірку.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Один граф зі стабільною тотожністю замінює 963 анонімні переказування, і сторінки несуть менше, а не більше. Вимірювання, з якого почалася робота, варто тримати в голові: сайт видавав той самий опис організації 1 671 раз, і ніщо не могло їх поєднати.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Data Governance","Frontend‑розробка","Автоматизація та CI/CD","Бренд і маркетинг","Веброзробка","Data Governance та якість даних","Бренд, маркетинг та SEO","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/","url":"https://software.engineer.company/uk/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/","title":"Скоротила пакунок стилів із 87 КБ до 31 КБ, вийнявши з нього шрифт у base64, і відкинула 756 КБ у 22 файлах, які публікувалися при кожному розгортанні й на які ніщо не посилалося.","summary":"Пакет важить 31 КБ замість 87, 756 КБ мертвих ресурсів перестали розгортатися, і за кожним рішенням стоїть вимірювання — зокрема за тим, що пішло в інший бік,…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Пакет таблиць стилів сайту важив 87 КБ, а для документного сайту без фреймворку це більша частина ваги сторінки, витрачена ще до прибуття будь‑якого вмісту. Сайт до того ж публікував каталог піктограм за кожного розгортання, згенерований один раз і відтоді ні з чого не згаданий.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Вага мала впасти без зміни дизайну, і мала впасти з причини, на яку можна вказати, а не через загальне прибирання.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Спершу вимірювання. Дві третини найбільшої таблиці стилів були одним шрифтом, закодованим у base64, — приблизно 56 КБ тексту, що кодували приблизно 42 КБ шрифту, — вбудованим заради виграшу в першому промальовуванні, який попередньо завантажений зовнішній файл дає й так, і оплачуваним на кожній сторінці незалежно від того, чи потрібна була та вага. Його вилучення забрало цей файл з 84 КБ до 28, а весь пакет з 87 до 31. Три насиченості шрифту натомість попередньо завантажуються, і третя приєдналася до переліку лише тоді, коли польові дані показали, що вона закриває найдовший критичний ланцюжок, а не тому, що три звучить завершено. Окремо перевірка того, що розгортання насправді публікувало, виявила двадцять одну згенеровану піктограму та дублікат файлу налаштувань, 756 КБ, що вивантажувалися щоразу й не згадувалися нізвідки; а власний файл піктограм сайту впав із 145 КБ до 15. Сучасний формат зображень оцінили для знака бренду, виміряли й відхилили — він вийшов більшим, а механізм вибору бере за порядком, а не за розміром, тож сучасний браузер брав би скрізь важчий файл. Дві перевірки тепер тримають межу: жодну світлину не можна показувати ширшою за половину її вихідних пікселів, і кожну ілюстрацію треба публікувати в розмірі, який підтримують її власні пікселі і за звичайної, і за високої щільності.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Пакет важить 31 КБ замість 87, 756 КБ мертвих ресурсів перестали розгортатися, і за кожним рішенням стоїть вимірювання — зокрема за тим, що пішло в інший бік, і це корисніший запис із двох.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","Автоматизація та CI/CD","Веброзробка","Дизайн‑системи та UI","Оптимізація продуктивності","Бренд, маркетинг та SEO","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/","url":"https://software.engineer.company/uk/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/","title":"Виправила мапу сайту, де 172 з 176 URL мали одну позначку часу зміни, взявши дату з історії git після встановлення, що експорт переписує кожен файл при кожному запуску.","summary":"Повторна синхронізація після місяця редагування вмісту тепер торкається восьми файлів зі 186 замість усіх, і мапа сайту каже щось правдиве.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Мапа сайту казала пошуковим системам, що 172 з його 176 сторінок востаннє змінилися тієї самої миті. Це не тонка неточність — дата зміни є обіцянкою повзунові, що вміст сторінки змінився, і сайт, який дає цю обіцянку 172 рази одночасно, або каже правду про повне переписування, або не каже нікому нічого корисного.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Дати мали описувати вміст, а не файл, не вигадуючи точності, якої репозиторій не має.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Причиною було те, що дата бралася з часу зміни файлу, а експорт вмісту переписує кожен файл за кожного прогону, тож одна синхронізація штампувала весь корпус. Виправлення переносить джерело до історії версій, із ланцюжком запасних варіантів, що пробує спершу явне поле, потім історію комітів, потім файл. Пастка в цьому виправленні варта запису: буквальна назва поля має з\u0026rsquo;явитися в переліку, інакше генератор ніколи його не прочитає, тож налаштування, що на вигляд віддає перевагу авторській даті, але пропускає назву, мовчки ігнорує кожну авторську дату. З тієї самої роботи вийшли ще два рішення про дати. База даних тепер несе, коли кожен запис було написано й востаннє переглянуто, і це навмисно тримають окремо від того, коли відбулася сама робота, — вони віддалені на роки, і злиття їх датувало б сторінку, написану цього року, десятиліттям тому. А рядки в тому файлі є необов\u0026rsquo;язковими, і нічого не виводиться, бо власна історія репозиторію починається пізніше за вміст: відсутня дата лишає поле порожнім, а не фіксує міграцію, за принципом, що точне хибне число гірше за відсутнє, бо вірять саме хибному.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Повторна синхронізація після місяця редагування вмісту тепер торкається восьми файлів зі 186 замість усіх, і мапа сайту каже щось правдиве. Загальне правило потрапило до документа з метаданими поруч, бо та сама пастка стосується кожного поля, що має ланцюжок запасних варіантів.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Python","Автоматизація та CI/CD","Бренд і маркетинг","Веброзробка","Тестування та QA","DevOps та автоматизація CI/CD","Бренд, маркетинг та SEO","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/brought-the-quality-gate-code-under-a-linter-143/","url":"https://software.engineer.company/uk/portfolio/brought-the-quality-gate-code-under-a-linter-143/","title":"Підвела 10 242 рядки JavaScript воріт якості під форматувальник і лінтер, встановивши, що це найбільший обсяг коду в репозиторії й єдиний, якого ніщо не читало, виправила 13 знахідок і не придушила жодної.","summary":"Найбільший і найбільш несучий код у репозиторії тепер відформатовано, перевірено лінтером і перевірячем типів, із тринадцятьма виправленими висновками й нулем…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Перевірка якості сайту — це тридцять два скрипти загальним обсягом 10 242 рядки JavaScript. Це був із великим відривом найбільший масив коду в репозиторії, і це був єдиний масив коду, якого ніщо не читало — ані форматувальник, ані лінтер, ані перевірка типів. Програми, що примусово застосовували кожне правило в проєкті, були єдиними програмами, на які не поширювалося жодне з них.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Перевіряльників треба було підвести під той стандарт, заради примусового застосування якого вони існують, і форматувальник треба було припасувати до них, а не навпаки.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Форматувальник ішов першим, і ширина відступу була цікавим рішенням. Усталеним значенням репозиторію є чотири пробіли; за чотирьох пробілів форматувальник переписав би 2 173 рядки найбільшого перевіряльника. Перевизначення на два пробіли для цих файлів звело це до 38 рядків справжнього розходження. Записаний із цим принцип полягає в тому, що форматувальник припасовують до коду, а не код до форматувальника — переформатування двох тисяч рядків заради вподобання знищує здатність читати історію файлу. Далі лінтер, що дав тринадцять справжніх висновків, усі виправлено й жодного не придушено. Перевіряльники на Python дістали те саме поводження через перевіряч типів, налаштований на середню суворість із тридцятьма окремими правилами суворого рівня, увімкненими понад це й обраними за вимірюванням: за цього налаштування дерево мовчить, і з тридцяти кандидатів двадцять дев\u0026rsquo;ять уже мовчали, а один спрацював — і його виправили, а не звільнили. Перевіряч типів знайшов два справжні дефекти, які лінтер пропустив чистими, обидва про форму значення, а не про його синтаксис.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Найбільший і найбільш несучий код у репозиторії тепер відформатовано, перевірено лінтером і перевірячем типів, із тринадцятьма виправленими висновками й нулем придушень. Причина, чому це важить більше, ніж підказує кількість рядків, зазначена в плані: дефект у таблиці стилів сайту виявляється як сторінка, що виглядає хибно, а дефект у перевіряльнику виявляється як перевірка, що проходить тоді, коли не мала б.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["DevOps","Frontend‑розробка","Python","Автоматизація та CI/CD","Документація","Тестування та QA","DevOps та автоматизація CI/CD","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/built-a-database-driven-cv-and-portfolio-generator-144/","url":"https://software.engineer.company/uk/portfolio/built-a-database-driven-cv-and-portfolio-generator-144/","title":"Побудувала на Python генератор CV, рекомендацій, портфоліо та супровідних листів на основі бази даних — 41 модуль, 10 580 рядків — що відтворює шість форматів виводу з одного джерела SQLite на 23 таблиці, зібраного ідемпотентним конвеєром із 19 кроків.","summary":"Шість форматів, три мови й п'ять тем виходять з однієї бази даних, а виправлене речення виправляють один раз.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e CV, аркуш рекомендацій, портфоліо та супровідний лист — це ті самі факти, впорядковані чотирма способами, і тримати їх як чотири документи означає робити кожне виправлення чотири рази, а зрештою не робити. Три мови множать це на три. Режим відмови полягає не в тому, що документ хибний; він у тому, що два документи розходяться, і ніщо не каже, який із них поточний.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Одне джерело фактів мало виробляти кожен документ, кожною мовою, у кожному форматі, з упорядкуванням, яке вирішує код, а не той, хто останнім редагував файл.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Джерелом є база даних SQLite із двадцяти трьох таблиць — досягнення, посади, компанії, регіони, категорії, послуги, профілі, рекомендації, резюме, — зібрана конвеєром із дев\u0026rsquo;ятнадцяти кроків, що йде від порожнього файлу до повної бази даних однією командою. Кроки впорядковано, і кожен написано так, щоб його було безпечно повторювати, тож конвеєр можна виконати проти наявної бази даних, не дублюючи жодного рядка. Сорок один модуль Python загальним обсягом 10 580 рядків подають із неї шість вихідних форматів: HTML, PDF у двох варіантах, звичайний текст, Markdown і JSON, через шість шаблонів Jinja і вісім таблиць стилів. Залежності часу виконання втримано рівно на двох, шаблонний рушій і рендерер PDF, з тим аргументом, що генератор документів, який не вдасться встановити за п\u0026rsquo;ять років, нічого не зберіг. Націлювання є повноцінним поняттям, а не ручним редагуванням: профіль обирає, які досягнення з\u0026rsquo;являються і в якому порядку, тож документ, спрямований на один різновид читача, є запитом, а не копією.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Шість форматів, три мови й п\u0026rsquo;ять тем виходять з однієї бази даних, а виправлене речення виправляють один раз. Ціна в тому, що система тепер є єдиним способом виробити документ — більше немає файлу, який можна поспіхом відкрити й відредагувати, а додати мову означає додати її скрізь, перш ніж узагалі щось збереться.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Full‑Stack розробка","Python","SQL","Автоматизація та CI/CD","Архітектура рішень","Бази даних","Інтернаціоналізація","Backend- та API‑розробка","Full‑Stack продуктова розробка","Архітектура платформи та рішень","Інтернаціоналізація та локалізація","Проєктування та моделювання баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/","url":"https://software.engineer.company/uk/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/","title":"Втримала генератор на 981 тестовому випадку із порогом покриття гілок 92% і попередженнями як помилками та ствердила ідемпотентність, запустивши весь конвеєр збірки двічі з порожнього файлу й вимагаючи, щоб другий прохід нічого не змінив.","summary":"Конвеєр можна повторно виконати проти живої бази даних без страху, і саме це взагалі уможливлює поступову роботу з вмістом.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Генератор, що збирає базу даних з нуля, має особливий різновид вади: він працює першого разу й псує другого. Кроки, що вставляють без перевірки, кроки, що залежать від порядку виводу попереднього кроку, кроки, безпечні поодинці й не разом. Нічого з цього не виявляється в тесті, що починає з нічого й виконується один раз.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Збирання треба було довести як повторюване, а не просто робоче, а набір тестів мав бути достатньо великим і суворим, щоб регресія не змогла тихо крізь нього пройти.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Тест ідемпотентності є прямолінійним і найкориснішим: зібрати всю базу даних із порожнього файлу, зробити знімок, виконати весь дев\u0026rsquo;ятнадцятикроковий конвеєр знову поверх результату й вимагати, щоб другий прохід нічого не змінив. Кількості рядків, вміст та ідентифікатори мають збігатися. Довкола нього стоять 383 тестові функції — 981 випадок, коли параметризовані розгортаються, — у сорока п\u0026rsquo;яти файлах і 7 944 рядках, що охоплюють конвеєр, рендерери, завантажувачі вмісту, логіку націлювання та перевіряльників. Покриття гілок несе підлогу в дев\u0026rsquo;яносто два відсотки, примусово застосовану в збиранні, а не подану в підсумку, і набір наразі показує близько 95 відсотків, тож підлога має запас і не є декоративною. Попередження налаштовано як відмови, і саме це налаштування на практиці важить найбільше — сповіщення про застарілість, що друкується два роки, є сповіщенням, якого ніхто не читає, а прогін, що перетворює його на червоний тест, є тим прогоном, після якого його виправлять.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Конвеєр можна повторно виконати проти живої бази даних без страху, і саме це взагалі уможливлює поступову роботу з вмістом. Підлога є підлогою, а не ціллю, і варто сказати, що дев\u0026rsquo;яносто два відсотки покриття гілок усе одно лишають гілки, якими ніщо ніколи не проходило, — число обмежує ризик, а не усуває його, і два дефекти, знайдені в проєкті згодом, були в коді, який звіт про покриття показував як покритий.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["DevOps","Python","Автоматизація та CI/CD","Бази даних","Надійність і резервне копіювання","Тестування та QA","Backend- та API‑розробка","DevOps та автоматизація CI/CD","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/established-pdf-ua-1-conformance-across-nine-documents-146/","url":"https://software.engineer.company/uk/portfolio/established-pdf-ua-1-conformance-across-nine-documents-146/","title":"Встановила відповідність PDF/UA‑1 на дев'яти документах за 106 зі 106 правил і виявила, що архівний варіант валить одне правило зі 146 — майже‑успіх, який читається як успіх для будь‑кого, хто не запускає валідатор.","summary":"Відповідність доступності доведено на повний бал, а архівну заяву висловлено чесно як майже влучання із названою конкретною прогалиною.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e PDF, що має правильний вигляд на екрані, не каже нічого про те, чи здатен його прочитати екранний читач, чи утворюють його заголовки структуру, чи оголошено його мову і чи відкриється він ще за двадцять років. Відповідність доступного PDF і архівного PDF є двома машинно перевірюваними стандартами, а документ, якого ніколи не проганяли через валідатор, є документом, що робить неперевірену заяву.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Згенеровані документи треба було зміряти проти обох стандартів, із результатом, записаним як число, а не як намір.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Дев\u0026rsquo;ять документів — CV у своїх варіантах, аркуш рекомендацій, портфоліо та супровідний лист, у різних мовах — прогнали через незалежний валідатор окремо для профілю доступності й архівного профілю. Профіль доступності проходить на 106 зі 106 правил, і це вимагало тегованої структури, оголошеної мови документа, альтернативного тексту на кожній недекоративній графіці, справжнього заголовка в метаданих і явного порядку читання замість того, який випадково дає розкладка. Архівний профіль дає цікавіший результат: він валить рівно одне правило зі 146. Це та форма результату, яку легко подати хибно. Сто сорок п\u0026rsquo;ять пройдених у підсумку читається як відповідність, і це не відповідність; це документ, який відхилить система, що застосовує стандарт. Правило, яке не проходить, записано разом із тим, що воно є і чому його не закрито, а не заокруглено геть.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Відповідність доступності доведено на повний бал, а архівну заяву висловлено чесно як майже влучання із названою конкретною прогалиною. Межа, про яку варто сказати прямо, полягає в тому, що обидва числа походять від одного валідатора; інша реалізація може не погодитися, а правило, що проходить, є лише свідченням того, що цьому перевіряльникові не було чого про нього сказати.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Python","UX / UI‑дизайн","Автоматизація та CI/CD","Веброзробка","Документація","Тестування та QA","UI/UX‑дизайн та дизайн‑системи","Розробка вебсайтів та CMS","Технічна документація"]},{"id":"https://software.engineer.company/uk/portfolio/enabled-every-python-linter-rule-as-an-error-147/","url":"https://software.engineer.company/uk/portfolio/enabled-every-python-linter-rule-as-an-error-147/","title":"Обрала кожне правило, яке має лінтер Python, як помилку й опрацювала 1 815 знахідок до нуля, де кожен із небагатьох винятків несе письмову причину, а два з них підперті перевіркою, а не коментарем.","summary":"Лінтер працює на повну силу з нулем висновків, і кожне відхилення задокументовано в тому рядку, де його взято.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Більшість проєктів обирає зручну підмножину правил свого лінтера, і цю підмножину обирають ті правила, що мовчали того дня, коли його налаштовували. Це робить налаштування записом наявних звичок коду, а не стандартом, якого код дотримується, і кожне лишене вимкненим правило є класом дефектів, про який нікому ніколи не скажуть.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Усталений вибір треба було обернути — кожне правило, яке реалізує інструмент, увімкнене як помилка, — а отриманий доробок відпрацювати до нуля, а не виторгувати вниз, вимикаючи правила назад.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Вибір повного набору правил дав 1 815 висновків на першому прогоні. Їх опрацьовували за категоріями, а не за файлами, бо категорії про щось кажуть: невживані аргументи та затінені вбудовані імена є шумом, а категорія безпеки, категорія змінюваних усталених значень і категорія обробки винятків кожна вказувала на справжню поведінку. Справжні несумісності існують — форматувальник і лінтер можуть розходитися щодо того самого рядка, а кілька правил суперечать власним свідомим виборам проєкту, — і кожне з невеликої кількості звільнень несе письмову причину в тому місці, де звільнення береться, і каже, чого хотіло правило й чому цей код робить інакше. Два з них ідуть далі й підперті перевіркою, а не коментарем, тож звільнення не може тихо розширитися: правило вимкнено, а тест стверджує саме ту властивість, яку правило примусово застосувало б. Поряд працює перевірка типів у суворому режимі, а це окремий і жорсткіший стандарт, і саме вона спіймала дефекти, яких лінтер не бачив, бо вони про те, чим значення є, а не про те, як його записано.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Лінтер працює на повну силу з нулем висновків, і кожне відхилення задокументовано в тому рядку, де його взято. Ціна реальна й варта називання: найсуворіше налаштування дає висновки, на які щиро не варто зважати, і хтось має ухвалювати це рішення 1 815 разів, а не один раз.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["DevOps","Python","Автоматизація та CI/CD","Документація","Тестування та QA","Backend- та API‑розробка","DevOps та автоматизація CI/CD","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/vendored-a-qr-encoder-in-522-lines-148/","url":"https://software.engineer.company/uk/portfolio/vendored-a-qr-encoder-in-522-lines-148/","title":"Вбудувала кодувальник QR — Ріда‑Соломона над GF(256), фіксоване розташування модулів, вісім шаблонів маски — на 522 рядках, замість брати третю залежність часу виконання, і перевірила його, зчитавши готову матрицю незалежно написаним декодером.","summary":"Кількість залежностей часу виконання лишилася на двох, а кодувальник є єдиним вкладеним компонентом у проєкті.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Документам потрібен був QR‑код із посиланням на онлайнову версію. Кожна доступна бібліотека це вміє, і взяти одну з них означало б додати третю залежність часу виконання до проєкту, що свідомо тримався двох — шаблонного рушія й рендерера PDF — з тим аргументом, що генератор документів має встановлюватися й через багато років.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Треба було або прийняти залежність, або реалізувати формат, і реалізацію треба було довести як правильну, а не просто таку, що дає щось квадратне й чорне.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Кодувальник має 522 рядки й реалізує ті частини специфікації, які насправді потрібні для цього вжитку: кодування в байтовому режимі, виправлення помилок за Ридом‑Соломоном над полем Галуа з 256 елементів із твірним многочленом, побудованим у потрібному степені, фіксовану розкладку модулів із її пошуковими взірцями, часовими взірцями та взірцями вирівнювання, інформацію про формат і версію, а також усі вісім взірців маскування даних, оцінених за чотирма штрафними правилами специфікації, тож обирається маска з найнижчим балом, а не стала. Саме перевірка зробила це захисним. Випробовувати кодувальник проти його власної логіки не доводить нічого, тож готову матрицю модулів зчитує назад декодувальник, написаний незалежно за порядком читання зі специфікації, і тест стверджує, що декодований рядок дорівнює вхідному. Це перетворює «воно дає правдоподібне зображення» на «воно дає код, що декодується в правильну URL‑адресу», і це перевіряють за кожного прогону, а не один раз оком і телефоном.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Кількість залежностей часу виконання лишилася на двох, а кодувальник є єдиним вкладеним компонентом у проєкті. Слід сказати прямо, що це не універсальна реалізація — вона підтримує ті режими й версії, які використовують документи, і нічого більше, а чесним обґрунтуванням є бюджет залежностей, а не якась заява, що результат кращий за зрілу бібліотеку.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Python","Документація","Оптимізація продуктивності","Тестування та QA","Backend- та API‑розробка","Архітектура платформи та рішень"]},{"id":"https://software.engineer.company/uk/portfolio/moved-every-user-facing-string-into-a-content-tree-152/","url":"https://software.engineer.company/uk/portfolio/moved-every-user-facing-string-into-a-content-tree-152/","title":"Перенесла кожен рядок, звернений до користувача, з Python у дерево контенту з 874 файлів трьома мовами, знайшовши мертві переклади, чиєї мертвості ніхто не бачив, і перевірку, яка мовчки оцінювала третину досягнень.","summary":"Прозу тепер можна редагувати, не торкаючись коду, і порівнювати між мовами підрахунком. Ціною є те, що додавання мови тепер однозначне, а не поступове — дерево…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Кожен рядок генератора, звернений до користувача, — кожне досягнення, кожен відгук, кожен заголовок розділу, кожне резюме, трьома мовами — жив усередині коду на Python. Це робить редагування речення зміною коду, робить перегляд перекладу різницею проти коду й унеможливлює побачити з першого погляду, чи мова повна. Це також ховає той режим відмови, що має значення: переклад може бути присутнім, хибним і недосяжним водночас.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Рядки треба було винести з коду до дерева вмісту, яке можна перерахувати, порівняти між мовами й перевірити, не запускаючи рендерера.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Результатом є 874 файли у каталозі вмісту, впорядкованих за видом, а потім за мовою: досягнення, відгуки, резюме, посади, компанії, регіони, категорії, послуги, профілі, рекомендації та фрагменти супровідних листів. Файли з полями через табуляцію, де одиницею є рядок з ідентифікатором, і окремі файли, де одиницею є абзац. Завантажувач читає їх під час збирання, і база даних збирається з них, тож дерево є джерелом, а база даних — похідною. Два висновки вийшли безпосередньо зі здатності рахувати. Деякі перекладені рядки більше не мали жодного англійського відповідника — мертві записи, яких ніщо не подавало і яких ніхто не міг би помітити, доки вони були вкладені в код, бо непосиланий ключ словника має точнісінько такий вигляд, як посиланий. А перевірка вмісту, що мала оцінювати кожне досягнення, читала лише ту підмножину, яку могла розв\u0026rsquo;язати, оцінювала тридцять сім із дев\u0026rsquo;яноста трьох і звітувала про успіх. Перетворення корпусу на каталог зробило обидва ці факти видимими як розбіжність у кількості файлів.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Прозу тепер можна редагувати, не торкаючись коду, і порівнювати між мовами підрахунком. Ціною є те, що додавання мови тепер однозначне, а не поступове — дерево робить неповну мову очевидною, і в цьому вся суть, але це також означає, що часткові переклади не можна тихо випускати, поки їх доробляють.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Data Governance","Python","Документація","Інтернаціоналізація","Міграції та модернізація","Backend- та API‑розробка","Data Governance та якість даних","Інтернаціоналізація та локалізація","Міграція та модернізація баз даних"]},{"id":"https://software.engineer.company/uk/portfolio/built-a-cross-language-figure-and-notation-check-153/","url":"https://software.engineer.company/uk/portfolio/built-a-cross-language-figure-and-notation-check-153/","title":"Побудувала міжмовну перевірку контенту, яка валиться, коли переклад губить число, вказане англійською, і коли мова вживає нотацію, якої не вживає, — знайшовши два данські описи без метрики і шістнадцять українських фрагментів, що цитували на англійський лад.","summary":"Вісімнадцять справжніх дефектів закрито, а разом із ними закрито й клас, бо кожен майбутній переклад порівнюється зі своїм англійським джерелом, перш ніж його…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Найшкідливіший різновид помилки перекладу в CV — не незграбна фраза. Це число, що зникає. Англійське речення, що заявляє п\u0026rsquo;ятдесятикратне поліпшення, перекладене реченням, яке каже «значно», є заявою, тихо відкликаною на одному ринку й збереженою на іншому, — і жодна перевірка орфографії, граматики чи людське читання самої лише цільової мови цього ніколи не помітить, бо перекладене речення є цілком доброю прозою.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Потрібна була перевірка, що читає мови одна проти одної, а не кожну окремо, на тих двох речах, які мають пережити переклад: числа й нотація, якою кожна мова їх записує.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Перевірка чисел витягує кожне число, відсоток, множник та одиницю з англійського рядка й вимагає, щоб кожне з них з\u0026rsquo;явилося в кожному перекладі того рядка, з формами множників, зіставленими для кожної мови окремо, а не збіганими буквально: англійська форма «у п\u0026rsquo;ятдесят разів» відповідає певній данській і певній українській вимові, і перевірка знає це зіставлення, а не вимагає самих лише цифр. Перевірка нотації є її дзеркалом: кожна мова має конвенції, які мусить вживати, і конвенції, яких вживати не має, зокрема десяткові розділювачі, групування тисяч і лапки. Українська бере лапки‑ялинки; англійські подвійні лапки в українському реченні є так само хибними, як пропущене число, і їх набагато легше внести копіюванням. Перший повний прогін виявив два данські описи, де показник, присутній в англійській, було втрачено, і шістнадцять українських фрагментів із лапками в англійському стилі.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Вісімнадцять справжніх дефектів закрито, а разом із ними закрито й клас, бо кожен майбутній переклад порівнюється зі своїм англійським джерелом, перш ніж його можна закомітити. Чого перевірка не вміє, так це судити про зміст: вона доводить, що число вижило і що пунктуація рідна, а переклад, що зберігає кожне число й водночас перевертає заяву навпаки, проходить її без зауважень.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Data Governance","Python","Автоматизація та CI/CD","Документація","Інтернаціоналізація","Тестування та QA","Data Governance та якість даних","Інтернаціоналізація та локалізація","Технічна документація"]},{"id":"https://software.engineer.company/uk/portfolio/built-a-native-macos-messaging-client-in-swift-6-154/","url":"https://software.engineer.company/uk/portfolio/built-a-native-macos-messaging-client-in-swift-6-154/","title":"Побудувала нативний клієнт обміну повідомленнями для macOS на Swift 6 і SwiftUI — 11 141 рядок у 53 файлах — поверх C‑інтерфейсу ядра на Rust, злінкованого як статичний архів із зафіксованої ревізії.","summary":"Рідний клієнт, що запускається як програма для Mac, використовує власні матеріали та елементи керування платформи й не несе вбудованого браузера.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Протокол обміну повідомленнями мав добре випробуване ядро, написане на Rust, і клієнти на кількох платформах, але настільний досвід на macOS був кросплатформною оболонкою — він не мав вигляду програми для Mac, не поводився як така й ніс середовище виконання, якого рідній програмі не потрібно. Ядро відкриває свою спроможність через C‑інтерфейс, а це означає, що будь‑яка мова, здатна викликати C, може на ньому будувати, і Swift здатен.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Рідного клієнта треба було збудувати безпосередньо на тому C‑інтерфейсі, поточною мовою платформи та її поточним інтерфейсним каркасом, із ядром, вкомпонованим усередину, а не постаченим поруч.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Програма має 11 141 рядок Swift у п\u0026rsquo;ятдесяти трьох файлах у цілі застосунку, збудована на SwiftUI з ядром, вкомпонованим як статичний архів, зібраний із закріпленої висхідної ревізії. Закріплення ревізії, а не стеження за гілкою, є тим рішенням, що робить збирання відтворюваним: C‑інтерфейс є контрактом, і рухоме ядро змінює контракт, не змінюючи жодного рядка Swift. Шарування тримає небезпечну поверхню малою — тонка обгортка володіє кожним вказівником і кожним рядком, що перетинає межу, моделі над нею є звичайними значеннями Swift, а інтерфейсний шар ніколи не бачить сирого вказівника. Усе, що повертає C‑інтерфейс, має правило володіння, і помилитися в одному з них означає або витік, або аварію без жодного попередження компілятора між ними, тож саме в обгортці живе вся дисципліна пам\u0026rsquo;яті проєкту. Збиранням керує виконавець завдань із п\u0026rsquo;ятдесятьма шістьма цілями, що охоплюють компіляцію ядра, збирання Swift, набори тестів, лінтери та пакування.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Рідний клієнт, що запускається як програма для Mac, використовує власні матеріали та елементи керування платформи й не несе вбудованого браузера. Те, чого не зроблено, слід зазначити: це не випущений реліз. Немає ні нотаризованого розповсюдження, ні каналу оновлень, і в інтерфейсі одна мова, тож це радше робоча програма, ніж продукт, який хтось інший використовує.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Frontend‑розробка","Full‑Stack розробка","UX / UI‑дизайн","Архітектура рішень","Дизайн‑системи та UI","Full‑Stack продуктова розробка","UI/UX‑дизайн та дизайн‑системи","Архітектура платформи та рішень"]},{"id":"https://software.engineer.company/uk/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/","url":"https://software.engineer.company/uk/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/","title":"Спинила застосунок, що наповнював пам'ять зі швидкістю 41 МБ за секунду — зафіксовані 111 ГБ стиснених сторінок на машині з 36 ГБ, — обмеживши кожен потік подій, підписуючись за типом події та поклавши бюджет швидкості на журналювання, що звело 610 996 рядків журналу до 1 411.","summary":"Пам'ять лишається рівною під тривалим навантаженням, і той самий сеанс, що давав 610 996 рядків журналу, дає 1 411.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Програма наповнювала пам\u0026rsquo;ять, доки операційна система її не вбивала. Зафіксований інцидент сягнув 111 ГБ стиснутих сторінок на машині з 36 ГБ, зростаючи приблизно на 41 МБ за секунду, а файл журналу за один короткий сеанс тримав 610 996 рядків. Машина в такому стані не повільна, вона непридатна — вбивство приходить після того, як підкачування вже змусило все інше на робочому столі перестати відповідати.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Зростання треба було знайти, а не вгадати, і кожному необмеженому шляху треба було дати межу, бо одна обмежена черга поруч із трьома необмеженими не є виправленням.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Причин‑множників було три, і саме множення пояснює, чому це відбувалося так швидко. Потік подій із ядра споживався без жодної межі, тож події надходили швидше, ніж інтерфейс міг їх застосувати, і доробок утримувався, а не відкидався. Кожен передплатник отримував кожну подію й фільтрував після цього, тож вартість однієї події множилася на кількість слухачів, і фільтрування кожного слухача виділяло пам\u0026rsquo;ять. А журналювання було небюджетованим, тож кожна подія породжувала рядки журналу — і це складений доданок, бо обсяг журналювання був пропорційним до обсягу того, що йшло не так. Виправлення взялося за всі три: обмежені буфери з явною політикою того, що стається за їх заповнення, передплата за типом події, тож слухача будять лише для подій, яких він хоче, і бюджет швидкості на журналювання, що згортає повтори, а не пише кожен. Регресійний тест жене високу швидкість подій і стверджує, що стеля пам\u0026rsquo;яті тримається, тож межа є властивістю збирання, а не коментарем.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Пам\u0026rsquo;ять лишається рівною під тривалим навантаженням, і той самий сеанс, що давав 610 996 рядків журналу, дає 1 411. Чесним зауваженням є те, що бюджет швидкості на журналювання відкидає інформацію: коли щось іде не так швидко, запис про це тепер навмисно неповний, і це обмін, зроблений свідомо проти альтернативи, якою є машина, що спиняється.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","Архітектура рішень","Моніторинг та observability","Надійність і резервне копіювання","Оптимізація продуктивності","Тестування та QA","Архітектура платформи та рішень","Надійність та моніторинг (SRE)"]},{"id":"https://software.engineer.company/uk/portfolio/adopted-swift-6-strict-concurrency-over-a-c-event-loop-156/","url":"https://software.engineer.company/uk/portfolio/adopted-swift-6-strict-concurrency-over-a-c-event-loop-156/","title":"Прийняла повну сувору паралельність Swift 6 без акторів, перекинувши місток від блокувального циклу подій C до головного актора через одного виробника, одного споживача й один порядок — після встановлення, що задача на подію губить порядок, від якого залежить інтерфейс.","summary":"Програма компілюється за повної суворої перевірки паралельності без придушень, а впорядкованість подій є структурною властивістю, а не сподіванням.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Повна сувора перевірка паралельності у Swift 6 перетворює гонитви за даними на помилки компіляції замість переривчастих аварій. Впроваджувати її проти бібліотеки на C — саме там, де стає важко: цикл подій ядра є блокувальним викликом, що має вічно виконуватися поза головним потоком, а значення, які він повертає, є вказівниками без жодних гарантій щодо паралельності. Компілятор не може міркувати про це все й відхилятиме всі, доки межу не буде описано явно.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Повну перевірку треба було ввімкнути без жодних запасних лазівок, а це означало спроєктувати перехід від блокувального циклу на C до головного актора, а не обставляти його анотаціями.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Очевидним підходом є актор на підсистему, і його відкинули за вимірюванням, а не за смаком. Породження задачі на кожну вхідну подію дозволяє середовищу виконання планувати їх у будь‑якому порядку, а потік подій ядра є впорядкованим — подія «повідомлення змінено», що обганяє подію «повідомлення створено», на яку вона посилається, дає інтерфейс, що показує редагування чогось, чого ще не існує. Повторний вхід в актора робить це гіршим, а не кращим, бо актор може призупинитися посеред методу й обробити інший виклик. Те, що це замінило, є навмисно простим: один потік‑виробник, що володіє блокувальним циклом, один споживач, одна черга між ними та єдиний стрибок на головного актора наприкінці. Порядок зберігається, бо шлях рівно один і ніщо нічого не обганяє. Небезпечні типи, що перетинають цю межу, загорнуто в типи, чию потокобезпеку стверджують на обгортці, а не припускають, і твердження задокументовано разом із тим, чому воно чинне: вказівником володіє один потік, і його копіюють, перш ніж передати.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Програма компілюється за повної суворої перевірки паралельності без придушень, а впорядкованість подій є структурною властивістю, а не сподіванням. Ціною є те, що задум менш паралельний, ніж міг би бути: усе стікається через одного споживача, і якщо той споживач колись стане вузьким місцем, виправлення вимагатиме заново вивести, які події можна безпечно переставляти, а це саме той аналіз, якого це дозволило уникнути.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Backend‑розробка","Frontend‑розробка","Архітектура рішень","Надійність і резервне копіювання","Оптимізація продуктивності","Тестування та QA","Backend- та API‑розробка","Архітектура платформи та рішень","Технічне лідерство та консалтинг"]},{"id":"https://software.engineer.company/uk/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/","url":"https://software.engineer.company/uk/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/","title":"Написала парсер, який читає справжній C‑заголовок на 7 308 рядків і перевіряє кожне місце виклику, кожну константу переліку й те, що кожен клас‑власник вказівника є final, після того як рукописний заголовок‑заглушка дозволив викликам до трьох вилучених функцій скомпілюватися, злінкуватися й впасти.","summary":"Клас дефектів, що спричинив початкову аварію, не може повторитися, бо застаріле посилання тепер є відмовою збирання, а не відмовою під час виконання.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e На початку проєкту C‑інтерфейс представляв рукописний заголовний файл, що описував функції, яких очікувала програма. Той заголовок компілювався, програма зв\u0026rsquo;язувалася, а виклики трьох функцій, яких у ядрі більше не існувало, доходили до моменту виклику й аварійно завершувалися. І компілятор, і компонувальник задовольнилися описом бібліотеки замість самої бібліотеки, а розрив виявився лише під час виконання.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Справжній заголовок — 7 308 рядків і 268 оголошень — мав стати авторитетом, і кожне його використання в коді Swift треба було звіряти з ним автоматично, а не переглядом.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Перевіркою є розбирач, що читає справжній висхідний заголовок і будує множину функцій, констант переліку й типів, які той оголошує, а потім читає код Swift і розв\u0026rsquo;язує кожне місце виклику та кожне посилання на константу проти цієї множини. Виклик функції, якої заголовок не оголошує, валить збирання. Посилання на константу переліку, яку перейменували, валить збирання. Поточне число — 132 з 268 оголошень, на які є посилання, і знати, які 136 не використовуються, саме собою корисно, бо це каже точно, якої частини ядра клієнт не досяг. Розбирач також примусово застосовує правило, якого не може компілятор: кожен клас Swift, що володіє вказівником у ядро, має бути фінальним. Нефінальний клас, що володіє вказівником, можна успадкувати, а підклас, що перевизначає деініціалізацію або додає власний час життя, змінює момент звільнення вказівника — використання після звільнення без жодного небезпечного ключового слова поблизу. Правило перевіряють за іменем по всьому дереву.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Клас дефектів, що спричинив початкову аварію, не може повторитися, бо застаріле посилання тепер є відмовою збирання, а не відмовою під час виконання. Обмеженням є те, що розбирач розуміє оголошення заголовка, а не його семантику: він доводить, що функція існує з відповідним іменем, а функція, чиє значення чи правило володіння змінилося вище за течією зі збереженням сигнатури, проходить без зауважень.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Автоматизація та CI/CD","Безпека","Документація","Тестування та QA","Backend- та API‑розробка","DevOps та автоматизація CI/CD","Технічна документація"]},{"id":"https://software.engineer.company/uk/portfolio/named-all-seventeen-interface-icons-for-screen-readers-159/","url":"https://software.engineer.company/uk/portfolio/named-all-seventeen-interface-icons-for-screen-readers-159/","title":"Назвала кожен суто піктограмний елемент керування в інтерфейсі для зчитувачів екрана після того, як кнопка надсилання оголошувалася як «arrow up circle, button», і написала лінтер, що вимагає підпис у межах восьми рядків від піктограми.","summary":"Усі сімнадцять елементів керування оголошують свою функцію, і вісімнадцятий не можна додати без неї.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Інтерфейс використовував системні символи для своїх елементів керування, а символ без мітки доступності екранний читач озвучує його власним внутрішнім іменем. Кнопка надсилання оголошувалася як «стрілка вгору коло, кнопка». Так само робив кожен інший елемент керування лише з піктограмою в програмі, кожен по‑своєму — сімнадцять із них описували власний малюнок замість своєї функції.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Кожен елемент керування лише з піктограмою потребував мітки, що описує, що він робить, і виправлення мало прийти з перевіркою, бо наступна додана піктограма інакше внесла б дефект назад негайно.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Кожному із сімнадцяти надали мітку, що називає дію, а не форму, і там, де значення елемента залежить від стану, мітка йде за станом, а не є сталою. Перевірка є тією частиною, яку варто описати, бо загального правила «чи це доступно» для цього не існує. Лінтер шукає конструкцію, що створює елемент керування лише з піктограмою, і далі вимагає мітки доступності в межах восьми рядків від неї. Вісім рядків є навмисно грубою евристикою, і її обрано вимірюванням: вона достатньо довга, щоб охопити кожен законний спосіб, яким кодова база пише один із цих елементів разом із його модифікаторами, і достатньо коротка, щоб мітка, приєднана до іншого подання нижче, її випадково не задовольнила. Точне правило тут мало б розуміти ланцюжки модифікаторів SwiftUI як дерево, а дешеве правило близькості ловить справжню помилку — а це не хибно підписаний елемент, це непідписаний.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Усі сімнадцять елементів керування оголошують свою функцію, і вісімнадцятий не можна додати без неї. Неточність правила є реальною й зазначена там, де його визначено: його може задовольнити мітка на сусідньому поданні, тож воно доводить, що мітка існує поруч, а не що мітка правильна, і для правильності досі потрібно, щоб хтось її послухав.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Автоматизація та CI/CD","Дизайн‑системи та UI","Документація","Тестування та QA","UI/UX‑дизайн та дизайн‑системи"]},{"id":"https://software.engineer.company/uk/portfolio/built-a-48-token-design-system-160/","url":"https://software.engineer.company/uk/portfolio/built-a-48-token-design-system-160/","title":"Побудувала систему дизайну на 48 токенів поверх власного скляного матеріалу платформи й написала лінтер, який відхиляє магічне число, жорстко задений розмір шрифту чи анімацію, що ігнорує настройку зменшеного руху.","summary":"Сорок вісім токенів описують увесь інтерфейс, вигляд іде за системою, і жодне з трьох руйнувань не можна закомітити.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Інтерфейс, збудований додаванням подань, накопичує значення: радіус заокруглення тут, шрифт у чотирнадцять пунктів там, анімація на дві десятих секунди десь іще. Кожне окремо є розумним, а разом вони є дизайном, якого не можна змінити, бо не існує такої речі, як «радіус заокруглення», щоб її змінити, — їх сорок, злегка різних, розсипаних по п\u0026rsquo;ятдесяти файлах.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Візуальний словник треба було скоротити до іменованої множини, вираженої проти власного матеріалу платформи, а не винайденої заново, і захищеної перевіркою, щоб він лишався скороченим.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Системою є сорок вісім токенів у шести групах: відступи, типографіка, колір, радіус, підняття та рух. Колір і матеріал збудовано на семантичних кольорах платформи та її скляному матеріалі, а не на сталих значеннях, і саме це змушує інтерфейс іти за системним виглядом, акцентним кольором і налаштуваннями контрасту без жодного коду, що за ними стежить. Типографіка відображається на текстові стилі платформи, тож вона масштабується з уподобою розміру в користувача замість прив\u0026rsquo;язки до пунктового значення. Лінтер відхиляє три речі: числовий літерал там, де належить токен відступу чи радіуса, жорстко заданий кегль будь‑де і анімацію, оголошену без шанування уподоби зменшеного руху. Третя є тією, що інакше руйнувалася б найшвидше, бо анімацію додають у мить наведення блиску, і саме перевірку уподоби пропускають — тож правило робить саму анімацію неможливою для написання без неї, а не просить когось пам\u0026rsquo;ятати.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Сорок вісім токенів описують увесь інтерфейс, вигляд іде за системою, і жодне з трьох руйнувань не можна закомітити. Межею є те, що система токенів обмежує узгодженість, а не якість, — тепер усе пасує одне до одного, а пасувати не те саме, що бути добре спроєктованим, і це судження не виносить жоден лінтер у цьому проєкті.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Автоматизація та CI/CD","Дизайн‑системи та UI","Тестування та QA","UI/UX‑дизайн та дизайн‑системи","Бренд, маркетинг та SEO"]},{"id":"https://software.engineer.company/uk/portfolio/reached-the-unused-half-of-the-messaging-core-161/","url":"https://software.engineer.company/uk/portfolio/reached-the-unused-half-of-the-messaging-core-161/","title":"Дістала ту половину ядра обміну повідомленнями, якої застосунок ніколи не використовував, — передавання резервної копії, зникомі повідомлення, редагування та повторне надсилання, підтверджені запрошення, проксі та політику шифрування, — ведучи кожен тест проти справжньої бібліотеки без заглушок.","summary":"Раніше недосяжну половину ядра тепер ганяють тести проти справжньої бібліотеки, а обгортка несе найвищу підлогу в проєкті.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Клієнт використовував приблизно половину того, що пропонує ядро обміну повідомленнями. Невикористана половина не була маловідомою — перенесення резервних копій між пристроями, зникомі повідомлення, редагування та повторне надсилання повідомлень, перевірені запрошувальні посилання, налаштування проксі та політика шифрування для розмови. Кожне з цього є можливістю, якої очікував би користувач, і кожне було невипробуваною ділянкою C‑інтерфейсу, а це небезпечніший факт, бо невипробувана ділянка C‑інтерфейсу — саме там, де живуть помилки володіння.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Недосяжну спроможність треба було задіяти й покрити, і тести мали виконуватися проти справжньої бібліотеки, а не проти заміщувача.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Прийнятим правилом було жодних імітацій для ядра. Імітація C‑інтерфейсу кодує переконання розробника про те, що робить бібліотека, а кожен вартий пошуку дефект тут є місцем, де це переконання хибне, — тож пройдений тест на імітації є свідченням про імітацію. Натомість тести створюють справжні облікові записи в тимчасових каталогах, ганяють справжню бібліотеку і стверджують про те, що вона насправді повертає, і кожен набір прибирає власний стан. Саме це зробило покриття змістовним: задіяти перенесення резервних копій означало обробити машину станів справжнього перенесення та її шляхи відмов, а задіяти перевірені запрошення означало сконструювати справжній формат посилання й дати бібліотеці його розібрати. Підлоги покриття задано на кожен шар окремо, а не одним числом: вісімдесят чотири відсотки для обгортки ядра, сімдесят п\u0026rsquo;ять для допоміжних функцій і шістдесят п\u0026rsquo;ять для моделей, з тим міркуванням, що шар, який торкається сирих вказівників, слід тримати найвище, а модель, яка здебільшого складається зі збережених властивостей, не варто набивати тестами заради середнього.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Раніше недосяжну половину ядра тепер ганяють тести проти справжньої бібліотеки, а обгортка несе найвищу підлогу в проєкті. Ціною є швидкість і передбачуваність: тести проти справжньої бібліотеки повільніші за імітації, і вони можуть падати з причин середовища, а це ціна за їхню здатність падати зі справжніх.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["API та інтеграції","Backend‑розробка","Автоматизація та CI/CD","Безпека","Надійність і резервне копіювання","Тестування та QA","Backend- та API‑розробка","DevOps та автоматизація CI/CD","Безпека та керування доступом"]},{"id":"https://software.engineer.company/uk/portfolio/rewrote-the-error-messages-against-a-tone-standard-162/","url":"https://software.engineer.company/uk/portfolio/rewrote-the-error-messages-against-a-tone-standard-162/","title":"Переписала повідомлення про помилки застосунку за письмовим стандартом тону після того, як відмовлений вхід звинуватив користувача в друкарській помилці, тоді як провайдер насправді вимагав пароль для застосунку, і покрила це тестом, який називає провайдера.","summary":"Поверхня помилок дотримується зазначеного стандарту, а випадок, що до нього спонукав, покрито тестом, який падає на старому тексті.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Вхід до великого поштового провайдера не вдався, і програма сказала користувачеві, що його пароль хибний. Він не був хибним. Той провайдер вимагає окремого пароля застосунку для сторонніх клієнтів і відхиляє пароль облікового запису незалежно від того, наскільки ретельно його набрано. Повідомлення відправило користувача перенабирати те, що ніколи не могло спрацювати, а справжня вказівка — піти й створити інший різновид пароля — не з\u0026rsquo;являлася ніде.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Повідомлення про помилки треба було переписати за письмовим стандартом, а не латати по одному, бо це було видимим випадком звички, що проходила крізь усі них.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Стандарт має три вимоги: скажи, що сталося, ніколи не натякай, що користувач зробив щось не так, коли причина деінде, і дай наступну дію, коли така є. Застосований до всієї поверхні помилок, він показав, що більшість повідомлень порушує щонайменше одну — кілька були рядком помилки нижчої бібліотеки, пропущеним наскрізь, а він описує стан для програміста, а не ситуацію для людини. Випадок із провайдером переписали так, щоб назвати провайдера, зазначити, що він вимагає окремого пароля застосунку для інших клієнтів, і сказати, де такий створити. Тест є тим, що не дає цьому повернутися, і він навмисно конкретний: він жене невдалий вхід проти того провайдера й стверджує, що повідомлення містить ім\u0026rsquo;я провайдера та вислів, що описує потрібний тип облікових даних. Тест, що стверджував би лише появу якоїсь помилки, пройшов би й на початковому хибному повідомленні, тож твердження стоїть на вмісті, а це єдина частина, що колись була зламана.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Поверхня помилок дотримується зазначеного стандарту, а випадок, що до нього спонукав, покрито тестом, який падає на старому тексті. Нерозв\u0026rsquo;язаним лишається масштаб: стандарт примусово тримають переглядом і одним тестом на одне повідомлення, а інші провайдери зі своїми особливими вимогами не мають рівноцінного тесту, тож клас задокументовано, а не закрито.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Frontend‑розробка","UX / UI‑дизайн","Безпека","Документація","Продукт і вимоги","Тестування та QA","UI/UX‑дизайн та дизайн‑системи","Продуктова стратегія та вимоги","Технічна документація"]},{"id":"https://software.engineer.company/uk/portfolio/built-the-visual-identity-from-two-drawings-164/","url":"https://software.engineer.company/uk/portfolio/built-the-visual-identity-from-two-drawings-164/","title":"Побудувала набори піктограм і фавіконів компанії з двох рукотворних малюнків, де кожен похідний ресурс перегенеровується скриптом, а перевірка валиться, коли похідний файл закомічено раніше за своє джерело.","summary":"Два малюнки виробляють кожну опубліковану піктограму, перегенерація є однією командою, а застарілий ресурс валить збирання.","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Візуальну ідентичність малої компанії зазвичай купують, генерують або збирають зі стокових матеріалів, і результатом є ідентичність, що не належить нікому. Альтернативна проблема гірша: рукотворна графіка, що існує лише як експортовані файли, де вихідний малюнок втрачено, експорти редагують безпосередньо, і протягом року версії в ужитку розходяться між собою, а оригіналу, який це владнав би, не лишилося.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Ідентичність треба було намалювати, а не роздобути, і конвеєр від малюнка до опублікованого ресурсу мав бути відтворюваним, щоб кожен файл на сайті виводився, а не зберігався.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e В основі згенерованого зображального матеріалу лежать два рукотворні малюнки — знак компанії та шестірня, що стала фавіконом, — і кожну піктограму, яку публікує сайт, вироблено з них. Знак є растровим малюнком; шестірня є вектором. З них скрипти виробляють кожну похідну форму: набір favicon у потрібних розмірах, дотикові піктограми, зображення для соціальних попереднів, адаптивні растрові варіанти в кожній ширині й у кожному сучасному форматі та версії для конкретних тем. Генерація є завданням, яке може виконати будь‑хто, тож питання «звідки взявся цей файл» має відповідь, що є командою. Перевірка застарілості є тим шматком, що тримає це разом: вона порівнює час зміни кожного похідного ресурсу з його джерелом і падає, коли похідний файл старіший, і це ловить саме ту відмову, задля запобігання якій цей задум існує, — хтось редагує джерело, забуває перегенерувати, і опублікований сайт далі показує графіку, що більше не відповідає оригіналові. Правило, що похідні файли ніколи не редагують вручну, зазначено там, де живуть джерела.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Два малюнки виробляють кожну опубліковану піктограму, перегенерація є однією командою, а застарілий ресурс валить збирання. Компромісом є жорстка залежність від набору інструментів: похідні файли закомічено, тож сайт збирається будь‑де, але зміна ідентичності вимагає, щоб генераційне знаряддя досі працювало, а вихідний формат, який перестане читатися, забере всю ідентичність із собою.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["UX / UI‑дизайн","Автоматизація та CI/CD","Бренд і маркетинг","Веброзробка","Дизайн‑системи та UI","Тестування та QA","UI/UX‑дизайн та дизайн‑системи","Бренд, маркетинг та SEO","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/portfolio/published-the-site-as-a-tor-onion-mirror-on-a-readable-168/","url":"https://software.engineer.company/uk/portfolio/published-the-site-as-a-tor-onion-mirror-on-a-readable-168/","title":"Опублікувала сайт як onion‑дзеркало в Tor на читабельній адресі, що починається з engineer, з ключем, згенерованим поза хостом, тож він ніколи не потрапив ні до цього репозиторію, ні на ноутбук, і лишила ці двері єдиними з чотирьох, які ніколи не рахують.","summary":"Сайт має четверо дверей до однієї збірки, і ці -- єдині, яких ніколи не рахують. Запити Gemini та з'єднання Gopher підраховують щодня без адреси й без шляху; в…","content_html":"\u003cp\u003e\u003cstrong\u003eСитуація.\u003c/strong\u003e Сайт уже відповідав на трьох протоколах з однієї збірки. Читач, якому треба було дістатися до нього, не виказуючи, що він дістався, усе ще робив гак через вихідний вузол до звичайної адреси, а це слабше за власні двері. Очевидне заперечення проти четвертих дверей \u0026ndash; це фаєрвол, і воно не діє: демон анонімності виходить у мережу, будуючи вихідні ланцюги, тож ніхто не дзвонить усередину, жоден порт не відкривається, і жодному з двох шарів фаєрвола нема чого узгоджувати.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eЗавдання.\u003c/strong\u003e Дзеркало мало віддавати ті самі сторінки, що й звичайна адреса, бути опублікованим там, де опубліковані інші дзеркала, нести адресу, яку людина може прочитати вголос, а не випадковий рядок, і ніколи не дозволити приватному ключу, який і є адресою, торкнутися цього репозиторію чи ноутбука.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eДія.\u003c/strong\u003e Роль встановлює демон із власного пакета дистрибутива, пише конфігурацію з вимкненим вихідним портом проксі й відмовляється перезаписувати особу, якої не генерувала, \u0026ndash; тож ключ, покладений рукою, просто використовується. Читабельну адресу не можна обрати, лише знайти: адреса \u0026ndash; це відкритий ключ у base32, тож префікс купують, генеруючи пари ключів, доки одна з них випадково не закодує потрібні літери, і кожен символ коштує в тридцять два рази більше за попередній. Куплений префікс читається як власна назва компанії. Адреса \u0026ndash; це оголошене значення в інвентарі, і кожне зведення стверджує, що справжній файл особи на хості збігається з ним, тож підмінений ключ зі застарілим оголошенням валить запуск, а не мовчить. Ключ ловлять обидві сторожі секретів, після того як було виміряно, що очевидний шаблон для файлу ключа збігається з ключем розгортання й проминає цей. Виведення з обігу випадкової адреси, з якою дзеркало вийшло, було поетапним переходом, а не перемикачем, тож опублікована адреса працювала, доки публікувалася читабельна. Крок, що видавався останнім, ним не був: ключ ліг правильно, а зведення повідомило про відсутність змін, бо ніщо ще не називало нову теку, тож нова адреса так і не була опублікована \u0026ndash; тепер роль валиться на особі на диску, якої не називає жодна служба.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eРезультат.\u003c/strong\u003e Сайт має четверо дверей до однієї збірки, і ці \u0026ndash; єдині, яких ніколи не рахують. Запити Gemini та з\u0026rsquo;єднання Gopher підраховують щодня без адреси й без шляху; в onion немає лічильника й немає прапорця, щоб його додати, бо порахувати там читача \u0026ndash; це саме те єдине, заради запобігання чому протокол існує, і сліпота тут ціна позиції, а не прогалина у звітності. Дзеркало окупилося ще й як друга думка: його перші читачі сиділи на іншому рушії браузера, який не реалізує керовану прокруткою анімацію, на яку спирався колофон, тож кожен із них отримав колофон, намальований поверх головної сторінки. Це був справжній дефект звичайного сайту, знайдений аудиторією, яка не мала іншого способу про нього повідомити.\u003c/p\u003e\n","date_published":"2026-10-09T14:31:15+02:00","date_modified":"2026-10-09T14:31:15+02:00","language":"uk","tags":["Linux та сервери","Безпека","Веброзробка","Інфраструктура","Системне адміністрування","Infrastructure as Code","Безпека та керування доступом","Розробка вебсайтів та CMS"]},{"id":"https://software.engineer.company/uk/notes/safari-underline-font-subset/","url":"https://software.engineer.company/uk/notes/safari-underline-font-subset/","title":"Підкреслення, яке не обходило літери","summary":"Safari проводив наші підкреслення крізь кожен виносний елемент. Причиною був кириличний підшрифт на сторінках, які його не завантажують.","content_html":"\u003cp\u003eНаш власний сайт підкреслює кожне посилання й дозволяє браузеру вирізати\nпроміжок там, де хвостик літери перетинає лінію, — \u003ccode\u003eg\u003c/code\u003e, \u003ccode\u003ep\u003c/code\u003e, кома. У Safari\nцього не відбувалося. Лінія йшла просто крізь них. І так було на англійських та\nданських сторінках відтоді, як сайт став\nбагатомовним (вада, про яку ніхто не повідомляє, бо вона просто має дешевий вигляд).\u003c/p\u003e\n\u003cp\u003eПричиною були три оголошення шрифту для абетки, яку ті сторінки ніколи не\nзавантажують.\u003c/p\u003e\n\u003ch2 id=\"що-браузер-має-робити\"\u003eЩо браузер має робити\u003c/h2\u003e\n\n\u003cp\u003e\u003ccode\u003etext-decoration-skip-ink\u003c/code\u003e — це властивість, яка піднімає підкреслення над\nнижнім виносним елементом. Вона ввімкнена за замовчуванням, і роками відповіддю\nна «моє підкреслення має неправильний вигляд» було взятися за\n\u003ccode\u003etext-underline-offset\u003c/code\u003e і посунути лінію нижче. Це хибний рефлекс: зсув лінії\nзмінює дизайн, а бракувало насправді саме проміжку.\u003c/p\u003e\n\u003cp\u003eПерш ніж дійти до цікавого, ми знайшли дві справжні причини, і обидві варті\nуваги.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eПідкреслення завтовшки \u003ccode\u003e1px\u003c/code\u003e отримує проміжок розміром \u003ccode\u003e1px\u003c/code\u003e.\u003c/strong\u003e Розрив, який\nвирізає рушій, пропорційний товщині лінії, що його вирізає. Наш стиль\nзафіксував товщину на одному пікселі, і це лишало близько 0,6px повітря з\nкожного боку штриха — технічно проміжок, візуально лінія просто крізь літеру.\n\u003ccode\u003etext-decoration-thickness: auto\u003c/code\u003e змасштабував обидві величини разом і збільшив\nпроміжок з 3,5px до 12,4px, не зсунувши підкреслення ані на піксель.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003efrom-font\u003c/code\u003e — не той безпечний варіант, яким здається.\u003c/strong\u003e Він читає товщину,\nяку оголошує сам шрифт, а Ubuntu оголошує 0,056em для Light, 0,020em для\nMedium і 0,120em для Bold — родина, у якої лінія Medium важить менше за\nполовину лінії Light. На великих розмірах це шестипіксельна лінія поряд із\nдвопіксельною на одній сторінці.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eЦе виправило Chrome. Safari й далі вів лінію крізь усе.\u003c/p\u003e\n\u003ch2 id=\"частина-яка-забрала-найбільше-часу\"\u003eЧастина, яка забрала найбільше часу\u003c/h2\u003e\n\n\u003cp\u003eМи виміряли це як належить: запустити справжній Safari, перефарбувати\nпідкреслення, зробити знімок екрана у восьмикратному масштабі й порахувати\nпікселі, де лінія уривається й починається знову.\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003e\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eнамальована товщина\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eпроміжок навколо виносного елемента\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eChrome\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e2,00px\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e5,8 / 12,5 / 6,3px\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eSafari\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e1,38px\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e1,8 / 1,0 / 1,0px\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eОтже, Safari таки вирізав проміжок. Просто вшестеро вужчий за Chrome, а в\nрозмірі для читання проміжок в один піксель — це не проміжок. Гірше: звичний\nважіль лише погіршував справу. За товщини 3px Safari падав із трьох проміжків до\nодного, за 4px — до жодного, бо він не масштабує проміжок разом із лінією. Він\nфіксує його приблизно на 0,07em за будь-якого розміру, тоді як Chrome дає 0,6em.\u003c/p\u003e\n\u003cp\u003eМи перебрали проти нього близько двадцяти оголошень — \u003ccode\u003eskip-ink: all\u003c/code\u003e, обидва\nзастарілі написання властивості, кожну товщину від половини пікселя до чотирьох,\n\u003ccode\u003etext-underline-position\u003c/code\u003e, \u003ccode\u003efont-smoothing\u003c/code\u003e, \u003ccode\u003etext-rendering\u003c/code\u003e, \u003ccode\u003epaint-order\u003c/code\u003e.\nНіщо не розширило проміжок. Чесний висновок на той момент був такий: WebKit\nпросто обмежує проміжок, і зі стилів більше нічого не вдіяти.\u003c/p\u003e\n\u003cp\u003eТой висновок виявився хибним, а зламав його\n\u003ca href=\"https://github.com/fontsource/fontsource/issues/1096\"\u003eзвіт про ваду проти шрифтового проєкту\u003c/a\u003e:\nSafari ігнорує skip-ink, коли шрифт завантажено з нелатинською підмножиною.\u003c/p\u003e\n\u003ch2 id=\"справжня-причина\"\u003eСправжня причина\u003c/h2\u003e\n\n\u003cp\u003eСайт віддає Ubuntu шістьма частинами — три накреслення латиницею, три\nкирилицею, — щоб українська сторінка була набрана тим самим шрифтом, що й\nанглійська, а не відкочувалася до того, що запропонує система. Кожна частина\nоголошує діапазон символів, який покриває, і браузер завантажує лише ті\nчастини, які сторінці справді потрібні.\u003c/p\u003e\n\u003cp\u003eУсі шість були оголошені під однією назвою родини — це найочевидніший спосіб це\nзаписати. І саме він є спусковим гачком, зафіксованим як\n\u003ca href=\"https://bugs.webkit.org/show_bug.cgi?id=255159\"\u003eвада WebKit 255159\u003c/a\u003e: \u003cstrong\u003eколи\nодне накреслення в родині оголошує нелатинський діапазон символів, Safari\nпогіршує skip-ink для кожного символу цієї родини\u003c/strong\u003e — зокрема для латинського\nтексту на сторінці, яка ніколи не завантажує той інший файл.\u003c/p\u003e\n\u003cp\u003eАнглійська сторінка малювала свої підкреслення погано, бо десь у стилях існувало\nукраїнське оголошення шрифту. Коли ми видалили ті три рядки під час виконання й\nне змінили більше нічого, проміжки зросли з 1,8/1,0/1,0px до 4,5/11,0/5,0px.\u003c/p\u003e\n\u003ch2 id=\"виправлення\"\u003eВиправлення\u003c/h2\u003e\n\n\u003cp\u003eДайте другій системі письма власну назву родини й назвіть її у стеку шрифтів\nпісля першої:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-css\" data-lang=\"css\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e@\u003c/span\u003e\u003cspan class=\"k\"\u003efont-face\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003efont-family\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"nt\"\u003eUbuntuCyrillic\u003c/span\u003e\u003cspan class=\"o\"\u003e;\u003c/span\u003e   \u003cspan class=\"c\"\u003e/* було: Ubuntu */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003esrc\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"nt\"\u003eurl\u003c/span\u003e\u003cspan class=\"o\"\u003e(\u003c/span\u003e\u003cspan class=\"nt\"\u003eubuntu_300_cyrillic\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003ewoff2\u003c/span\u003e\u003cspan class=\"o\"\u003e)\u003c/span\u003e \u003cspan class=\"nt\"\u003eformat\u003c/span\u003e\u003cspan class=\"o\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;woff2\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003eunicode-range\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"nt\"\u003eU\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"nt\"\u003e0400-045F\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"nt\"\u003eU\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"nt\"\u003e0490-0491\u003c/span\u003e\u003cspan class=\"o\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"nd\"\u003eroot\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003e--body-font\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eUbuntu\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUbuntuCyrillic\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esystem-ui\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kc\"\u003esans-serif\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eЛатинська літера знаходиться в першій родині й ніколи не доходить до другої.\nКирилична проминає першу, де такого гліфа немає, і потрапляє в другу, а не в\nсистемний шрифт. Діапазони символів і далі вирішують, що завантажується, тож в\nзавантаженні не змінюється нічого: англійські та данські сторінки беруть три\nлатинські файли й жодного кириличного, українські — навпаки.\u003c/p\u003e\n\u003cp\u003eТри перейменовані оголошення й один запис у стеку. Проміжки в Safari зросли до\n4,5/11,0/5,0px, Chrome лишився недоторканим, підкреслення не зрушило з місця, а\nукраїнська й далі набирається в Ubuntu з тими самими ширинами.\u003c/p\u003e\n\u003ch2 id=\"що-ми-сказали-б-наступному\"\u003eЩо ми сказали б наступному\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eВимірювання skip-ink справедливе лише для того рушія, який його дав.\u003c/strong\u003e Ми\nмали таблицю чисел, правильний діагноз і справжнє виправлення — і все це було\nChromium. Знімок екрана, який відкрив справу наново, надійшов від людини, яка\nподивилася на сторінку.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eБеріться за товщину раніше, ніж за зсув.\u003c/strong\u003e Ширший проміжок зберігає дизайн;\nзсув лінії вниз його замінює.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eДілити шрифт за системами письма — правильно, але поділ має бути й у назві\nродини.\u003c/strong\u003e Одна назва на кілька систем письма читається краще й коштує вам\nskip-ink у Safari. Злити їх назад має вигляд прибирання, а є регресом.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eЗавантаження ніколи не було проблемою.\u003c/strong\u003e Будь-яка інтуїція підказує, що\nсторінка, яка малюється погано через кириличний шрифт, мусить завантажувати\nщось зайве. Вона не завантажувала. Досить було самого оголошення.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"джерела\"\u003eДжерела\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://bugs.webkit.org/show_bug.cgi?id=255159\"\u003eВада WebKit 255159 — \u003ccode\u003etext-decoration-skip-ink\u003c/code\u003e і підмножини шрифтів\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/fontsource/fontsource/issues/1096\"\u003eIssue 1096 у Fontsource, який назвав спусковий гачок\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-skip-ink\"\u003eMDN: \u003ccode\u003etext-decoration-skip-ink\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range\"\u003eMDN: \u003ccode\u003eunicode-range\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","date_published":"2026-09-28T00:00:00Z","date_modified":"2026-10-09T14:31:15+02:00","language":"uk"},{"id":"https://software.engineer.company/uk/notes/solana-mobile-wallet-deeplinks/","url":"https://software.engineer.company/uk/notes/solana-mobile-wallet-deeplinks/","title":"Як відкрити dApp у мобільних гаманцях Solana","summary":"Чому browse-deeplinks до Phantom, Solflare і Backpack не спрацьовують на мобільних, і точні формати, правила запуску та виправлення, які змушують їх працювати.","content_html":"\u003cp\u003eReact-dApp, побудований на \u003ccode\u003e@solana/wallet-adapter-react\u003c/code\u003e, без проблем\nпід\u0026rsquo;єднує десктопні гаманці, але на телефоні той самий потік розсипається:\nгаманець має відкрити dApp у власному вбудованому браузері, а deeplinks, які\nмали б це зробити, просто мовчки не спрацьовують. Backpack виводить на\nсторінку «завантажте застосунок»; Solflare відкриває застосунок, але ніколи —\nсайт; здається, що не працює жоден варіант. Ми розібрали проблему на частини,\nі виявилося, що це чотири окремі проблеми з одним спільним симптомом.\u003c/p\u003e\n\u003ch2 id=\"чотири-проблеми\"\u003eЧотири проблеми\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eПосилання для Backpack було сформоване неправильно.\u003c/strong\u003e Єдиний\nзадокументований формат —\n\u003ccode\u003ehttps://backpack.app/ul/v1/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e: універсальне посилання\nіз цільовим URL у шляху та обов\u0026rsquo;язковим \u003ccode\u003eref\u003c/code\u003e. Здогадка з власною схемою на\nкшталт \u003ccode\u003ebackpack://ul/v1/browse?url=...\u003c/code\u003e не збігається з жодним маршрутом,\nякий реєструє застосунок, тож користувач опиняється на сторінці встановлення\nгаманця.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSolflare теж потребує свого універсального посилання:\u003c/strong\u003e\n\u003ccode\u003ehttps://solflare.com/ul/v1/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e, а не голої схеми\n\u003ccode\u003esolflare://\u003c/code\u003e. Гола схема може запустити застосунок, не спрямувавши його —\nа це саме те, що «застосунок відкривається, але вкладку із сайтом\nдоводиться відкривати вручну».\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eОбидва параметри мають бути закодовані.\u003c/strong\u003e \u003ccode\u003eurl\u003c/code\u003e — це повна абсолютна\nадреса dApp, а \u003ccode\u003eref\u003c/code\u003e — origin, який робить запит; кожен проходить через\n\u003ccode\u003eencodeURIComponent\u003c/code\u003e. Незакодований \u003ccode\u003e?\u003c/code\u003e або \u003ccode\u003e\u0026amp;\u003c/code\u003e у цілі псує розбір, і\nгаманець відкривається на своєму головному екрані замість вкладки браузера.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eСпосіб запуску важить не менше за саме посилання.\u003c/strong\u003e Універсальні посилання\nперемикають застосунки лише під час навігації, якій довіряє операційна\nсистема — і вони навмисно не роблять нічого, коли їх вставляють в адресний\nрядок, і саме так цілком коректне посилання «не працює» під час тестування.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"задокументовані-формати\"\u003eЗадокументовані формати\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003ePhantom: \u003ccode\u003ehttps://phantom.app/ul/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e — саме тут без\n\u003ccode\u003e/v1\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eSolflare: \u003ccode\u003ehttps://solflare.com/ul/v1/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eBackpack: \u003ccode\u003ehttps://backpack.app/ul/v1/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eОдин шаблон покриває всі три:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003econst WALLET_BROWSE = {\n  phantom: (url, ref) =\u0026gt;\n    `https://phantom.app/ul/browse/${url}?ref=${ref}`,\n  solflare: (url, ref) =\u0026gt;\n    `https://solflare.com/ul/v1/browse/${url}?ref=${ref}`,\n  backpack: (url, ref) =\u0026gt;\n    `https://backpack.app/ul/v1/browse/${url}?ref=${ref}`,\n};\n\nfunction walletBrowseLink(\n  walletName,\n  targetUrl = window.location.href,\n) {\n  const build = WALLET_BROWSE[walletName.toLowerCase()];\n  if (!build) return null;\n  return build(\n    encodeURIComponent(targetUrl),\n    encodeURIComponent(window.location.origin),\n  );\n}\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"як-запустити-посилання-щоб-ios-та-android-його-прийняли\"\u003eЯк запустити посилання, щоб iOS та Android його прийняли\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eРендерте справжній якір, обчислений заздалегідь.\u003c/strong\u003e Звичайний\n\u003ccode\u003e\u0026lt;a href={walletBrowseLink('phantom')}\u0026gt;\u003c/code\u003e — найнадійніший спосіб запуску на\nобох платформах.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eЯкщо це має бути програмно\u003c/strong\u003e, присвоюйте \u003ccode\u003ewindow.location.href\u003c/code\u003e синхронно\nвсередині обробника натискання — без \u003ccode\u003eawait\u003c/code\u003e, без \u003ccode\u003efetch\u003c/code\u003e, без \u003ccode\u003esetTimeout\u003c/code\u003e\nперед цим. Після асинхронної роботи контекст жесту втрачено, і iOS\nвідкочується до вебсайту гаманця. Ніколи не використовуйте \u003ccode\u003ewindow.open\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eНіколи не тестуйте вставлянням в адресний рядок.\u003c/strong\u003e Універсальні посилання\nнавмисно там не спрацьовують; тестуйте посиланням, на яке натискають, або\nQR-кодом, який сканує камера.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eЗважайте на webview месенджерів.\u003c/strong\u003e Відкриті у вбудованому браузері\nTelegram або Instagram, універсальні посилання часто просто поглинаються, і\nнатомість завантажується звичайний вебсайт гаманця. Визначення за\nuser-agent — у кращому разі евристика, тож дайте користувачам ще й видимий\nзапасний вихід: «відкрийте в Safari чи Chrome, а тоді під\u0026rsquo;єднайтеся».\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"ґрунтовніше-виправлення-на-android\"\u003eҐрунтовніше виправлення на Android\u003c/h2\u003e\n\n\u003cp\u003eСаморобні deeplinks — це історія про iOS. На Android Mobile Wallet Adapter від\nSolana Mobile дає dApp, що працює в мобільному браузері, під\u0026rsquo;єднатися прямо до\nвстановленого застосунку гаманця, узагалі без гаку через вбудований браузер.\nСвіжі версії \u003ccode\u003e@solana/wallet-adapter-react\u003c/code\u003e реєструють мобільний адаптер\nавтоматично, тож оновлення пакетів wallet-adapter може полагодити Android саме\nсобою. Цільова архітектура: Mobile Wallet Adapter на Android, універсальні\nbrowse-посилання на iOS, де Apple не дозволяє нічого рівноцінного.\u003c/p\u003e\n\u003ch2 id=\"перевірка-на-пристрої\"\u003eПеревірка на пристрої\u003c/h2\u003e\n\n\u003col\u003e\n\u003cli\u003eСправжній пристрій, встановлений гаманець, посилання відкрито із системного\nбраузера — не з месенджера.\u003c/li\u003e\n\u003cli\u003eНатисніть відрендерене посилання або відскануйте QR-код; ніколи не\nвставляйте в адресний рядок.\u003c/li\u003e\n\u003cli\u003eПереконайтеся, що гаманець відкривається і dApp завантажується у вкладці\nйого вбудованого браузера — саме друга половина і ламається.\u003c/li\u003e\n\u003cli\u003eПовторіть без встановленого гаманця: універсальне посилання має деградувати\nдо вебсайту гаманця. Якщо ця сторінка з\u0026rsquo;являється, коли застосунок\nвстановлено, — посилання або спосіб запуску все ще неправильні.\u003c/li\u003e\n\u003cli\u003eПотім перевірте шлях через месенджер і додайте підказку «відкрийте у\nбраузері», якщо там не спрацьовує.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"джерела\"\u003eДжерела\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://docs.phantom.com/phantom-deeplinks/deeplinks-ios-and-android\"\u003ePhantom: deeplinks на iOS та Android\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://docs.solflare.com/solflare/technical/deeplinks/other-methods/browse\"\u003eSolflare: Browse-deeplink\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://docs.backpack.app/deeplinks/other-methods/browse\"\u003eBackpack: Browse-deeplink\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://docs.solanamobile.com/mobile-wallet-adapter/mobile-apps\"\u003eSolana Mobile: Mobile Wallet Adapter\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","date_published":"2026-08-10T00:00:00Z","date_modified":"2026-10-09T14:31:15+02:00","language":"uk"}]}