Когда проект только стартует, в воздухе витает амбиция - Мы обязательно сделаем всё правильно. Чистая архитектура, ясные зоны ответственности, аккуратные контракты между сервисами, но реальность не знает о ваших планах.
Не потому, что кто-то не знал паттернов проектирования или выбрал не ту СУБД, а потому бизнес требует фичи "на вчера". И шаг за шагом архитектура сдаёт позиции. Что самое интересное - разрушение происходит незаметно. Никакого взрыва вертолетов на заднем фоне не будет. Только десятки небольших компромиссов, которые за относительно короткое время могут превратить систему в клубок боли. Тихо и буднично. Конечно, количество спринтов будет больше трех, но основной сути это не меняет.
Поэтому подготовил для тебя, системный аналитик (и не только), гайд “Как убить архитектуру за три спринта” даже если в начале все было относительно под контролем. Чтож… Щас выскажусь!)))
Первая стадия: “Временный костыль”
Разрушение начинается тихо. Буквально с одной безобидной фразы:
Давайте пока сделаем так, а потом поправим.
Компромисс ради скорости поставки! Его легко принять особенно когда давят сроки и нужно показать результат бизнесу здесь и сейчас. Но в реальности заявленное “потом” может не наступить никогда.
Следующий спринт диктует нам необходимость выполнить новые задачи, приоритеты меняются, а рефакторинг затягивается. Это временное решение может легко уйти в продакшн и обрасти различными зависимостями. Со временем команда начинает воспринимать это, как норму.
И вот уже все строится не на продуманной архитектуре, а на спагетти из компромиссов и обходных решений. На этом этапе еще можно остановиться, но часто никто этого не делает. Потому что задачи продолжают сыпаться сверху, а времени на переосмысление и рефакторинг не прибавляется. К сожалению.
Кейс:
Кросс-команда работала над срочной интеграцией внешнего сервиса с расчетами. На полноценную проработку не было времени. И поэтому сделали вызов, но без учета ролевой модели, решив вернуться к рефакторингу позже.Через каких-то 2 месяца на это решение уже опирались другие компоненты. После аудита со стороны ИБ (который по какой-то причине не был выполнен изначально) нарушение всплыло мгновенно. Исправить без остановки критических бизнес-процессов было фактически невозможно.
Пришлось затыкать дыры костылями с пластилином и оправдываться на различных уровнях. Кажется это был незаменимый опыт.
Вторая стадия: “Фичи любой ценой”
На старте у вас был план и вы его придерживались: сначала фундамент, а потом фичи и котяток натыкать для UIности, но что-то пошло опять не так:
Пользователям нужен срочно новый функционал.
Бизнес недоволен, истерит, топает ножкой и требует быстрее.
Конкуренты запустили такое еще на прошлой неделе и вам нужно обязательно ускориться.
Плевать на архитектуру. Главное - фича в проде и KPI. Не важно, что требуют результат здесь и сейчас. Это нормально! Важно то, что без архитектурной дисциплины каждая новая фича ложится на уже трещащий каркас и проект развивается хаотично.
Каждый следующий спринт становится не развитием, а борьбой за выживание. Система напоминает здание, в котором каждую новую комнату пристраивают к уже перекошенным стенам, а команда начинает думать только в рамках конкретной задачи, а не целостного продукта.
Фраза "нам нужно это к следующему релизу" начинает оправдывать всё.
Кейс:
Бизнес требовал регулярно выкатывать новые типы отчетности, чтобы выгодно отличаться от конкурентов. Для ускорения разработки начали подмешивать вычисления прямо в запросы. Все выглядело “Не красиво, но работает!”Пилот показал хорошие результаты и отчеты стали официальной частью продукта. Но за это время база претерпела изменения в виде новой модели данных. Оказалось, что старые запросы собирали данные некорректно.
На исправление боли потратили огромное количество времени и по итогу вынесли логику на уровень сервиса.
Третья стадия: “Границы? Не, не слышали!”
Архитектура держится не на коде, а на ясном понимании, где проходят границы ответственности между частями системы. Когда в угоду скорости эти границы начинают нарушать, процесс разрушения становится необратимым.
Изначально у каждого сервиса была своя зона ответственности. Один сервис работал со статусами заказов. Другой рассчитывал скидки. Третий - отправлял уведомления. Но когда давление возрастает, границы стираются:
"Этот сервис и так трогает заказы, пусть заодно скидку посчитает."
"А тут недалеко, добавим отправку уведомления прямо сюда."
Архитектура теряет свою модульность. Каждая правка превращается в потенциальную цепную реакцию из багов по всей системе, тестирование становится дорогим и медленным. И когда-нибудь при попытке исправить одну бизнес-функцию все вдруг начнёт падать в трёх соседних подсистемах. Печально? Безусловно. Реально? Все так же безусловно.
Кейс:
Изначально сервис статусов заказов отвечал только за смену состояний: от "нового" до "доставленного". Чёткая и простая логика.Но со временем начали прилетать "маленькие" улучшения: сначала попросили, чтобы сервис сам рассчитывал скидку перед подтверждением статуса. Потом чтобы он заодно проверял оплату. Потом чтобы сразу отправлял уведомление клиенту о смене статуса.
Каждое изменение казалось безобидным: “плюс одна функция, всё равно в этом потоке работаем”.
Когда встал вопрос о разделении обязанностей, выяснилось, что зависимости между модулями настолько переплетены, что каждое изменение требовало бы весомых изменений в бизнес-логике. Переписывать с нуля было дешевле и быстрее, чем чинить то, что получилось.
Четвертая стадия: “Технический долг? Оплатим потом!”
На этом этапе команда уже прекрасно понимает, что долг растёт. Рефакторинг и исправление архитектурных ошибок откладываются "на потом". Есть практика проведения технических спринтов, чтобы подобрать все хвосты, но часто ли это делают?
Каждый новый спринт приоритезирует новые хотелки бизнеса. Фичи, фичи и еще фичи! А технический долг все так же продолжает копиться в фоне, как радиация - невидимая, но смертельно опасная:
Увеличивается время на реализацию задач.
Снижается надёжность системы и увеличивается количество багов.
Растет количество взаимных зависимостей.
Технический долг не исчезает сам. Он работает как невидимый налог, который команда платит вечно. И в какой-то момент наступает точка невозврата: проект становится настолько тяжёлым и неповоротливым, что переписать его с нуля дешевле и безопаснее, чем пытаться исправить и вернуть в прежнее русло.
Кейс:
На старте проекта решили не заморачиваться с брокерами: нагрузка была небольшой, сервисов мало. Сделали свою лёгкую шину событий: быстро, просто, без зависимостей.Поначалу всё выглядело идеально: сервисы легко обменивались событиями, не надо было городить очереди, на продакшн всё катилось без лишней инфраструктуры. Разработчики гордились своей "гибкостью и лёгкостью".
Но проект рос. Сервисов становилось больше. Появились параллельные цепочки событий, массовые рассылки, всплески нагрузки. И начали вылезать проблемы: иногда события терялись, иногда приходили в неправильном порядке, иногда сервис просто не успевал обработать пачку входящих вызовов. Отлаживать такие кейсы было почти невозможно.
Все видели, что шина трещит по швам, но каждый раз откладывали миграцию на нормальный брокер. В один момент шина перестала стабильно передавать события.
После этого проект экстренно переехал на полноценный брокер и сдвинул нормальные сроки развития на полгода вперёд.
Что в итоге
Проекты не взрываются из-за одного неправильного решения. Они взрываются из-за уступок. С каждым "пока так сойдёт", с каждым "сначала выпустим, потом подчистим".
Архитектуру убивают не баги и не форс-мажоры. Её убивает слабость команды и неспособность защищать свои принципы перед давлением срочности и очередных невнятных хотелок.
Если вы этого еще не понимаете - добро пожаловать в клуб!
Я веду свой ТГ канал #ЯЖАНАЛИТИК, в котором рассказываю о буднях системного аналитика, околоITшной жизни, описываю кейсы, лайфхаки, рабочие неудачи и все то , что тебе потребуется для работы. Простым и доступным языком. Без нудятины и духоты (ну может быть совсем чуть-чуть).