Привет, Хабр. Меня зовут Алексей Постригайло. Двадцать с лишним лет я занимаюсь системной интеграцией и управлением проектами, сейчас — старший партнер одного крупного ИТ-интегратора. Здесь я рассказываю о технических и организационных подробностях наших проектов.
Меня, признаться, удивило, что наш предыдущий рассказ — тот самый «больнючий» опыт про СТО — так неожиданно бодро набирает просмотры. Мы решили, что стоит продолжить про кейсы с разными «граблями» (и «успешными успехами», куда без них), которые помогли нам научиться и кодить лучше, и процессы строить грамотнее. Берите на вооружение полезное и не повторяйте наших ошибок. Поехали.
Предыстория: непростая ситуация.
Наш заказчик — Департамент труда и социальной защиты населения Москвы (ДТСЗН), масштабная и живая структура. Его портал обслуживал две совершенно разные вселенные:
-
с одной стороны — миллионы москвичей, ищущих информацию о социальных услугах,
-
с другой — сотрудники более 300 подведомственных учреждений, для которых портал служил ежедневным рабочим инструментом.
Проблема назревала постепенно. Одним из ключевых сервисов для горожан был «Социальный навигатор» — интерактивная карта, встроенная в основной портал. К 2021 году на карте было отмечено свыше 935 адресов по 225 различных услуг, а общее число обращений к нему перевалило за 1,3 миллиона. Мы понимали, что рост нагрузки — дело времени, но настоящий вызов пришел с другой стороны.
На портале кипела жизнь: релизы требовались в среднем раз в три дня, а срочные правки с дедлайном «еще вчера» — и того чаще. И вот руководство заказчика ставит задачу: срочно доработать «Социальный навигатор», добавив к нему крупную фичу А для презентации к несдвигаемой дате в Департаменте. Мы успевали, но был нюанс.
Параллельно в том же монолитном проекте мы уже вели разработку другой, не менее масштабной фичи — подсистемы отчетности для тех самых 300+ организаций (фича Б). Код естественным образом смешался в общей dev-среде.
Ожидаемо мы получили классическую патовую ситуацию — полностью готовая и протестированная фича А оказалась намертво заблокирована. Выкатить ее в прод нельзя, потому что вместе с ней улетели бы сырые, всё ломающие изменения из фичи Б.
Боль управления зависимостями
Чтобы было понятнее, в чем суть затыка (см. рис. 1), поясню чуть глубже архитектуру. Точками соприкосновения «Навигатора» (фича А) и системы отчетов (фича Б) были общие сущности в базе данных: «подведомственные организации», «НКО», «бизнес», «услуги», а также «округА» и «районы». Сущность «подведомственная организация» была особенно объемной и тесно связанной с «услугами» — ключевой для «Навигатора». Эти «лёгкие» правки мы и не могли перенести в прод без незавершенных структурных изменений по отчетам.
Ситуацию усугубляли два фактора.
Во-первых, подсистема отчетности была критична для упомянутых выше сотен организаций, и ее деплой требовал долгих согласований и предупреждений всех пользователей (они должны были успеть сохранить данные и выйти из системы). Чаще всего это означало работу после конца рабочего дня. Срочные правки по навигатору просто «застревали» в ожидании окна.
Во-вторых, изменения были не косметическими, а архитектурными, затрагивающими таблицы БД. Изолировать их простым feature toggle было невозможно.
Оставался скользкий путь, знакомый каждому, кто работал с legacy-монолитами: ручные cherry-pick’и — то есть выборочные переносы коммитов из одной ветки в другую. Но чем больше таких манипуляций, тем выше энтропия и риск уронить прод. На практике попытки таких переноса регулярно вызывали конфликты в общих CSS и JS-файлах, «уезжала» верстка, появлялись трудноуловимые баги на фронтенде. Учитывая масштаб подсистемы отчетности — с объемом рисков был явный перебор.
Техническая проблема стремительно и ожидаемо переросла в коммуникационную: «Почему не выкатываете обновления? Мы заждались!».
Предложение
И вот в один прекрасный летний день мы пришли к заказчику с радикальным, но, на наш взгляд, неизбежным предложением: резать монолит «по-живому», а именно выделить «Социальный навигатор» в полностью независимый сервис на отдельном поддомене: https://nav.dszn.ru (см. рис. 2).
Аргументы были просты и логичны:
-
Это быстро и относительно недорого. Не надо переписывать всё с нуля — нужно просто «хирургически» отделить существующий, работающий функционал.
-
Это развяжет руки всем:
-
мы сможем оперативно поставлять фичи для «Навигатора», независимо от разработки других модулей;
-
срочные доработки перестанут «томиться» в ожидании «окна».
-
-
Кроме того, анализ метрик, в том числе из Яндекс.Вебмастера, показывал, что интерактивная карта сильно нагружала и без того тяжелый «монолит». Её вынос ее должен был стабилизировать работу основного портала.
Уговаривать не пришлось — нам дали «добро».
На реализацию ушло около 3 месяцев.
Технические компромиссы и бонусные решения
Выделить сервис — полдела. Надо было не создать на месте одной проблемы две новых. И мы пошли на некоторые технические компромиссы.
Первый и самый принципиальный выглядел еретически: мы не стали заводить отдельную БД. Зачем плодить сущности? Навигатору не нужно состояние — ему достаточно получать свежие данные по запросу. База осталась на основном портале.
Это решение одним махом сняло с нас пласт проблем:
-
не потребовались дополнительные серверы СУБД (а с ними настройка бэкапов и репликации);
-
не появилось новых точек отказа;
-
плюс безопасность — нет локальной БД на публичном сервисе, значит, неоткуда случиться прямой утечке.
Данные в «Навигатор» поступают через API в формате JSON, по запросу (вручную, по кнопке в админке) или по расписанию (cron). Но источников данных стало два:
-
администраторы портала, как и раньше, правят информацию в основной админке;
-
ключевое архитектурное изменение — мы создали личные кабинеты для каждой из 300+ подведомственных организаций.


Теперь каждый центр соцобслуживания или фонда сам, как ему надо, актуализирует информацию о себе: адреса, контакты, перечень услуг. Правки отправляются на модерацию и только после утверждения попадают в «Навигатор».
Иными словами, вся система теперь завязалась на трех ключевых приложениях (см. рис. 3):
-
панели администрирования на основном портале;
-
личные кабинеты для подведомственных организаций;
-
сам «Навигатора».
Так мы решили две проблемы разом: избежали двойного ввода данных и переложили нагрузку по их наполнению на тех, кто знает эти данные лучше всех — на сами учреждения.
В навигаторе всегда хранится только одна, текущая версия данных из свежего JSON-файла. Никакого версионирования, никаких миграций — если на источнике менялась структура, мы просто корректировали логику обработки JSON.
Поскольку JSON-файлы объемны, их «наивная» обработка съедала бы много ресурсов. Поэтому мы задали легкий PHP-пакет, реализующий паттерн «Коллекция» (аналог Illuminate/Collections из Laravel). Вместо «прожорливых» циклов foreach разработчики получили возможность использовать декларативный код с цепочками методов map(), filter(), groupBy(), плюс «ленивые» вычисления дополнительно экономили память и процессорное время.
«Вишенка на торте» — помимо основного сервиса, мы сделали его облегченную версию в виде виджета (рис. 4). Это интерактивная карта в iframe, которую можно встроить куда угодно — мы встроили на главную страницу основного портала. Весь интерактив работает внутри фрейма, без всяких авторизаций и сложностей с CORS.
Результаты и выводы
Что мы получили в сухом остатке?
Во-первых, достигли главной цели — ускорили выкатку фич. Мы перестали быть заложниками параллельных разработок, и обновления для «Социального навигатора» теперь выходят независимо от состояния других частей монолита.
Во-вторых, разработка стала безопаснее. Мы ушли от практики рисков с cherry-pick’ами, которая изрядно нервировала команду.
В-третьих, — и это весомо для заказчика, — прямая экономическая выгода. Создав личные кабинеты для подведомственных учреждений, мы перенесли на них основную нагрузку по управлению контентом. Профильные подразделения Департамента разгрузились.
Соответственно, и скорость обновления информации в Навигаторе увеличилась в разы, сделав его для москвичей значительно полезнее.
Но главный вывод лежит не в технической, а в управленческой плоскости. Мы делали декомпозицию не потому это стильно-модно, а потому что она развязывала конкретный узел бизнес-проблем. А это — аргумент.
А на этом я с вами прощаюсь. Благодарю за ваше внимание. Подписывайтесь, чтобы быть в курсе технических и организационных подробностей (т. е. граблей и успехов) наших проектов. До новых встреч.
ссылка на оригинал статьи https://habr.com/ru/articles/1026414/