CV
Цель документа
Append only living document. Набор фактов отражающих персональное развитие в software. Не резюме. Не сопроводительное письмо. Цель документа - фиксация истории без позиционирования, метрик, маркетинга. Дополнительная цель документа - возможность использовать силы ИИ для сопоставления честной истории с конкретной рабочей вакансией, последующей генерацией непротиворечивой проекции в виде Резюме.
CV (Curriculum Vitae) - ход жизни (латынь)- хроника биографических фактов.Résumé - выжимка (французский)- сжатая проекция биографии под требования конкретной вакансии.
Документ может иметь художественный стиль. Если что-то отсутствует, вероятно, такого опыта и не было.
Некоммерческая предыстория
2009-2011 - Знакомство с компьютером и интернетом
Появился первый компьютер. Как и все отдаленные от подобной техники пользователи сталкивался с первыми трудностями. Читал первую книгу по работе с Windows. Глубже погружаясь в проблемы и их решения, постепенно стал одним из парней на районе, способным установить винду и поменять оперативную память. Будучи подростком начал интересоваться играми. В том числе, углублялся во внутренние директории. Изучал устройство директорий, системных файлов, конфигураций. Правил ini файлики, меняя правила игры. Впервые начал проявлять интерес к устройству вместо использования. В 2011 году в дом провели первый ADSL интернет. Низкая скорость - огромный клад знаний.
2017 - ФСБ МТС
Находясь на курсантской службе в военном учреждении получал образование специалиста многоканальных телекоммуникационных систем. Обширная теория и прикладная практика в условиях военного применения. Сеть, Linux, cisco, tcp/ip, модель OSI, понятие пакета, терминал. Коммутация, радио-волны, шифрование. Доступ к мобильной, компьютерной технике и к интернету был ограничен и строго направлен на цели тематических задач. Таким образом тренировал важное умение исследования темы в условиях сжатых сроков и контролируемого списка материалов. Развивал навык структурирования полученной информации в курсовых курсантских работах. Жизненный этап курсантской жизни дисциплинировал порядок мышления и научил разделять проблемы. Там же впервые заинтересовался разработкой ПО. C#, JS, HTML, CSS, Git. Курсантская служба включала в себя множество различных опционных секций на выбор. Среди них был "научный кружок", который довольно прямо был связан с программированием.
2019 - Программирование
Осознал, что программирование для меня оказалось кратно интересней военной службы. Написал заявление на отчисление до распределения. Был направлен на курсантское "дослуживание" контракта в другую часть. Демобилизацию встретил дома за компьютером - углубленно изучая Windows Forms, WPF. Пытался учиться по YouTube видео, но довольно быстро перешёл на текстовые материалы, форумы, metanit.
Открылся бесконтрольный мир материалов для свободного обучения и свободного применения знаний. Помогал друзьям решать университетские практические работы на C++. Для меня он был сильно похож на C#.
Quicktag
Загорелся идеей программы с интеграцией ВК. VK mini-apps рекомендовали официальную систему компонентов ReactJS. Научился применять ReactJS. Погрузился в полный цикл продакшена, Shared Hostings, Heroku, VPS, RegRU, TimeWeb, первые домены, Linux-администрирование, Backend, Frontend, DB. Написал первое собственное приложение с полным циклом - chrome extension виджет + VK mini-app + ASP.NET. Официальная группа приложения насчитывала 30+ подписчиков с активными пользователями. Знакомился с инновационными AI технологиями. Сделал интеграцию Computer Vision API в свое приложение. В целом, оно приносило не очень много денег. Но было неплохим стартом.
Freelance
Начал первые фрилансы на fl.ru. Заработал первые крепкие долгосрочные отношения с клиентами. Большая часть проектов вокруг VK mini-apps. Также были интересные проекты вне основной специализации, например Canvas-игра "Лабиринт". Писал цикл, модель координат, стены, успех, поражение. Боты для VK, Telegram и даже для Minecraft. ВК игра "Тайные желания" на Python и React. C# становился всё меньше применим в условиях оплачиваемых проектов. Чаще встречались ExpressJS, ReactJS. Иногда VanillaJS, Python. Знакомство с CoffeeScript, транспиляцией. На протяжении года применял знания JS, ExpressJS, C#,
PHP
В конце года впервые пришлось познакомиться с PHP 7.4, OSPanel, Nginx. Порекомендовали Laravel. Изучил и написал несколько небольших проектов. Укрепил знания реализовав фриланс-сервис для управления клиентами спортивного клуба. Laravel, VK mini-app, ReactJS, Telegram bot.
Backend Laravel собеседование №1
Полностью провалил его на архитектурных вопросах и глубине software концепций. Собеседующий Лид благородно выписал мне темы, которые необходимо знать.
2020 - Концепции
Погружался в концептуальные материалы: Роберт Мартин, Марк Симан, Мартин Фаулер. Познакомился с Аланом Кеем, отличием его ООП от того, что продвинуло Java. Конкретно по Laravel обнаружил недавно рождённую работу Адиля Фаизрахманова. Глубоко вникал в OOP, SOLID, IoC, Паттерны проектирования, Unit-Тестирование. Увлёкся изучением RFCs, CGI, FCGI. Теоретический концептуальный интерес повышался, консолидировал.
Gamedev
Между теоретическим изучением на протяжении полугода появилось хобби - GameDev на Unity. Особенным интересом для меня были физические симуляции. Реализовал игру - Осьминог, чьи щупальца с компонентом физики перемещали тело по твердым блокам, функционируя через мозг-координатор.
Soundhaunt
Второе полугодие встретил новым личным проектом. Первый действительно большой проект. Фриланс-платформа для звукорежиссёров. Успешно провалил управление сложностью.
Управление сложностью
Начал глубже погружаться в понятие сложности, когнитивности, баланса. Обнаружил работу Фреда Брукса - Мифический человек-месяц. Сущностная, приходящая и необязательная сложность. Укреплял архитектурные принципы на новых проектах в рамках Laravel. Первые интеграционные, функциональные, UI-тесты. Постепенно в моей работе фронтенд полностью вытеснился бесконечным миром бэкенда.
Management
Глубоко интересовался подходами организации работы над проектом. Agile, scrum, распределение задач. Также погружался в навыки работы с Jira, автоматизации, интеграции с Git репозиториями, типы задач, иерархия, статусы.
2021 - CI/CD, Архитектура, Фреймворки
Backend Laravel собеседование №2
Второе собеседование на позицию Backend Laravel. Полностью провалил его на теме контейнеризации, упаковки, доставки и автоматических воркфлоу.
CI/CD
Первые знакомства с VMware, VirtualBox. Сменил рабочую ОС. Полностью переехал с Windows на Linux. Начал погружаться в понятие процесса, дескрипторов, UNIX, контейнеризации, cgroups, Docker, CI/CD, Gitlab Platform. С этих пор начал вечную борьбу с единообразием окружений программы, DX, легкий запуск, дебаг, доставка.
Soundhaunt 2
Возродил фриланс-платформу для звукорежиссёров. На этот раз, сложность была удержана. Слои разложены. Модули поделены. Юзкейсы определены. Транспорт агностирован. Тесты ловят регрессии.
Получил приглашение в компанию на позицию Backend Laravel. Отказался по причине вовлечённости в свой проект.
Фреймворки
Затянуло в углубление Service Provider и более широкий паттерн федеративной загрузки, который за ним стоит. Появился академический интерес к устройству фреймворков, bootstrap, kernel, configuration, container, transport, bootloaders, serialization.
Начались экспериментальные проекты, в рамках которых реализовал собственные фреймворки, с набором фундаментальных необходимых компонентов. Добился высокой интероперабельности. Symfony экосистема, PSR-интерфейсы, вариации контейнеров.
Увлёкся кодогенерацией. Реализовал экспериментальный DI resolver, превращающий граф зависимостей в настоящий PHP-файл, через DSL-описание.
Получил второе приглашение в компанию на позицию Backend Laravel. Отказался по причине вовлечённости в концептуальное устройство фреймворков.
Погрузился в устройство ORM, Active Record, Data Mapper, в магические методы, проксирование вызовов, PDO. Увлёкся чистым SQL без ORM. Формулировал эвристики выбора подходов для разных ситуаций. Немного копнул в SQL Explain. Обнаружил книгу SQL Cookbook.
2022 - Концепции, DIV
Погружался в концептуальные темы. Паттерны ООП. Меткое именование переменных, методов, классов, модулей. Паттерны рефакторинга. Антипаттерны проектирования. Определения доменных границ, ответственностей, гарантий и допущений.
Также изучал проблемы дрифта конфигурации. Вникал в IaC, DaC, GitOps.
DIV
Получил реферальное приглашение на позицию Backend Laravel в компанию DIV. Предложили решить тестовое задание с менеджментом заявок. Реализовал задачу с учётом всех полученных ранее умений. Архитектурные слои, тесты, Docker, API sandbox, readme. Ответил на вопросы по SQL, предназначение интерфейсов, паттерны ООП, HTTP, Rest API. Прошёл собеседование.
В компании проводилась проектная разработка, в которой команды дробились по заказчикам. Проекты были долгосрочные. Очень редко, скоротечные.
Оказалось, что в компании был не только Laravel. Впервые познакомился с Yii 2, Postgres. Попутно начал попытки изучения Golang, его подходов и экосистемы.
Почтовый CRM
Занимался, в основном, правкой контрактов, поддержкой и написанием новых фильтров запросов.
Ресторан Азиатской кухни
Поддержка legacy. Перевод трафика на новый сервис. Впервые руководство обнаружило мои навыки "Развернуть LEMP стек". Стали доверять поддержку в администрировании Линукс серверов.
Интернет магазин одежды
Поддержка legacy. Первый опыт с админ-панелью PHP Orchid. Реализовал модуль "Программа лояльности и скидок".
Государственный портал для голосований
Первый опыт интеграции с ЕСИА. Вход через госуслуги. Взаимодействие с админами ЦИД.
Сервис статистики интернет магазина
Древнейший Legacy. Интеграция с Wildberries API. Формирование Excel для выгрузки объемной таблицы статистики с богатым набором калькуляций. Получил задачу на разработку интеграции Ozon с полным дублированием логики таблицы Wildberries. По ощущениям, одна из сложнейших моих задач этапа DIV. Убедил лида в необходимости двухдневного исследования уже существующей логики перевода её в графический факт. Провёл полный анализ взаимодействия с Wildberries API, какие данные приходят, откуда, куда идут, какие калькуляции от них зависят. Разработал диаграмму FigmaJam, с полными путями и описанием назначения всех данных и функций. Укрепил навыки программной археологии.
Провел этап планирования, получил одобрение и полностью реализовал зеркальную интеграцию с Ozon API.
Сервис дополненной реальности
Получил задачу поддержать фронтенд в проблемах несовместимости 3д моделей между разными мобильными устройствами. Предложил, защитил и реализовал отдельный сервис конвертации 3д моделей - gltf-usdz-glb конвертер. На тот момент не знал термина "Микросервис". Но получилось нечто подобное.
Система страхования грузов
Впервые доверили роль Lead для небольшой команды в рамках эксперимента. Проект включал в себя объёмный CRUD, версионирование ревизий документов и материализацию истории изменений. Написал ядро версионирования и алгоритм Diff для документов. Реализовал уведомления об изменении документа. Использовал Laravel echo. Документы меняются append-only, создается новая версия. Богатая админ-панель на Orchid. На этом проекте применил архитектурный паттерн "Функциональное ядро".
Внутренний сервис realtime статистики компании
Краткосрочный внутренний проект, цель которого на основе предоставленного read-only доступа к БД корпоративного таск-менеджера формировать бизнес-статистику для вывода на TV-экран. Также реализовал сервис уведомлений на основе php-ratchet. Пул websocket подключений, каналы, комнаты и общая логика авторизации.
Интернет магазин "Мастер-ТС" - Внедрение
Конец года. Yii 2. Огромный проект. Бесконечное количество слоёв, логики. Руководство принялось внедрять меня на постоянные долгосрочные работы. Вникал. Подробное описание вклада в 2023 году.
Параллельно с DIV.
Развитие фриланс платформы
Продолжал развитие своей фриланс платформы для звукорежиссёров. Интеграция с ffmpeg и наложение аудио voice-tag. UI-воронка.
Переводчик субтитров
Многопоточная обработка srt файлов. Субтитры переводил через Google Translate API. Одна из первых моих программ на Golang.
Сервис для управления записями клиентов для мелкого бизнеса.
Погрузился в использование golang, grpc, grpc-gateway, postgresql, google-wire, golangci-lint, pgxpool, cobra cli.
Сервис поиска и фасетной фильтрации.
Go, Gin, ElasticSearch, Kafka. Импорт YML-фидов. Yandex Market. Виджет поиска и фильтров.
Прочее
Познакомился с понятием Interface Definition Language или же IDL. Первые исследования о понятии контракта и форме операции. Первые мысли о проблеме тройного налога на API и о проблеме contract drift.
Мысль "Почему мы вообще пишем сваггер?" в 2026 году перетекла в полноценное исследование
Дополнительно обнаружил работы Сергея Теплякова, защитное программирование, сервер-феникс Мартина Фаулера.
Собеседование Golang Backend
Провалил собеседование на этапе High-load System Design. Собеседующий уважительно описал недостаток кругозора в рамках инструментов и подходов решений задач высокой нагрузки. Добавил в список пробелов.
2023 - Долгосрочный проект
Расширение кругозора
Углубление в разные инструменты под разные задачи. Обнаружил highload.today, linux.org. Различные виды баз данных. Реляционные, key-value, временные ряды, колоночные, строковые. Погрузился в Redis, EventStoreDB, Elastic, Clickhouse. Изучение паттернов high-load, паттернов отказоустойчивости. Микросервисы, распределенные транзакции, 2PC, Saga. Дополнительно изучил работу Владимира Хорикова - Принципы юнит тестирования.
Мастер-ТС
Поиск
Штатный поиск не справлялся с объёмом каталога и не учитывал структуру. Внедрил Manticore Search как альтернативный движок, написал экшн для адаптации ответа под текущую вёрстку. Защитил идею вынести его в отдельный микросервис. Сделал исследование по конфигурации Manticore.
Результаты поиска были нерелевантны из-за отсутствия сортировки по приоритетам категорий. Добавил в админку поисковый приоритет категорий, сортировку по наличию и популярности.
SEO и индексация
Товарный sitemap превышал лимиты поисковиков. Разбил sitemap на части, ввёл индексный sitemap, добавил lastmod для карт категорий, производителей и товаров.
Поисковики индексировали неканонические URL и дубли страниц. Настроил robots.txt, canonical, noindex, микроразметку Schema.org, 301-редирект с UPPERCASE на lowercase.
Отсутствовала система управления SEO-контентом для категорий. Реализовал SEO-шаблоны и SEO-ссылки с приоритетом полей и строгим сравнением url.
Корзина V2
Старая корзина была запутанной, логика размазана по контроллерам и видам, внесение изменений требовало остановки. Полностью переписал корзину: модалки доставки, контактов, подтверждение заказа. Вынес логику в отдельный компонент.
Ошибки валидации обрабатывались непрозрачно, пользователи теряли данные. Разработал систему ошибок валидации, согласовав с лидом и командой фронтенда. Сделал валидацию и возврат ошибок через Ajax.
Боязнь сломать оформление заказов тормозила выкатку. Проводили долгое тестирование на тестовом стенде с фиктивным шлюзом оплаты и интеграцией новой корзины. Контракт соблюдён. Выкатили в прод без даунтайма и потери заказов.
Безопасность и стабильность
Авторизация была уязвима к перебору, не хватало логирования. Внедрил ReCaptcha v2/v3, интегрировал SMS оповещение с OTP, добавил логирование попыток входа.
Потребовалось выборочно скрывать товары и бренды в конкретных городах без удаления. Внешняя политика компании. Реализовал блокировку с исключением из поиска, корзины, избранного, сравнения и YML-выгрузок.
Платёжный шлюз падал при атаках и возвращал 429, оплаты терялись. Добавил обработку 429 статуса, выключение возможности онлайн-оплаты по кнопке в админ панели. Добавил задержки проверки статусов эквайринга.
PreloadCaptcha
Боты агрессивно сканировали сайт, вызывая падение сайта. В основном это были ошибки bad gateway из-за невозможности FPM обработать весь шторм подключений. Прорабатывал HTTP-кеширование, делал исследование инструментов и подходов к фильтрации ботов. Использование CloudFlare было невозможным из-за политики. Обнаружил Nginx Bot Filter. Внедрили.
Понадобились какие-то метрики, чтобы ориентироваться на факты, а не домыслы. Внедрил широкую систему логирования и получение метрик - загруз сервера, скользящее окно с подсчетом ботов и реальных пользователей.
Разработал систему фильтрации трафика до загрузки страницы: компонент и виджет PreloadCaptcha с проверками по User-Agent, Referrer, utm-меткам.
После прохождения капчи пользователи теряли исходный URL. Реализовал сохранение оригинального URL и GET-параметров для возврата.
Легитимные пользователи повторно попадали под капчу. Добавил конфигурируемость из админки срока жизни капчи, пороги срабатывания подозрительности и другие параметры.
Краулеры GeedoBot и serpstatbot продолжали атаковать. Вынес в админку возможность блокировать определенных роботов. Ответ robots.txt был динамическим рендером шаблона, а не статическим файлом.
В админку вынес возможность блокировать диапазоны IP адресов.
Инцидент
Однажды заблокировали всю южную магистраль. Что потребовало внедрения системы BlameBehaviour.Инциденты с падением от ботов прекратились.
Интеграции и парсеры
Обмен с 1С требовал ручного вмешательства при появлении новых сущностей. Выпросил время на рефакторинг и обобщение лишней сложности в ядро парсинга 1С XML файлов. Реализовал гибкий пайплайн, который можно было внедрить рядом со старой логикой. Реализовал парсер преимуществ с изображениями, парсер тегов с минус-файлом, парсер статистики менеджеров.
Выгрузки для Яндекс.Маркета и Директа не учитывали региональные ограничения. Сделал YML-выгрузки с исключением товаров по городам и брендам.
Администраторам не хватало возможности выборочно запускать обмен. Настроил кастомизируемый ручной обмен 1С в админке, с постановкой очередей задач, статусами и отменами.
Мастер-ТС V5
Клиент с руководством приняли решение переписать проект с нуля на современном стеке. Laravel. Разработка велась параллельно поддержке. Меня всё чаще начали привлекать к новой версии проекта.
Мысли об этом
Для меня эта идея казалась сомнительной, однако у меня было недостаточно аргументов и авторитета для влияния на решение. Я понимал, что любой проект может требовать распила и рефакторинга. Любой проект способен превратиться в легаси. Я не знаю почему именно V5. PHP 6 effect. Подозреваю, что полностью переписывают Мастер-ТС не в первый раз.
Архитектура и проектирование с нуля
Спроектировал и реализовал огромную часть бэкенд маркетплейса с нуля: от аутентификации и каталога до сложных фильтров и интеграций. Выстроил многослойную архитектуру (domain, use cases, queries, repositories) с чистым разделением ответственности. Внедрил агностичный транспорт: одни и те же юзкейсы работали через REST API и GraphQL без изменений. Спроектировал систему подготовленных данных (Prepared Catalog) для кардинального ускорения выборок: цены, остатки, доставка, характеристики - всё считалось заранее и обновлялось по расписанию.
Сложные технические решения
Реализовал фасетную фильтрацию с произвольным набором чекбоксов и диапазонов, включая динамический пересчёт количества товаров для каждого фильтра. Для ускорения фильтрации применил Redis Bitmaps: каждый фильтр хранился как битовая карта товаров, пересечения вычислялись через BITOP. Это позволило обрабатывать сложные запросы за миллисекунды. Разработал алгоритм пост-обработки диапазонов цен и характеристик (RangesLegacyPostProcessor). Алгоритм был почти полностью перенесён в новую версию. К нему были применены рефакторинг и багфиксы, включая деление на ноль и другие edge-кейсы, найденные в бою. Впервые он получил свои тесты, по крайней мере в новом проекте. Внедрил кастомный GIN-индекс на Redis Bitmaps для поиска товаров по множеству признаков - решение, принятое после анализа последствий внедрения этой логики в основную БД. Согласовав с руководством успешно вынес фасетную фильтрацию в независимый Go-сервис с отдельной поддержкой и жизненным циклом.
Работа с данными и интеграции
Написал всю систему импорта из 1С: категории, товары, цены, производители, маркеры, остатки, бонусы, файлы, характеристики. Реализовал пачки (batches) с пропуском ошибок и записью в минус-файл. Сделал синхронизацию изображений и файлов с обработкой дубликатов и привязкой через morph-отношения. Реализовал логику цен: гостевые, обычные, корпоративные - с посчитанными значениями прямо в подготовленных товарах. Спроектировал логику динамической цены, зависящей от конкретной репутации пользователя. Интегрировал бонусную систему и шлюз для синхронизации с внешним сервисом.
Производительность и оптимизация
Кардинально ускорил загрузку страниц каталога за счёт: подготовленных данных, кеширования (Redis), жадной загрузка только нужных связей, оптимизации запросов. Решил проблему обнуления количества у фильтров при исключении самих себя, переработав логику пересечения битмапов. Добавил постоянную структуру фильтров (skeleton) для избежания дорогих запросов при каждом HTTP-запросе. Оптимизировал генерацию XML-фидов для Яндекс-Маркета через потоковую запись с разделением на страницы (XmlPaginatedExporter). Для импорта 1С XML-файлов придумал оптимальный баланс DX и эффективности. Файлы читались потоковым XMLReader, однако конкретные сущности грузились в память через SimpleXML и передавались в декларативный пайплайн.
Качество кода, тестирование и CI/CD
С нуля настроил CI/CD пайплайны: автопрогон тестов, линтеры (phpcs, php-cs-fixer, Larastan), проверка миграций. Поднял уровень Larastan с 1 до 5, попутно исправляя ошибки типизации в проекте. Написал десятки feature-тестов для ключевых юзкейсов: аутентификация, каталог, фильтры, импорт. Написал не меньше модульных тестов для чистых алгоритмов, которые пришлось осознавать и выносить. Восстановил потерянное тестовое покрытие. Защитил и внедрил строгие практики код-ревью: обязательные глоссарии, ADR, Structural Review, запрет размытых имён (Service, Manager).
Observability
Начал погружаться в наблюдаемость. Внедрил Laravel Pulse и SPX для профилирования запросов, GoAccess для анализа логов, Telescope для отладки. Перенастроил логирование: структурированные логи с requestId, телеграм-каналы для алертов. Включил строгий режим Eloquent (Model::shouldBeStrict) для автоматического обнаружения N+1 и ленивой загрузки на проде. Заложил фундамент мониторинга и прозрачности, который позволил команде быстро находить узкие места и сократить MTTR.
Параллельно с DIV
Погружался в Observability, Grafana, Dashboards as Code, метрики, условия алертов, процентили. Разрабатывал эвристическую систему ошибок на основе Google API Improvement Proposals (AIP).
2024 - Team Lead, Tech Lead
Мастер-ТС - Новая роль - Team Lead
Команда выросла. Со временем мне доверили роль Team Lead проекта: координировал бэкенд-разработку, распределял задачи, проводил ревью кода. Сформировал стандарты и практики, которые затем начали перенимать другие команды компании.
В проекте удалось добиться определённой культуры разработки и внутренней архитектуры.
Выстроил строгое разделение кода на уровни с чёткими контрактами. Публичный интерфейс приложения состоял из UseCases, разделённых на Команды (write) и Запросы (read). Каждый UseCase имел единый метод handle и возвращал только OperationResult, не зависящий от транспорта. Это позволило вызывать одну и ту же бизнес-логику из HTTP, консоли, очередей и вебсокетов без изменений. В дальнейшем этот подход превратился в невероятный DX с использованием Dedoc Scramble + Laravel Data. Внутренняя реализация опиралась на атомарные Domain Actions, которые могли переиспользоваться разными Командами, но не покидали границ своего домена. Действия, претендовавшие на выход за границы домена, явно указывали на необходимость пересмотра бизнес-логики.
Чтение данных было инкапсулировано в три типа Репозиториев. Eloquent-репозитории возвращали модели и коллекции. Pure-репозитории - сырые структуры и value objects для оптимизированных запросов. Query-репозитории - построители запросов с преднастроенными scope и фильтрами. По имени класса можно было однозначно определить тип возвращаемого результата.
Проект намеренно избегал проникновения HTTP-семантики в бизнес-логику. От стандартных Laravel Resources отказались: логика преобразования данных переехала в метод transform() внутри самих Query. Разработчик, открывая Query, видел и сам запрос, и финальную форму ответа без необходимости перемещаться по цепочке контроллер-ресурс-модель. Более того, это избавило от проблем каскадности ресурсов. Эгоистичные usecase-bounded-outputs заставляли чётко понимать, что именно отдаёт операция. Тоже самое касается и input.
Стандартизировал Git-процесс. Ввёл conventional commits с обязательным scope по номеру задачи. Breaking changes помечались восклицательным знаком в заголовке. Заголовок коммита отражал название задачи или проблемы. Тело коммита фиксировало выполненные микро-задачи, а подвал - предостережения, обещания и факты о нарушениях обратной совместимости. Обязательные Pull Request'ы на любого коллегу обеспечивали коллективную ответственность и обобщение знания проекта. Ветки именовались по шаблону <тип><номер-задачи><описание>. Исключены личные местоимения и гендерные маркеры в коммитах. "Добавил валидацию" заменилось на "Добавлена валидация" для смещения фокуса на сам факт изменения системы.
Сложные алгоритмы и util-методы документировались в формате "Вошло -> Вышло" с обязательным примером входных и выходных данных. Похоже на Go-examples. Это одновременно служило и документацией, и неявным контрактом для тестов.
Архитектурные слои были подвержены линтингу с помощью PestArch и PHPAT.
Среда, построенная на этих правилах, исключала возможность случайного нарушения архитектуры. Ограничения были не в виде устных договорённостей, а встроены в структуру кода и процесса, разработчик физически не мог написать "неправильно".
Обеспечил быстрый и единообразный вход в проект. Одна команда task up поднимала все Docker-контейнеры с преднастроенным Xdebug для локальной отладки, автоматически запускала сидеры баз данных и генерировала необходимые IDE-helper файлы. Команда task lint выполняла полную локальную проверку проекта с последующим автоформатированием по конфигурации php-cs-fixer. Pre-push хук запускал проверку локально, предотвращая лишние циклы CI-сервера и ускоряя обратную связь.
Успешно запустили новую версию проекта на Laravel. Всё заработало. Продажи, интеграции с 1С, наблюдаемость. Проект переходил к этапу поддержки.
Я собеседующий
Впервые доверили ради эксперимента провести 3 собеседования кандидата на роль Backend Laravel. Успешно провёл и подобрал исполнителя. Программист отлично вписался и работает вплоть до 2026 года, в котором составлено это CV.
Tech Lead
Руководство предложило должность, в обязанности которой входили:
- Исследования и внедрение подходов, инструментария, концепций, стандартов
- Составление внутреннего роадмапа и системы грейдов
- Укрепление общего инженерного уровня команд, менторство программистов и технический онбординг новичков
- Аудит архитектуры и точечные ревью
- Помощь менеджменту в декомпозиции требований клиента
- Технический разбор пресейлов
- Общие временные оценки, пессимистичные и оптимистичные
- Снятие с разработки фич, в угоду поддержки тех, кто разрабатывает фичи
- При возникновении трудностей самостоятельно погружаться в конкретную задачу
- Еженедельные выступления и презентации на руководительских встречах
- Подчинение руководителю и техническому директору, напрямую
PHP code-style компании
Продвинул необходимость договориться о формате кода PHP. Для этого у меня уже были наработки с проекта Мастер-ТС. Однако недостаточно было просто сказать "Теперь делаем так". Сделал обширное исследование линтинга и форматирования в экосистеме PHP. Исследовал каждую возможную настройку php-cs-fixer. Объяснил предназначение каждого параметра, показал примеры и предложил значение с аргументацией. Всех устроило. Начали внедрять стандартный php-cs-fixer ruleset компании.
Тестовое покрытие
Провёл анализ типичных проблем на проектах. Баги, регрессии, слепота. Продвинул необходимость исследовать тестовое покрытие проектов, особенно старых. Продумал постепенное встраивание тестов. Для Yii-2 проектов - Codeception Для Laravel - Pest. Надстройка над PHPUnit c крепкой экосистемой и видами тестирования. С менеджментом и руководством обсудил необходимость обязательного выделения определенного процента времени на фиксацию техдолга, рефакторинг, увеличение покрытия. Аргументировал стратегическую пользу. Лично контролировал внедрение через периодический запланированный анализ.
Docker
Добился продвижения культуры контейнеризации и единообразия окружения благодаря Docker. Разрабатывал конфигурацию с Non-Root, XDebug, Auto-Start. Прорабатывал план обучения для ребят, малознакомых с докер, показывая им плюсы того, чтобы внедрить единообразный подъём окружения для разработки. Оно не ускоряло пайплайны деплоя. Но оно повышало DX, особенно в срезе компании со множеством проектов. Task up - единообразный способ поднять окружение любого проекта. Независимо от конкретного фреймворка или стека. Из зависимостей dev хоста только сам Docker и Taskfile. Впоследствии эти практики целиком переехали в эталонный шаблонный репозиторий компании.
Dedoc-Scramble PRO
Сделал исследование на тему дрифта документации и проблемы тройного налога на API. Защитил предложение покупки Dedoc-Scramble PRO. Это позволило делегировать огромную часть подверженного ошибкам бойлерплейта на автоматический инферинг API хендлеров.
Юзкейсы
Продвинул необходимость внедрения UseCase архитектуры, отделения слоя логики от транспорта. Аргументировал архитектурно, а также добавил крепкие аргументы о пользе такого подхода:
- Уменьшение размазывания публичной логики программы
- Применение эгоистичных Input и Output классов для юзкейсов позволило локализовать логику каждой операции
- Уменьшение когнитивной нагрузки на разработчика, благодаря строгому project layout
- Интеграция Laravel-Data и Dedoc-Scramble PRO позволили инкапсулировать инвариант входа и выхода юзкейса, а также добиться полной автоматической API документации
Шаблонный репозиторий
Продвинул предложение создать эталонный репозиторий с набором практик, и решением повторяющихся проблем. При необходимости, репозиторий с Laravel может быть развернут для абсолютно любого нового проекта. В старые проекты, можно легко переносить необходимые конфигурации, пайплайны, архитектурные концепции, докерфайлы и компоузы.
В дальнейшем он превратился в автоматизированную платформу разработки. Это позволило раз и навсегда решить множество хронических проблем. Продолжительно развивал его, а со временем, команды сами начали продвигать улучшения в нём.
Обеспечил быстрый и единообразный вход в любой новый или старый проект. Одна команда task up разворачивала полное Docker-окружение: PHP-FPM, Caddy, MySQL, Redis, Mailpit, Prometheus, Grafana. Все сервисы были преднастроены, включая Xdebug для локальной отладки, не требуя от разработчика ручных манипуляций.
Автоматизировал рутину, исключив человеческий фактор. При запуске контейнера автоматически выполнялись composer install, миграции, генерация ide-helper, типовые dev onboarding операции. Pre-push Git-хук блокировал отправку кода, не прошедшего полный цикл проверок: линтинг, статический анализ, архитектурные тесты, аудит пакетов. Снапшоты базы данных создавались автоматически каждую ночь с настройкой ротации, конфигурируется. Минимизирует ситуации отсутствия снапшотов на новых проектах, в целом. Генерация документации API (Scramble) и моделей (ide-helper) происходила централизованно, без необходимости помнить команды.
Стандартизировал и закрепил в коде ключевые инженерные практики. Внедрил единый строгий php-cs-fixer и PHPStan (level 5) как обязательный стандарт качества для всей компании. Настроил архитектурные тесты на базе Pest и PHPat, которые в автоматическом режиме проверяли соблюдение DDD-структуры и контрактов: наличие strict_types, запрет абстрактных классов, единственный публичный метод handle у UseCases, отсутствие sleep/usleep и другие правила. Декларативно описал доменную структуру и допустимые зависимости между слоями, предотвратив архитектурную деградацию кода.
Решил проблемы, о которые спотыкались все проекты. Избавился от MassAssignmentException - глобально отключил защиту (Model::unguard). Модели не занимаются валидацией себя, уходим от типичного Yii-2 Active Record с умными моделями. Включил строгий режим Eloquent (Model::shouldBeStrict) для автоматического обнаружения N+1 и ленивой загрузки, предотвращая тихие деградации производительности. Дополнительно это решает проблему silent attribute discard. Решил проблему прав доступа в Docker - UID/GID пользователя в контейнере автоматически синхронизировался с хостом, исключив конфликты с файлами. Настроил автоматическое определение HTTPS-схемы за reverse-прокси (Caddy), убрав баги с кривыми URL. Внедрил Laravel Data (DTO) как единый стандарт для Input/Output объектов, автоматически обеспечивая валидацию и исключая расхождения.
В итоге шаблонный репозиторий стал действующим стандартом компании. Он сократил время развёртывания новых проектов с дней до минут, унифицировал практики десятков разработчиков и гарантировал, что каждый проект начинается с высокого уровня качества, без необходимости помнить и обсуждать базовые настройки. Для девопс инженеров, в нём была документация. Описание четких границ ответственности проекта, необходимость реверс прокси на продакшене, типовой запуск проекта. При этом сам репозиторий никак не мешал практикам девопс - host, docker-compose, k8s. Проект не диктовал условий, но был экстремально полезен в рамках DX.
HomePage
Выдвинул и прорабатывал концепцию единого корпоративного портала (HomePage), который должен был объединить разрозненные сервисы и инструменты компании в одну платформу с унифицированным доступом, общей навигацией, сквозными CI/CD пайплайнами, RAG-ассистентом, справочниками и оркестрацией процессов. Инициатива была нацелена на повышение связности инженерной инфраструктуры и улучшение Developer Experience для всех команд. Не успел реализовать, но мечтаю однажды получить возможность.
Observability
Пропагандировал, а впоследствии внедрил базовые метрики во все проекты и в шаблонный репозиторий. Девопс команда подхватила. Централизовали Grafana дашборды и прометеус. Каждый проект обязался выдавать стандартный набор /metrics. Также начали повсеместно внедрять node, db, redis экспортеры. На тот момент, я ещё не был знаком с OpenTelemetry.
Ревью и менторство
Непрерывно занимался поддержкой программистов, организацией ревью и продвижением накопленных лучших практик. В том числе продвигал необходимость проведения cross-review. Шаблонные CI/CD и преднастроенный воркспейс Bitbucket репозиториев создавали строгие флоу интеграций кода. Обязательные аппрувы от коллег и автоматические проверки качества кода. Многие наработанные эвристики впоследствии были зафиксированы в архитектурных тестах эталонного репозитория.
Поддержка менеджмента
Вовлечение в процесс взаимодействия менеджмента и команд разработки. У всех была возможность призвать меня в текстовое обсуждение задачи. Вникал. Подключался. Организовывали встречи и решали нетривиальные проблемы.
Поддержка DevOps
На постоянной основе выступал скорой помощью в ситуациях неопределенности или высокой сложности в рамках серверных задач:
- Инфраструктура, развертывание, поддержка
- Linux, Docker, базы данных, взаимодействие сервисов
- Реакции на инциденты, формулирование плана решения, оценка рисков, составление техдолга
Presale
Глубоко был вовлечён в процесс Presale. Прорабатывал клиентские желания на техническом уровне, подсказывал, предостерегал и направлял менеджмент.
В рамках этого процесса провёл множество исследований на темы клиентских идей, среди которых были довольно интересные:
- NLP. Перевод натурального языка в программные сущности. Парсинг новостных происшествий, сбор мест и цветового настроения новостей. Named Entity Recognition (NER)
- Медиа-стриминг высокого разрешения. Механизмы, необходимые для реализации платформы вертикальных видео. Пайплайны транскодирования, генерации превью и протоколы адаптивного стриминга (HLS/DASH) для мгновенной потоковой выдачи контента на мобильных устройствах
- Корпоративная система централизации знаний с возможность автоматизации организационных процессов с помощью AI инструментов + RAG
Помогал оценивать риски и приоритеты.
Проводил анализ и агитировал отказы от проектов, которые были слишком сложными или рискованными.
Legacy Presale
Периодически в Presale приходили предложения о доработках чужой кодовой базы.
Вспоминая 2022 год, когда я пришёл в компанию, у нас был набор проектов доставшихся по наследству. По существу, самые проблемные проекты. В прошлом лично участвовал в поддержке унаследованного кода. Теперь осознал необходимость формализовать получаемые риски и переработки.
Провёл анализ. Чужой стек, архитектура, подходы. Чужой техдолг. Инфраструктура. Зафиксировал аргументы. Получил поддержку руководства на отказы начала работ над чужими проектами.
Гигантский presale, от соответствующей компании гиганта (NDA)
Документы функциональных и нефункциональных требований включали в себя сотни переплетенных страниц реифицированных процессов. Широкие требования от строгого использования ПО зарегистрированного в гос-реестре до градуса наклона обдува серверных стендов. Предложил исследование на тему реализуемости за описанные сроки, вывел риски. Аргументы донёс до техдира и получил полное согласие на отказ.
Музей Победы
Сентябрь. Начинают периодически привлекать на пресейлы некого стратегического проекта. Музей Победы. Идея полностью сформулировалась только позднее. В декабре фулл-тайм погружаюсь в разбор идей менеджмента и клиента. Оригинальная идея проекта была невероятно слабо структурирована для понимания.
Защищаю необходимость выделения двух недель на обширные архитектурные подготовительные работы. Занимаюсь структурированием приходящих желаний. Активно кооперируясь с лидом фронтенда и менеджментом, составляем множество полезных артефактов, диаграмм и других визуализаций. Архитектура, карта смыслов, глоссарий, домены, ответственности, план работ, зависимости, оценка сложностей, оценка рисков.
Работа дала ожидаемые плоды. В конечном сформулированном виде идея заключалась в следующем. Тематика - Великая Отечественная Война. Московский Музей Победы - место, в которое дети и взрослые приходят, как сами, так и в составе групп учебных заведений для коллективного просвещения об истории и героях войны. Нам же было предложено разработать богатый набор связанных интерактивных приложений, запускавшихся на физических устройствах внутри музейного комплекса.
Было множество идей, которые были отсечены постепенно.
В конечном счёте проект включал в себя:
- Фронтенд приложения
- Панель управления презентацией таймлайна войны
- Презентор таймлайна войны с realtime реакциями на команды панели управления
- Энциклопедия. Богатейшая вики с контентом для посетителей, ссылками, связями, поиском
- Монофоны. 2 сервиса, богатый и упрощенный. Интерактивный рассказчик-презентация со звуковым погружением и наушниками
- Сервис аутентификации для Музея
- Ко всему этому бекенды:
- Ядро управления контентом. Админка. Инструменты для модераторов. CRUD сервисы. Герои, Награды, Сражения, События, Письма, Музыка, Вооружение, Наука, Фильмы, Газеты, Запросы, Области Победы, Библиотеки, Росархив, Электронные выставки и общие фильтры
- Интеграции с РосАрхивом
- Hub. Шлюз взаимодействия устройств
- Панель управления устройствами, настройка, выдача прав, реестр, включения, отключения, статусы
- Ядро таймлайна. Богатая конфигурация, иерархия, интеграция с контентным ядром
- Ядро поиска. Кросс-доменный полнотекстовый поиск сущностей
- Ядро синхронизации данных между гос-объектом и публичным сервисом контент-менеджмента
2025 - Музей Победы, RAG, Уход в Self-Fund
Музей Победы
Подготовил презентацию технических решений. Запланировали встречу с менеджментом, руководителями менеджмента, бекенда, фронтенда и моим личным руководителем. Провёл часовую презентацию, защитил. В этот же день одобрили начало работы.
Подготовка
С лидом фронтенда приняли решение организовать монорепозиторий для проекта. Аргументировали общим CI/CD, тулчейном, окружением, скоростью интеграций, централизации правил и культуры. Проект представлял собой многоуровневый layout.
На верхнем уровне располагались:
- Глобальные .env
- Docker-compose конфигурации сервисов на основе include
- Taskfile
- CI/CD пайплайны
- Документация и инструкции развертывания
Слой services/ содержал все необходимые для проекта сервисы. Каждый мог быть написан на своём стеке.
Бекенд: Laravel + множество инфраструктурных сервисов.
Фронтенд: NextJS + Lerna/NX.
Каждый сервис со своими Dockerfile, .env.
Карта сервисов выглядела примерно так:
| Имя контейнера | Назначение |
|---|---|
| backend_app | Laravel + FPM |
| backend_db | Основная СУБД |
| backend_horizon | Сервис обработки очередей и фоновых задач |
| backend_hub | Сервис распределения и управления WebSocket подключениями |
| backend_manticore | Поисковая СУБД для полнотекстового поиска и механизма автоссылок |
| backend_redis | Key-Value хранилище для кэшa и состояний очередей |
| backend_scheduler | Планировщик задач |
| backend_adminer | Веб-интерфейс для управления СУБД |
| backend_sshd | SSH демон для удаленного доступа, синхронизации файлов и БД через Rsync |
| frontend_control | Next.js приложение - Контроллер |
| frontend_encyclopedia | Next.js приложение - Энциклопедия |
| frontend_monophone | Next.js приложение - Монофоны 1 |
| frontend_monophonesimple | Next.js приложение - Монофоны 2 |
| frontend_present | Next.js приложение - Презентор |
| caddy | Публичный шлюз приложения, реверс-прокси |
| docker | Веб-интерфейс для мониторинга состояния контейнеров и просмотра логов |
Для разработчиков был настроен DX в виде task up команды, которая разворачивала полное окружение разработки с помощью многофайлового docker-compose. Caddy docker proxy позволял автоматизировать локальный DNS для сервисов. Каждый сервис был доступен через someservice.museum.localhost. Автозапуск фикстур и культура их поддержки позволяли избегать проблем неоднородности состояния у разработчиков. Локальная среда имела git-ignored local.ini.example, который копировался и включал XDEBUG и дополнительные dev настройки.
Проект включал в себя:
- настроенную админ-панель Filament
- examples директории для сервисов, слоёв внутри сервисов, примеры юзкейсов, инпутов, аутпутов, настройки транспорта.
- laravel reverb, с примерами взаимодействия устройств и их авторизации
- инструкции по развертыванию и локальной работе платформы
- пайплайны CI/CD, lefthook git хуки
- десяток тестов, юнит, функциональных
- Taskfile с основными inner-loop командами. up, down, fmt, lint, test, gen, encrypt, decrypt
- production-ready docker-compose с прописанными depends_on, health checks
- настроенный Caddy шлюз с прописанными zstd, gzip, php_fastcgi, file_server, настройками для robots.txt и CORS
Постепенно, принялись приглашать программистов одного за другим. Проводили онбординг, задавали домен и цели работ.
CI/CD
Настроил непрерывную доставку. ПР инициировал множество проверок, линтеров и тестов. Образы строились во время инициации ПР. Имели имена image-name:version. Теги раздавались напрямую и автоматически из номеров Jira карточек. Каждая версия уникальна и отражает суть изменений напрямую. Мерж не запускал деплой. Для деплоя настроил ручные действия в BitBucket. Оператор мог накатить и откатить версию приложения, оперируя номером тега и целевым окружением.
Окружения
Проект имел множество целевых окружений:
- local - Полностью готовая среда разработки с высоким DX
- dev - Стенд для inner-loop
- test - Среда с большим количеством фикстур для сквозных тестовых сценариев
- pre-stage - Среда предпросмотра с экспериментальными нововведениями
- stage - Клиент, менеджмент, боевые данные
- production-content - Среда для контент-менеджмента, доступна в публичной сети с аутентификацией.
- production-museum - Локальная среда объекта Музея
Секреты
Для централизации подхода GitOps в рамках проекта была разработана небольшая система пайплайна. Использовался dotenvx с шифрованием секретов. Приватные ключи сервисов надёжно хранились отдельно самих сервисов. Сервисы получали значения извне через ENV. По 12 факторам приложения. Сервера не содержали открытых секретных значений в файлах.
JIRA
Изначально пресейл проекта разрабатывался в таск-менеджере компании. Teletask.
Для проекта такого масштаба, требовался проверенный временем инструментарий. Иерархия. Связи. Per-task conversation с медиа attachments. Многоуровневая, централизованная документация. Руководство изначально сопротивлялось переходу к внешней платформе ведения проекта. Действительно, риск существовал. Большая часть программистов и менеджеров компании привыкли к Teletask. Проработал аргументацию того, что его функционал не поможет нам спроектировать надёжный цикл разработки. Вопреки, а не благодаря. Лично показал, что именно нам даст Jira и обязался взять на себя полный онбординг по работе в ней.
Перенос процесса работы в Jira - последний этап перед началом активной разработки. Формулировал стратегии работ в виде эпиков, расписывал юзер сторис, крепил к ним иерархию технических задач. Активно взаимодействовал с главным менеджером проекта. Прорабатывал Jira автоматизации, связи, смены статусов, авторов и исполнителей, интеграции с BitBucket, создания ретроспективных документов. Развивал структуру тегов, внедрял AC и DOD концепции в задачи. Впоследствии, основной объём работ в рамках Jira успешно закрывались менеджментом. Моё участие было только на уровне технических подзадач. На постоянной основе участвовал в декомпозиции и обсуждении клиентских user story. Погружение в JIRA периода 2020 года пригодилось. Впоследствии, флоу работ прижился на музейном проекте.
Начало разработки
Продумав срез работы в Jira, с менеджментом и лидом фронтенда, принялись привлекать программистов по одному. Фронтенд активно взаимодействовал с дизайном. Бекенд - с девопс.
Роль
- Вместе с менеджментом занимался декомпозицией задач в Jira и формированием спринтов
- Выступал в роли технического эксперта и архитектора на встречах с менеджментом, программистами, очень редко с клиентом и внешними техническими экспертами
- Проводил разбор приходящих требований. Приоритизация, анализ возможности, предложения решений с наименьшими временными потерями
- Формулировал статусы продвижения работ, предсказания, риски
- Проводил техническое менторство и онбординг программистов. Глубоко вникал в проблемы, помогал с архитектурой, реагировал на инциденты
- DX. Выступал средним элементом между менеджментом и разработкой. Каждой стороне приносил максимальную направленную пользу. Старался минимизировать стресс в командах разработки
- Доставка. Выступал экспертом по развёртыванию и лично занимался docker-контейнеризацией и CI/CD
- Production. Выступал экспертом по решению проблемных нюансов гос-объекта. Занимался модулем синхронизации данных между платформами.
- Hands-on. В редкие моменты свободы от ролевых обязанностей поддерживал команду бекенда, решая задачи в спринтах
Горящий дедлайн
Сроки давили. Все команды работали в овертайм. Компания благородно оплачивала сверхурочные. Но работать приходилось с раннего утра до поздней ночи и на выходных. К работе привлекались дополнительные специалисты. Росла потребность в декомпозиции и параллелизации.
В определенный момент, у меня появилось очень много долга по принятию решений в рамках инфраструктуры, развертывания и синхронизации данных. Встречи с менеджментом и с программистами, декомпозиция, ревью забирали 99 процентов времени.
Мой личный руководитель подключился к проекту и забрал операционную нагрузку. Чему я был очень благодарен.
Понимание важности DX барьера
Когда я переключился на инфраструктуру, роль живого буфера между менеджментом и разработкой временно отошла на второй план.
Достаточно было одного вечера, чтобы почувствовать последствия.
Менеджер написал мне глубокой ночью - растерянный, эмоциональный, с запросом "посмотри, что происходит". Я посмотрел. Ситуация была рабочая, но тон обсуждения задачи с разработчиком перешёл границы.
Вмешался и аргументировал в личном чате: Управление через давление и эмоции не работает. Если есть проблема - формулировка в задаче, аргументация, факты. Ни кнут, ни пряник. Уважение. Качество выполнения это метрика, которая должна анализироваться асинхронно, на основе сбора статистики. Качество постановки задачи это тоже метрика. В работе нужен баланс хитрости и честности.
Инцидент стал лучшей демонстрацией того, зачем нужен DX-барьер между менеджментом и разработкой. Когда он есть - его не замечают. Когда исчезает - начинается производственный ад.
Инфраструктурный долг был связан со следующей главой.
Обещания
Примерно в середине разработки потребовалась встреча с клиентом и внешними техническими специалистами. Тема встречи - настройка среды эксплуатации и развертывание в рамках Музея. С нашей стороны техническим экспертом выступал я. Провёл переговоры с внешними DevOps. Договорились о требованиях к среде.
- OS: Ubuntu Server 24.04
- Необходимые открытые порты: 80, 443, 522, 2019, 49153-49162
- Доступ в интернет и организация VPN для подключения платформы модерации: Требуется для обновлений и синхронизаций данных
- SSH: Нужно для реакции на инциденты, настройки среды, пайплайнов, синхронизаций
- Локальный DNS: Человекочитаемые имена и резолв хостов вместо обильной резервации портов
При выполнении этих условий я гарантировал настройку среды самостоятельно. Докер, CD пайплайны и всё, что было необходимо для проекта.
Спустя 4 месяца, наступил момент необходимости первого развертывания на объекте. Запросил SSH доступы и VPN. Получил отказ.
Прочитав ответ пришёл к тому, что 4 месяца подготовки автоматизации, Docker-контейнеров и CD-пайплайнов рискуют превратиться в тыкву. Огромный риск, что вместо автоматического деплоя одной кнопкой или событием наступит классическая "партизанская" настройка: ручной перенос сборок, развертывание вслепую и бесконечные созвоны с местными сисадминами.
SSH невозможен. IP-адрес был серым. Сервер Музея получил рядовой внутренний адрес локальной сети, полностью изолированный от внешнего интернета. На него нельзя было постучаться извне по SSH, к нему невозможно было поднять VPN, а открытые порты 80 и 443 существовали только внутри музейного контура. Мне предоставили AnyDesc доступы к нескольким целевым устройствам объекта.
Подключившись по AnyDesc, я увидел рабочий стол Windows 10.
Локальный DNS был запрещён.
Порты закрыты.
Это был жесткий урок: никогда не верить техническим гарантиям внешней команды на слово, пока лично не проверишь пинг до целевого сервера.
Эскалация проблемы ни к чему не привела. Времени на разбор полётов не было.
Решение
Вместо бесконечных и бесполезных разбирательств с организаторами выставки, пошел по пути наименьшего сопротивления, задействовав смекалку. Раз СБ заперла меня внутри Windows 10, я развернул там WSL (Windows Subsystem for Linux). Внутри него поднял наш монорепозиторий, вручную пересобрал переменные окружения, подобрал свободные порты, авторизовался в Docker Registry и написал .sh скрипты автоматизации. Первые смоук-тесты подтвердили: локально всё разворачивается и обновляется.
Но оставалась главная проблема - безопасная, надежная и контролируемая синхронизация тяжелого медиа-контента с нашей платформой управления. Спроектировал push-модель на базе rsync через SSH. Прямо в монорепозиторий добавил изолированный SSH-сервис. Безопасность довел до абсолюта: в рамках CI/CD-пайплайна для каждого релизного тега генерировался уникальный временный ключ (per-version key). Таким образом, связаться друг с другом могли только строго одинаковые версии сервисов. Никакой внешний клиент или злоумышленник физически не мог вклиниться в этот канал. На бэкенде платформы контент-менеджмента я с нуля разработал админ-панель для полного визуального контроля данных. Каждая версия контента теперь валидировалась по хешу и метке updated_at, а в интерфейс я вывел кнопки паузы и отката. Для наката структуры БД я внедрил систему миграций прямо из UI. Теперь инициировать полное обновление базы данных можно было в один клик прямо с физического объекта в Музее.
Последней баррикадой оставался пресловутый серый IP. Чтобы пробить изоляцию, требовалось долгосрочное соединение, инициированное изнутри самого Музея. Погрузился в исследование SSH-туннелей. Протестировав три разных архитектурных подхода, выбрал вариант с наилучшим DX: На внешнем сервере контент-менеджмента поднимался стабильный tunnel-server. Изнутри изолированного контура Музея запускался tunnel-client. Клиент сам пробивал дорогу наружу и устанавливал прочную связь. Как только долгосрочное соединение успешно фиксировалось, мы могли беспрепятственно запускать любые сценарии синхронизации и апдейтов. А сразу после окончания работ туннель автоматически и бесследно уничтожался. К сожалению внешняя команда DevOps полностью провалила свои обязательства по неизвестным мне причинам.
Благодаря reverse-туннелю, WSL и UI-миграциям проект Музея был успешно запущен и работал как часы, став одной из самых красивых инженерных побед в моей практике.
Финал
Проект Музей Победы для меня кульминацией этапа DIV. Успешно сдан в срок. Положительный эффект - гордость за проделанную работу. Негативный эффект - команды сгорели морально. Программистов и меня, в том числе, перераспределили на щадящие работы. Многие ушли в отпуск.
Я продолжил заниматься основными обязанностями тех-лида.
RAG-платформа (Корпоративный AI-ассистент)
Через некоторое время после завершения музейного проекта директор компании Филипп и руководитель менеджмента Антон, предложили мне интересную не-техлидскую задачу. Появился крупный клиент с интересом к внедрению искусственного интеллекта в свои внутренние процессы. Нам поручили разработать прототип корпоративной поисково-экспертной системы на базе RAG (Retrieval-Augmented Generation). Поскольку глубокого опыта работы с ИИ в команде на тот момент ни у кого не было, взял на себя роль исследователя и архитектора решения. За несколько месяцев я полностью погрузился в предметную область, изучил математику векторных расстояния, подходы к чанкингу данных, эмбеддингам и методы достижения детерминированного JSON-ответа от языковых моделей. Для тестирования компания закупила выделенный сервер с мощной графической картой (класса A4000/A100). На нем я развернул и протестировал инфраструктуру инференса: сначала через Ollama, а затем оптимизировал стек, перейдя на более производительный vLLM.
Находка
В процессе проектирования я наткнулся на готовые enterprise-решения автоматизации ИИ-агентов и пайплайнов на базе платформы n8n, а также на мощные ИИ-сервисы от MTS Web Services (MWS). У меня появилось четкое подозрение, что мы со своей кастомной разработкой идём куда-то не туда, пытаясь изобрести велосипед в гараже и тягаться с готовыми гигантами рынка. Поговорил об этом и меня убедили - никакой прямой гонки нет, мы делаем свое независимое решение под требования заказчика.Основное приложение было спроектировано на Laravel, вокруг которого крутилась сеть изолированных Docker-сервисов. Одним из ключевых микросервисов стал кастомный эмбеддер на Python, отвечающий за векторизацию документов. В качестве хранилищ я исследовал и протестировал ChromaDB и векторные индексы ElasticSearch.
В рамках проекта я спроектировал и реализовал:
- Внутренний интерфейс для загрузки документов, управления чанками и тестирования чатов. Темплейты запросов, история диалогов, выбор ролей и назначение уровней доступа на документы.
- Специализированный внутренний инструмент (inner-loop) для тюнинга, версионирования и отладки system prompts.
- Проектирование безопасной архитектуры контекста (Pre-Retrieval Filtering): Реализовал изолированную ролевую модель доступа (RBAC) в рамках RAG-ассистирования. Из-за недетерминированности языковых моделей и уязвимости к prompt injection, защита была вынесена на уровень инфраструктуры, до обращения к LLM. Система на Laravel детерминированно проверяла права пользователя, формировала белый список доступных ID документов и выполняла фасетную фильтрацию векторного пространства (ChromaDB/Elastic) по метаданным. Модель получала в контекст только разрешенные чанки, что гарантировало абсолютную изоляцию данных: ИИ физически не имел доступа к информации, скрытой от пользователя.
Спустя месяцы плотной разработки и ресерча проект столкнулся с классической проблемой неоправданных ожиданий: клиент посмотрел на готовый прототип и заявил, что это не то, что он имел в виду. Бизнес-история сошла на нет, а проект был закрыт. Несмотря на это, для меня кейс стал мощнейшим технологическим прорывом в область локального инференса LLM, работы с векторными СУБД и проектирования гибридных AI-систем.
Собеседования
Принял решение выйти на открытый рынок и начал активно проходить собеседования. Результат оказался холодным душем - 10 проваленных интервью подряд. Этот опыт заставил меня трезво взглянуть на ситуацию и прийти к тяжелому, но важному осознанию: все те нестандартные задачи, которые я решал в последнее время, абсолютно никак не помогали мне проходить стандартные собеседования на позицию backend-разработчика. Рыночные интервью требовали ответов на типовую теорию и практику, в то время как мой бэкграунд состоял из постоянного тушения пожаров, партизанского деплоя и проектирования кастомных архитектур в условиях жестких ограничений. Начал четко осознавать, что текущий формат работы в DIV перестал приносить мне релевантный для классического рынка опыт. Вместо системного развития как инженера-платформера, тратил колоссальный ресурс на адаптацию к хаотичным требованиям, закрывая дыры в процессах, которые не конвертировались в строчки стандартного коммерческого Resume. Это понимание стало главным триггером для следующего фундаментального шага - заявления на увольнение, ухода в Self-Fund и полной смены вектора развития.
Подготовка к увольнению
Написав заявление, осознал реальную необходимость полноценной двухнедельной отработки. Моей целью было привести дела в порядок и оставить после себя качественную экосистему, за которую не придется краснеть. И именно в этот момент сюжет сделал довольно ироничный поворот. Спустя четыре месяца эксплуатации музейная команда неожиданно для себя обнаружила, что свободное место на физических дисках под Windows имеет свойство заканчиваться, а самостоятельная поддержка WSL-инфраструктуры со всеми её дисковыми ограничениями требует чуть больше инженерных усилий, чем они рассчитывали. В итоге произошло то, что месяцами называлось невозможным.
Музей оперативно согласовал и приобрел именно ту серверную инфраструктуру, которую я запрашивал на этапе проектирования. Это стало отличной возможностью переписать инфраструктуру проекта в её первоначальном, правильном виде.
За две недели отработки провел монументальный рефакторинг, снизивший общую сложность системы четыре раза:
- Декомпозиция монорепозитория: Разделил перегруженный монолит на пул независимых, изолированных репозиториев по зонам ответственности команд.
- Упрощение контура: Полностью пересобрал Docker-сборки, пайплайны и логику синхронизации контента. После избавления от костылей WSL архитектура доставки данных стала линейной и прозрачной.
- Развертывание на штатном железе: С нуля настроил и запустил проект на полноценной целевой инфраструктуре, которую нам наконец предоставили.
- Передача дел: Подготовил исчерпывающую техническую документацию для специалистов, которым предстояло администрировать эту систему дальше.
Финальный спринт позволил закрыть дверь за эпохой DIV на высокой ноте.
Проект был спасён дважды: сначала вопреки тотальным ограничениям среды, а затем - в качестве демонстрации того, как система должна была работать с самого начала, если бы к техническим требованиям прислушивались вовремя
Конец DIV
1 Декабря наступил день увольнения. С чистой совестью и отработанным техдолгом занялся своими проектами.
Men In Black
Сразу после моего увольнения сайт компании был автоматически отредактирован с полным удалением моего имени из списка участников разработки. Автоматическая система учёта сотрудников щелкнула своим корпоративным нейролизатором, попытавшись стереть мой вклад в архитектуру этих систем. Но, в отличие от агентов в черных костюмах, код и работающий Музей Победы помнят все коммиты, да и я сам всё прекрасно помню.Мастер-ТС Observability
Сразу после увольнения я получил сообщение от технического директора компании Мастер-ТС. Поскольку в прошлом, заслужил инженерное доверие, ко мне решили обратиться напрямую. Весь декабрь я посвятил задаче, заключающейся в проектировании и полном перестроении инфраструктуры наблюдаемости (Observability) как для старого легаси-контура, так и для новых сервисов платформы. Эволюция архитектуры мониторинга прошла два больших этапа:
Базовый контур
На первом этапе я развернул классический стек на основе Prometheus, LogStash, Elastic, Grafana. Настроил сбор логов и системных метрик через промежуточные агенты-процессоры, поднял Grafana, спроектировал кастомные дашборды для мониторинга здоровья платформы и вывел систему моментального оповещения об инцидентах (Alerting) в дежурный Telegram-канал Мастер-ТС.
Переход на OpenTelemetry стандарты
В качестве центрального ядра сбора данных я развернул otel-collector, который агрегировал всю телеметрию и распределял её по целевым хранилищам. Логи и трейсы маршрутизировались в аналитическую платформу HyperDX. Для решения проблемы сбора метрик со сторонней инфраструктуры (Redis, базы данных и системные докер-сервисы), не имеющей нативной OTLP-интеграции, я спроектировал гибридную схему. Сбор текстовых метрик с эндпоинтов /metrics выполнялся с помощью легковесных локальных агентов VictoriaMetrics, которые затем упаковывали данные и отправляли их в общую систему через протокол Prometheus Remote Write. Это позволило добиться сквозной связности данных: теперь по любому алерту в логах можно в один клик увидеть полный распределенный трейс упавшего запроса к базе данных или внешнему API.
2026 - Golang, R&D, Open-Source
Autosolve
Работая над RAG-платформой в DIV, сильно заинтересовался AI. Какое-то время исследовал и использовал множество инструментов и провайдеров. Windsurf, Cline, Anthropic, OpenRouter, OpenHands, OpenCode, Koda, GigaChat, Yandex Cloud AI, TimeWeb AI, DevinAI, CodeRabbitAI, Github Copilot и что-то ещё.
Copilot, DevinAI, CodeRabbitAI вдохновили на мысли. Взаимодействие с ИИ, используя в качестве фронтенда GitHub PR/Issue. В некоторых моих репозиториях существует множество Issues, некоторые из них могут быть разобраны даже простейшей глупой моделью. Классифицировать, провести обсуждение с человеком, запомнить, консолидировать, реализовать и создать ПР. Начал разбираться в том, насколько просто реализовать такой пайплайн с учётом изученных инструментов.
Составил требования:
- Поддержка OpenAI, Ollama интерфейсов, как минимум
- Отсутствие необходимости добавлять в репозиторий GitHub workflow, secrets, app integration, webhooks
- Один легковесный бинарник или docker image с возможностью запуститься легко где угодно. Полный self-host
- Широкая конфигурируемость. Репозитории, организации, интенсивность, лимиты
- Интеграция с OpenTelemetry
Исследованные инструменты, в целом, позволяли добиться такого пайплайна. Это требовало глубокого погружения в настройку флоу. OpenHands сводил с ума своим масштабом. Выполнение даже команды help в нём может занимать 4 секунды. Это полезный, всеобъемлющий, но слишком большой инструмент для задачи ассистирования Issues/PR. По большей части, инструменты либо являлись платформой для чего угодно, либо делали что-то одно, без знания контекста и без возможности конфигурации. Кроме общих инструментов, обнаружил множество репозиториев, содержащих python программы, нарушающие одно или несколько требований.
Проведя исследование, принял решение разработать свою программу.
Для разработки использовал:
- Golang 1.26
- Клиентская обвязка и интерфейсы: google/go-github для работы с API GitHub, spf13/cobra для построения интерфейса командной строки приложения.
- Конфигурация и валидация: spf13/viper для гибкого чтения конфигурационных файлов, go-playground/validator для строгого контроля корректности настроек при запуске. Конфигурация в YAML-формате со встроенным маппингом стандартов OpenTelemetry SDK, позволяющая гибко управлять партиционированием репозиториев, интервалами полинга, локальным ИИ-контуром Ollama и полностью переопределять параметры через переменные окружения с префиксом AUTOSOLVE_.
- Логирование и маскирование секретов: samber/slog-multi и natefinch/lumberjack для организации ротации и параллельных потоков логирования, m-mizutani/masq для предотвращения утечки токенов и ключей ИИ-провайдеров в текстовый вывод.
- База данных и миграции: C-go free драйвер modernc.org/sqlite для сохранения легковесности бинарника, sqlc для генерации типобезопасного кода запросов, pressly/goose для контроля версий схем данных.
- Хранение очередей задач: maragu.dev/goqite на базе SQLite для реализации транзакционного паттерна Outbox и управления асинхронным потоком выполнения.
- Сборка графа зависимостей: google/wire для статической генерации DI-контура на этапе компиляции без использования рантайм-рефлексии.
- Полный контур наблюдаемости: Пакеты go.opentelemetry.io для сквозного сбора распределенных трейсов, метрик и системных логов с экспортом через gRPC-транспорт.
- Инструментация сторонних вызовов: otelhttp для контроля накладных расходов сетевых запросов к провайдерам ИИ и XSAM/otelsql для мониторинга производительности локальной базы данных.
- Ограничение интенсивности и синхронизация: golang.org/x/time для контроля лимитов запросов (rate limiting) к GitHub API и golang.org/x/sync для управления конкурентными воркерами.
- Визуализация в терминале: jedib0t/go-pretty для форматирования статусных таблиц и структурированного вывода системных отчетов в консоль.
- Кодогенерация и линтинг сборки: sqlc и wire в качестве утилит генерации кода, govulncheck для автоматизированного аудита уязвимостей зависимостей, skywalking-eyes для валидации лицензий пакетов.
- Отказоустойчивость: thumbrise/resilience собственного производства для изоляции сбоев при интеграции асинхронного инференса языковых моделей.
Добившись полностью рабочего прототипа, я зафиксировал веху в микрорелизе v0.1 Dispatch MVP, где система успешно выполнила сквозной цикл, оставив свой первый в истории ИИ-анализ в репозитории проекта. Проблема бесконечного цикла само-ответов была решена через скрытый HTML-маркер вместо проверки user_id. Отказ от детекции по аккаунту автора стал принципиальным шагом для сохранения базового требования автономности: бинарнику не нужно знать свой ID или создавать GitHub Application, он ориентируется исключительно на текстовый след в Markdown, сохраняя ультимативную простоту self-host развертывания.
Resilience
В процессе разработки autosolve и стабилизации его асинхронных задач, особенно на стыке с внешними API GitHub и Ollama, возникла острая необходимость в механизмах отказоустойчивости. Первой итерацией решения стал pkg/longrun, в конечном счете разросшийся до 20 файлов и 1500 строк кода. Будучи перегруженным 12 внутренними терминами (Task, Runner, Baseline, Policy, ErrorCategory и др.), он страдал от греха избыточной реификации: в рамках единых структур данных были намертво склеены три ортогональных концепта - оркестрация задач, управление жизненным циклом (graceful shutdown) и чистая логика отказоустойчивости. Осознание архитектурного тупика произошло в рамках пулл-реквеста #203, когда численный аудит выявил критический рост цикломатической сложности и дублирование механизмов подсчета попыток. Попытка косметического рефакторинга через разнесение кода по разным файлам была отброшена по принципу Торвальдса: "Splitting files is mv, not refactoring". В пулл-реквесте #216 фреймворк longrun был полностью ликвидирован, а его логика упрощена до фундаментального математического примитива - функции-замыкания type Option func(ctx, call) error, которая изолирует состояние вызова и полностью исключает риски дата-рейсов на уровне самой конструкции.
Было проведено исследование на тему инструментов отказоустойчивости в экосистеме Go. Аудит существующих библиотек (cenkalti/backoff, sony/gobreaker, go-resiliency, failsafe-go) показал глубокую разрозненность экосистемы: инструменты либо игнорировали context.Context в сигнатурах, либо превращали паттерны в изолированные острова, не способные к естественной композиции и нативному сбору обсервабилити. Вместо создания очередного тяжелого фреймворка с Java-подобным абстракционизмом, было принято решение отделить чистую неизменяемую математику алгоритмов (экспоненциальные кривые, конечные автоматы брейкеров) от способов их проводки через лаконичные Go-замыкания. Независимая конвергенция с идеями промышленного стандарта resilience4j подтвердила правильность выбранного пути: отказоустойчивость должна быть набором чистых, тестируемых функций, а не надстройкой над сетевыми рантаймами. Обнаружение resilience4j было приятным и большим удивлением.
Выделенный в независимое open-source ядро микро-тулкит thumbrise/resilience был спроектирован на базе двух строгих точек расширения: изменяющих поток выполнения и пассивных клиентских плагинов для контроля и сбора метрик. Проект зафиксировал отказ от неявной магии, глобальных мутабельных стейтов и YAML-конфигураций.
Также был не забыт функционал динамического переопределения задержек через WaitHint (Retry-After).
Реализовал рабочий прототип, который прямо сейчас используется в рамках Autosolve. На данный момент ждёт своего часа развития.
Multimod/Gover
При попытке изолировать плагины со сторонними зависимостями (такими как OpenTelemetry SDK) в рамках мульти-модульного репозитория, разработка уперлась в ограничения стандартного тулчейна Go, что заблокировало целевую архитектуру проекта и вынудило временно заморозить код ради исследования экосистемы.
Архитектура ядра библиотеки resilience с изолированной экосистемой дочерних пакетов (таких как OpenTelemetry) на физическом уровне была обязана проектироваться как мульти-модульная, чтобы избавить конечных пользователей от принудительного стягивания тяжелых транзитивных зависимостей. Однако как только репозиторий был нарезан на независимые модули со своими файлами go.mod, кодовая база мгновенно превратилась в инфраструктурный ад: локальное рабочее окружение полностью деградировало, компилятор и IDE ослепли, стандартные команды go test ./... перестали видеть подмодули, а ручное прописывание replace-директив и координация Git-тегов для каждого пакета превратились в бесконечный генератор человеческих ошибок с высоким риском навсегда отправить сломанный манифест в неизменяемый кэш Go Module Proxy.
В попытках починить локальный девелопмент по официальным гайдам, я начал глубоко исследовать встроенный механизм go.work. Однако детальный разбор официальных рекомендаций Go-команды выявил, что нативный инструмент является минным полем: базовая команда go work use -r . без разбора гребет в рабочее пространство мусор из директорий vendor/, testdata/ и ломает IDE кривыми тест-фикстурами, фантомные файлы воркспейсов из родительских папок скрыто меняют поведение сборки, а официальный совет "не коммитить go.work" делает zero-setup запуск проекта после клонирования физически невозможным.
Удивившись масштабу этой пропасти, я не поверил, что индустрия за столько лет не создала готового решения, и пошел исследовать, как эту проблему обходят другие крупные экосистемы и проекты. В процессе аудита я наткнулся на официальные инструменты команды OpenTelemetry, которые решали схожую задачу внутри своего огромного репозитория с помощью кастомной Go-утилиты. По иронии судьбы и абсолютно случайному совпадению - их утилита называлась точно так же, как я изначально планировал назвать свой исследовательский репозиторий: multimod. Я обнаружил в их утилите multimod жесткую реификацию и конфигурационную сложность. Вместо автоматического анализа кодовой базы они заставили инженеров вести тяжелый YAML-манифест versions.yaml, который дублировал структуру каталогов и привязывал логику релизов к внутренним соглашениям самой организации OpenTelemetry. Инструмент оказался монолитом, намертво скрестившим управление версиями с созданием промежуточных релизных веток, что заставляло CI-пайплайны плодить грязные коммиты в истории Git.
Этот архитектурный тупик заставил меня задаться фундаментальным вопросом: а почему мы вообще вынуждены вручную координировать и разводить версии разных модулей в рамках одного проекта? Именно в этой точке я впервые детально осмыслил онтологическую разницу терминов: монорепозиторий - это не мульти-модульный проект. Монорепозиторий - это сугубо стратегия хранения кода на диске, много независимых продуктов в одной Git-репе, в то время как мульти-модульный проект - это единый продукт, просто разделенный на слои. Пришло четкое осознание инварианта: версионирование должно вестись по принципу принадлежности к общему ченжлогу. Если при выпуске версии расширение появляется в общем логе изменений продукта - у них обязан быть единый жизненный цикл и одна SemVer-версия на весь граф подпакетов.
Изучая OpenTelemetry пришёл критическому осознанию двойственности состояний любого многомодульного репозитория в Go. Код обязан перманентно находиться в Dev-state с локальными replace-директивами, чтобы разработчики и IDE могли бесшовно работать внутри воркспейса, но в момент релиза система должна мгновенно переходить в идеально чистое Publish-state без локальных путей, иначе пользователи стянут сломанные манифесты. Задался вопросом, почему существующие практики заставляют инженеров пачкать историю Git, делая коммиты-маятники - сначала срезая локальные пути для публикации, а затем накатывая их обратно в ветку main. Пришло понимание, что Git-тегу абсолютно безразлична сущность веток - он фиксирует конкретный слепок данных. Это подтолкнуло к идее полностью изолировать грязные коммиты публикации от ветки разработки, вынеся чистое состояние релиза на изолированный, оторванный коммит (detached commit), доступный исключительно через SemVer-ссылку.
Параллельно я препарировал доминирующие на рынке системы автоматизации релизов, включая GoReleaser и семантические трекеры коммитов. Анализ их архитектуры вызвал жесткое инженерное отторжение: почему разработчик обязан сдаваться в рабство монолитным фреймворкам с проприетарными YAML-конфигурациями на 500 опций вместо того, чтобы сохранять полный контроль через классический Unix-way и прозрачные терминальные пайпы? Изучение истории изменений GoReleaser вскрыло коммерческий цинизм индустрии - с июля 2022 года авторы монолита принудительно заперли под платный пейволл (Pro-версию) функции разделения стадий сборки и публикации (--prepare / --publish), мульти-модульность и кастомные хуки. Возможности, которые в композабельном Unix-дизайне на базе stdin/stdout являются абсолютно бесплатными и естественными свойствами архитектуры, монолиты превратили в премиальные платные надстройки.
Обратившись к опыту коллег из смежных технологических стеков, я обнаружил, что в других языках программирования подобные проблемы были бесшовно решены на уровне стандартных экосистемных стандартов. Разработчики на Rust годами использовали нативный cargo workspaces в связке с cargo-release. В Node.js-сообществе стандартом управления многомодульными пакетами стал changesets. Java-инженеры опирались на полировавшийся с 2005 года mvn release. В Elixir из коробки существовали встроенные in_umbrella зависимости. Проведенный кросс-экосистемный анализ подтвердил шокирующий факт: Go оставался зрелым промышленным языком, где инженеры были брошены один на один с ручной координацией SemVer-тегов, отсутствием стейджинг-зон и тотальным вакуумом в области автоматизации многомодульной архитектуры.
Финальной точкой в исследовании рынка стало обнаружение архивного треда пятилетней давности на Hacker News. Детальный анализ дискуссии показал, что сообщество годами бьется в том же самом инфраструктурном тупике, а инженеры в унынии советуют либо "вообще не использовать мультимодули в Go", либо разворачивать тяжелый Bazel, который решает проблемы кэширования сборки, но абсолютно слеп к задачам управления go.mod и публикациям в прокси-сервера. Осознание того, что за пять лет официальный Go-toolchain так и не дал ответа на этот вызов, укрепило меня в решении прекратить ручную работу над resilience и сесть за написание собственного суверенного станка автоматизации жизненного цикла.
Составил требования:
Составил требования:
- Невозможность footgun. Защита инварианта и предоставление точной модели состояния репозитория
- Разделение dev&publish state
- Unix composability. Возможность использовать любой инструмент релизов или ченжлогов в связке с моим инструментом
- Ультимативный zero-config старт: Автоматическое обнаружение файлового графа без принудительного ведения YAML-манифестов и дублирования структуры go.mod
Записал этапы исследования и составил много-составной RFC.
Реализовал рабочий прототип.
GhSet
В процессе создания инструментов понял, инструменты рождают новые инструменты. Создание репозиториев дело несложное. Сложно повторять настройку репозитория. Защита веток, тегов. Правила пулл-реквестов, ребейза, мержа, аппрувов. Безопасность и сканирование.
Попытка найти готовое, простое решение вскрыла настоящее кладбище заброшенного софта, где официальные и популярные утилиты вроде probot/settings или safe-settings либо умерли вместе со своими фреймворками, либо падали на современных правилах защиты веток. Единственная живая альтернатива в виде Terraform-провайдера требовала написания HCL-кода, ручного импорта ресурсов в стейт и настройки бэкенда, заставляя инженера становиться Терраформ-специалистом ради копирования пары чекбоксов. При этом ни один инструмент на рынке физически не умел делать снимок (describe) настроек живого репозитория, вынуждая писать конфигурации руками с нуля.
Записал исследование.
Спроектировал ghset. Легковесный CLI-копировщик, который полностью делегирует авторизацию утилите gh CLI. Инструмент за один Unix-пайп выкачивает настройки, безопасность, лейблы и рулсеты в YAML-слепок, позволяя развернуть новый преднастроенный репозиторий одной командой ghset init --from. Полностью готовый к бою и использующийся несколькими людьми инструмент. Один из простых, но полезных. Describe from and apply to - очень мощная концепция.
TODO
- TG, линкедин, github-pages блог thumbrise + экосистемный портал.
- https://github.com/thumbrise/demo - Demonstrative project with academic fundamentals and examples of apps. СУБД с нуля на голанг. Примитивные типы данных с ручным мемори менеджментом. Хайлоад сервис комментариев с redis-streams + golang. Для всего реализовано plugin-system.
- https://github.com/thumbrise/otel-template-basic - Репозиторий наблюдаемости для развертывания в одну команду. Полная конфигурируемость + zero configuration. OTLP + прометеус коллектор. Full observability, only exposed OTLP and prometheus remote write. UI uptrace а впоследствии HyperDX.
- https://github.com/thumbrise/commitlint-scope - Linter that checks if declared commit scopes match the changed files.
- https://github.com/thumbrise/op - Anything-agnostic operation protocol. For operations-driven future. Широчайшее и глубочайшее исследование, как цель жизни.
- https://github.com/thumbrise/gcce - Golang Code Capability Emitter
- https://github.com/thumbrise/pipass - Compile-time type-safe pipeline pass wrappers generator for Go