Девять лет в распределённых системах

Что я делал и что из этого вышло.

Здравствуйте! Я Владимир Савкин, системный архитектор и технический руководитель. Девять лет проектирую высоконагруженные распределённые системы: связь, страхование, авиаперевозки, промышленное производство.

По образованию математик-программист. Там, где считаются деньги, цена ошибки измеряется в миллионах, поэтому я не полагаюсь только на тесты: правила обращения с деньгами доказываю формально, ещё на этапе проектирования.

Образование

Омский государственный технический университет.
Бакалавр по направлению «Математическое обеспечение и администрирование информационных систем», математик-программист (2017).
Магистр факультета элитного образования по направлению «Фундаментальная информатика и информационные технологии» (2019).

Работа

White-label платформа дистрибуции eSIM · 2025–2026

Пришёл старшим разработчиком, через три месяца стал системным архитектором и техническим руководителем. SaaS-агрегатор eSIM: платформа подключает провайдеров связи, забирает их тарифы и поток трафика, а партнёры перепродают eSIM под своим брендом. Наценка каскадно начисляется по иерархии в четыре уровня поверх тарифа провайдера, трафик тарифицируется почти в реальном времени. Деньги считаются на каждом уровне, и ошибка в копейку разрастается по всей цепочке.

  • Остановил развитие старой системы и спроектировал новую. Прежняя держала не больше трёх партнёров одновременно, новая рассчитана на миллионы профилей и переживает пиковые выгрузки провайдера без потери данных.
  • Заказчик начал принимать работу раньше, чем был готов весь объём: я пересобрал контракт на ядро и приращения. Работы по безопасности и целостности данных добавились к объёму позже и уложились в исходный бюджет, потому что были заложены ещё при проектировании.
  • Спроектировал и вёл шесть сервисов на .NET 8 и сервис обработки трафика на Go. Четыре из них написал сам, единственным бэкенд-разработчиком.
  • Тарификация ускорилась почти в 30 раз: с ~100 до ~2 860 сообщений в секунду. Потолок в 5–7 млн профилей посчитан по реальному потоку провайдера, поэтому момент апгрейда известен заранее.
  • Расчёты с деньгами проверены математикой: 302 формально доказанных утверждения о работе платформы в 16 моделях на SMT-решателе Z3. К ним 2943 автотеста на каждом изменении, прогон занимает четыре минуты. В прежней версии тестов не было вовсе.
  • Выкладка на прод занимала 50 минут с простоем, стала занимать 3–5 минут без простоя.
  • Выстроил процесс поставки с нуля, нанял тестировщика, вывел фронтенд-разработчика из замороженного проекта. После ухода технического директора вёл проект целиком.
Что именно закрыто на уровне архитектуры

Каскадное начисление: тарифы наследуются по иерархии и версионируются, балансы обновляются атомарно в целочисленных микроединицах, покрытие счетов - по очереди FIFO. Конвейер трафика работает по принципу «хотя бы раз»: пакет пишется одной транзакцией, списание выводится только из вставленных строк реестра - баланс и реестр не расходятся ни при каком повторе; испорченная запись не блокирует волну, падение пакета деградирует в поштучную обработку.

Кредитный лимит, которого раньше не было: прогноз исчерпания и блокировка на нулевом остатке. Без него перерасход между обнулением баланса и остановкой трафика оплачивала бы платформа.

Классы ошибок, которые не могут возникнуть по построению: расхождения балансов, гонки при одновременных операциях в иерархии, утечки данных между ветками партнёров, дубли счетов, порча подписанных документов. Права вычисляются на каждом запросе, поэтому отзыв действует немедленно.

У ключевых сущностей явная машина состояний: какие статусы есть, какие переходы допустимы и почему. Система сама говорит, что с ней можно сделать; интерфейс правила не дублирует. Одно действие пользователя - одна прослеживаемая цепочка через все сервисы; аудит фиксирует, кто начал действие.

Качество и процесс

Двенадцать архитектурных решений записаны в ADR с контекстом, отброшенными вариантами и ценой, включая негативные последствия, модели описаны в UML. Формальные модели покрывают каскадные тарифы, покрытие счетов, неизменяемость снимка счёта, кредитный мониторинг, видимость профилей по ролям; код и тесты писались один к одному по спецификациям.

Контракт API генерируется из кода на обеих ветках и сравнивается: ломающее изменение валит проверку, отчёт по релизу уходит в документацию, по нему тестировщик строит регресс. Сборка и тесты - на каждом изменении, входящие коммиты сканируются на секреты.

Спринты с явной ёмкостью, задачи не длиннее рабочего дня, ревью архитектуры до кода. Риски приносил владельцам письменно, заранее и с вариантами решения; ввёл таксономию дефектов с явной границей между гарантийным исправлением и новыми требованиями.

Стек: .NET 8, C#, ASP.NET Core, EF Core, PostgreSQL, RabbitMQ и MassTransit, YARP, Hangfire, ClickHouse, Go, Docker, Loki и Grafana, Z3.

Раньше

Проекты для S7 Airlines и Ингосстраха · 2021–2024

  • Платформа закупок S7: авиакомпания публикует потребности, поставщики отвечают предложениями. MVP с нуля за полгода в команде сеньоров. Ответы китайских поставщиков приходили письмами и вносились вручную по полчаса на каждое. После моего парсера они разбираются сразу.
  • Учёт трудозатрат S7 показывал данные двенадцатичасовой давности. Я перевёл цепочку на события, и отчёты стали показывать данные сразу, без перестройки системы.
  • Ингосстрах: нашёл, что пуш-уведомления в мобильном приложении не работали около года и никто об этом не знал. Восстановил их, переписал сервис на прямую работу с Apple и Google, рассчитал под пиковые маркетинговые рассылки. Внедрил вход через Госуслуги.
  • Наставлял начинающих разработчиков на каждом проекте, проводил собеседования, замещал руководителя команды.
Подробнее
  • Платформа закупок. Мои сервисы: слой над Kafka, приводящий предложения разных поставщиков к единой модели; справочники; почта; часть сервиса запросов. Парсер писем - с проверкой данных и уведомлением об ошибке.
  • Учёт трудозатрат. Коллектор собирал данные из Service Desk и JIRA, превращал их в бизнес-объекты через цепочку промежуточных таблиц, отдельный сервис показывал отчёты. Ввёл оркестратор заданий в коллекторе и перевёл всю цепочку в потоковый режим: коллектор публикует изменения в RabbitMQ, презентация пересчитывает проекции по событию. Фильтрация в отчётах - по проекциям вместо запросов по сырым данным.
  • Пуши Ингосстраха. Причины: пропущенный переход Apple на новый протокол и ошибки на Android. Переписал сервис на прямую работу с Apple и Google. От перехода на Firebase отговорил с обоснованием - позже санкции закрыли его для России, а прямая интеграция продолжила работать. По входу через Госуслуги вёл серверную часть и курировал мобильную: разбирал для команды последовательность шагов протокола.
  • Инфраструктура. CI/CD на Azure DevOps: каждый коммит проверяется на утёкшие секреты (Gitleaks) и качество кода (SonarQube). Мониторинг на Serilog, Elasticsearch и Grafana.

Стек: C#, .NET 6–7, ASP.NET Core, EF Core, MS SQL Server, PostgreSQL, Kafka, RabbitMQ и MassTransit, MediatR, SignalR, Quartz, OAuth 2.0, Docker, Kubernetes.

Измерительное оборудование · 2019–2021

  • Довёл точность стендов развал-схождения до уровня Hunter, мирового стандарта отрасли, и компания получила отраслевой сертификат.
  • Спроектировал подсистему измерений с запасом под будущие модели оборудования.
  • Переписал около половины кодовой базы под модульные тесты, внедрил непрерывную сборку.

Стек: C#, .NET, WPF, OpenCV, SQLite, NUnit.

Проект для Газпром нефти · 2017–2019

  • Система планирования производства: оптимизировал математическую модель на симплекс-методе и внёс в неё ограничения, которые до этого обходились эвристиками.
  • Написал модуль работы с временными интервалами - ядро планирования: расписания, окна доступности оборудования.

Стек: .NET Framework 4.6–4.7, .NET Core 2.0, WPF, Prism, Unity, Microsoft Solver Foundation, SQL Server, Telerik UI.

Как работаю

Архитектура - это решения, которые дорого менять потом. Отсюда правила:

  • Каждое значимое решение записываю: контекст, варианты, выбор, последствия - включая негативные. Через год документ отвечает на вопрос «почему так» без моего участия.
  • Сначала модель, потом код. Перед чтением чужой системы моделирую, как она должна работать: какие операции есть, какая у каждой обратная, кто что теряет, если операция пойдёт не так. Потом читаю код и ищу расхождения.
  • Машина состояний - это спецификация. Читаю её как бизнес-требования: есть ли тупики, копятся ли сущности без пути назад, есть ли статус, который открывает всё.
  • Проверка описывается до прогона: ожидание пишется раньше факта, иначе факт подгоняется под ожидание. Один этап работы - один этап проверки, сразу.
  • Задачи режу на куски не длиннее рабочего дня. Так видно движение, и не копится незавершённое.
  • Риски приношу заказчику письменно, заранее и с вариантами решения - до того, как они станут срывом.

Инструменты

.NET 8 и C# как основной стек, Go - там, где нужен поток данных. PostgreSQL, ClickHouse, RabbitMQ, Docker, Kubernetes. Формальная верификация - Z3 и SMT-LIB.

Разработка с ИИ-агентом

На последнем проекте выстроил процесс, в котором агент пишет код в рамках принятой архитектуры. Для этого написал собственный набор из полутора десятков навыков: как заводить сущность, репозиторий, контроллер, доменное событие; как писать тесты; как проводить ревью по решениям проекта; какой паттерн выбирать и когда не выбирать никакой. Отдельный навык задаёт дисциплину длинной работы: план с состояниями и критериями завершения, проверка каждого этапа сразу, как он готов. Результат агента проходит тесты и ручное ревью - он ускоряет написание, но не заменяет проверку.

Тем же способом написаны SMT-спецификации и код по ним. Спецификация и реализация шли из одного источника, совпадение проверялось тестами и вручную - поэтому они не разъехались за время разработки.

Дообучение моделей и оркестрация процессов - отдельный интерес, в рабочих задачах применяю по мере необходимости.

Открытый код

  • Web Holy Grail - мой флагманский продукт: фундамент для собственных сайтов на Next.js 15 и Payload CMS 3. Сайт растёт от визитки до портала внутри одного репозитория, без переезда на другой стек. Публичная документация с обоснованием выбора стека. Лицензия MIT. На нём работает и эта страница.
  • DotNetSolutionKit - каркас микросервисной платформы на .NET и PostgreSQL для высоконагруженных систем. Новый сервис появляется одной командой и сразу получает слои, тесты и файлы деплоя; шина с outbox, фоновые задачи, ClickHouse, журнал аудита, API-шлюз и секреты из Infisical включаются флагами. Каркас проверен в продакшене: на нём построена платформа, о которой сказано выше, инфраструктуру развернули за сутки, дальше команда писала только бизнес-логику. Команде из пяти человек с восемью сервисами при московских ставках он экономит 5-10 млн ₽ за первый год: общий слой не нужно строить, сервисы не нужно копировать, вычищать и гонять копии через ревью, тестирование и контроль руководства, а правка общей части делается один раз. Освободившиеся месяцы уходят на новые заказы. Ставится из NuGet, документация на русском и английском, код на GitHub, лицензия MIT.
Что DotNetSolutionKit закрывает на уровне каркаса
  • Доменные события живут вместе с транзакцией: обработчики срабатывают до коммита, после коммита или после отката, одинаково в запросе, консьюмере и фоновой задаче. Письмо по откаченной записи не уйдёт; сообщение другому сервису уходит через outbox только после коммита.
  • Каждый сервис владеет своей схемой PostgreSQL. Страж схемы закрепляет её при первом старте, и чужой сервис с той же строкой подключения не поднимется. Миграции идут под блокировкой, поэтому реплики можно запускать разом.
  • В любой точке цепочки видно, кто начал действие и из какого запроса: пользователь и идентификатор корреляции проходят через вызовы между сервисами, сообщения шины и фоновые задачи.
  • Журнал аудита пишется в той же транзакции, что и изменение. Тесты-правила падают, если для сущности не решили, аудировать ли её, если в журнал может попасть пароль или токен и если массовая запись в обход EF Core не объявлена.
  • Команду можно безопасно повторить: повтор с тем же ключом клиента получает сохранённый ответ, а из двух одновременных запросов с одним ключом результат запишет только один.
  • Контракт API под контролем: OpenAPI-документ строится из самого приложения без базы и секретов, и пулл-реквест с необъявленным ломающим изменением не проходит проверку.
  • Выкладка без простоя на одном сервере: blue-green под docker compose с автооткатом. Под непрерывной нагрузкой деплой и откат прошли 321 запрос, все с ответом 200.
Как посчитана экономия
  • Каркас первого сервиса: 2 человека на 2-3 месяца, с ревью и тестированием - 5-8 человеко-месяцев.
  • 7 сервисов копированием соседнего: разработка, ревью и тестирование, 8-17 дней на каждый - 3-6 человеко-месяцев.
  • Общая правка раз в месяц во всех 8 копиях: 1-2,5 дня на копию - 6-12 человеко-месяцев за год.
  • Контроль руководства: ещё 10-20% к работе команды.

Итого 16-31 человеко-месяц. Человеко-месяц стоит компании 265-390 тыс. ₽: медиана зарплаты разработчика по Хабр Карьере за первое полугодие 2026 года, НДФЛ и страховые взносы IT-компаний 2026 года (15% до 2,979 млн ₽ в год, 7,6% сверх). Выходит 4-12 млн ₽, при московских ставках от 5,6 млн ₽. Офис, техника и лицензии не учтены.

  • FoQLens - исследовательский проект: проектирую новую архитектуру языковой модели, в которой точность весов выбирается под смысл запроса. Вопрос о том, как пишется слово, не должен стоить модели столько же, сколько самый сложный вопрос, который она умеет решить. Стенд на Python, опыты на Gemma 4 E2B по жёсткой методологии, код открыт.

Открыт для сотрудничества

Архитектура, техническое руководство, сложные предметные области. Напишите о задаче и я вам обязательно отвечу.