Рефакторинг legacy-кода без остановки бизнеса
Рефакторинг кода часто откладывают годами: все понимают, что он нужен, но боятся остановить работающий продукт на время переделки. На деле заморозка релизов не обязательна — вот как вести рефакторинг legacy-кода так, чтобы бизнес вообще не заметил, что внутри системы что-то меняется.

Коротко: рефакторинг legacy-кода не требует заморозки релизов — паттерн Strangler Fig позволяет заменять систему по частям, пока старая версия продолжает работать; feature flags и параллельный запуск держат CI/CD живым во время миграции; а правило «сначала зафиксировать поведение, потом улучшать» защищает от потери скрытой бизнес-логики. Бизнес должен не перетерпеть переход, а вовсе его не заметить.
Если в компании раньше любая серьёзная переделка кода означала заморозку фич на месяцы, стоит пересмотреть процесс, а не сам рефакторинг: для этого нужна команда, которая продолжает дорабатывать и поддерживать сайт по частям, не останавливая его работу, а не разовый героический рывок, после которого разработка снова встаёт на паузу до следующего большого релиза.
Дальше — почему переписывание «большим взрывом» регулярно проваливается, как работает паттерн Strangler Fig, что дают feature flags и параллельный запуск, когда подход всё же не оправдан, и кто должен вести такой рефакторинг — внутренняя команда или подрядчик.
Почему «большим переписыванием с нуля» рушит сроки и бизнес
Классический соблазн — остановить изменения в старой системе и несколько месяцев писать версию 2.0 в отдельной ветке. Объём работы здесь не главная проблема — бизнес в это время не ставится на паузу: конкуренты продолжают выпускать фичи, клиенты продолжают присылать заявки, а требования продолжают меняться. К моменту, когда новая версия готова, она либо не покрывает то, что старая система успела накопить за время заморозки, либо отстаёт от рынка на те же месяцы простоя.
Ещё один риск Big Bang-подхода — потеря контекста. Пока одна часть команды полгода пишет новую реализацию в отдельной ветке, другая часть продолжает чинить старую систему, и расхождение между двумя версиями растёт быстрее, чем успевает закрываться. В итоге дата релиза непредсказуема вовсе не из-за сложности кода — просто никто не может оценить объём работы по сведению двух разошедшихся веток.
Strangler Fig Pattern: как заменить систему по частям, не выключая её

Название паттерна пришло из ботаники: Strangler Fig Pattern (фикус-душитель) описывает дерево, которое прорастает вокруг старого ствола и постепенно замещает его, пока опора продолжает стоять. В разработке это означает, что новый код строится рядом со старым за тем же интерфейсом, а не вместо него, и обе версии какое-то время существуют параллельно.
Принцип: новый код оборачивает старый, трафик переключается постепенно
Старый модуль не удаляется в начале работы — он остаётся основным путём для всех запросов, пока новая реализация не докажет, что отдаёт идентичный результат. Это снимает главный источник риска Big Bang-переписывания: откат на любом этапе занимает минуты, потому что старая система никуда не делась.
Прокси/роутинг как точка контроля миграции
Чтобы переключать долю трафика, нужна единая точка, через которую проходят все запросы — API-гейтвей, балансировщик нагрузки или прокси-слой внутри приложения. Именно он решает, какая версия обрабатывает конкретный запрос, и именно его логи дают первый сигнал, если новая реализация ведёт себя иначе, чем старая, прежде чем это увидят пользователи.
Правило «сначала повторить поведение, потом улучшать»
Прежде чем менять внутреннюю логику модуля, нужно зафиксировать, что он делает сейчас — не то, что он должен делать по документации, а то, что он реально возвращает на реальных данных. Такие тесты-характеристики не оценивают правильность поведения, они просто дают эталон для сравнения до и после правки. Подробнее о самой технике и о маленьких обратимых шагах — в материале подробнее о технике безопасного рефакторинга.
Без этого шага Strangler Fig превращается в гадание: новая реализация может отличаться от старой в граничных случаях, которые никто не документировал, и расхождение всплывёт только у реальных пользователей — именно тогда, когда переключение трафика уже не отследить без паники.
Feature flags и параллельный запуск: как релизы продолжают идти во время миграции
Самая частая ошибка — считать, что миграция требует отдельной замороженной ветки, из которой релизы не выходят, пока рефакторинг не закончится. На практике feature flags позволяют держать новый и старый код в одной основной ветке одновременно: флаг включает новую реализацию для части пользователей или процента трафика, а остальная команда продолжает коммитить и деплоить обычные фичи в ту же кодовую базу, не дожидаясь завершения миграции.
Конвейер здесь собирается из трёх элементов: CI/CD продолжает катить привычные деплои несколько раз в день, feature flag решает, какая версия логики активна для конкретного запроса, а мониторинг и логирование сравнивают поведение старой и новой реализации на реальном трафике. Если метрики расходятся, флаг откатывается одной правкой конфигурации — без отката кода и без простоя.
Отдельно стоит вести наблюдаемость именно миграции, а не только общую. Расхождение в бизнес-метрике — например, рост отказов при оформлении заказа у пользователей на новой реализации — должно останавливать выкатку так же быстро, как упавший технический тест, а не оставаться незамеченным до конца недели.
Когда этот подход оправдан, а когда дешевле остановиться и переписать
Strangler Fig хорошо работает, когда старую систему можно логически разделить на модули и подключить прокси, через который проходит трафик. Если архитектура настолько монолитна, что выделить границу модуля невозможно без правки половины кодовой базы, постепенная замена перестаёт быть постепенной — и в этом случае экономика действительно может быть на стороне полного переписывания. Подробный разбор признаков и критериев такого решения — в материале как решить, рефакторить или переписать с нуля.
Короткий ориентир: если команда уже может назвать конкретный модуль, который стоит заменить первым, и объяснить, через какую точку проходит его трафик, подход из этой статьи применим. Если такой точки в принципе не существует, сначала нужно навести архитектурный порядок, а не начинать миграцию.
Кто ведёт рефакторинг без остановки бизнеса — своя команда или подрядчик
Непрерывный рефакторинг требует одновременно инженерной дисциплины — маленьких шагов, тестов-характеристик, feature flags — и организационной: кто-то должен видеть миграцию целиком и принимать решение об откате, не отвлекаясь на текущие тикеты поддержки. Внутренняя команда, которая и так разрывается между багами и новыми фичами, нередко откладывает именно эту работу — не потому что не умеет, а потому что на неё физически не хватает выделенного времени.
Подрядчик с готовым процессом доработки сайтов по частям решает именно эту организационную проблему: приходит не на разовое «переписать всё», а на постоянное сопровождение, где рефакторинг — такая же рабочая задача в бэклоге, как любая новая фича, и выполняется без остановки текущих релизов и без простоя для пользователей.
Частые вопросы
Можно ли полностью избежать риска при рефакторинге legacy-кода на живой системе?
Полностью — нет, но риск сводится к минимуму: Strangler Fig Pattern и feature flags позволяют откатить любой шаг за минуты, потому что старая реализация продолжает работать параллельно с новой до момента полного переключения.
Сколько времени занимает миграция по Strangler Fig Pattern по сравнению с переписыванием с нуля?
Зависит от масштаба модуля: точечная замена одного логического блока обычно занимает несколько недель, а полная миграция крупной системы растягивается на месяцы — но в отличие от переписывания с нуля, релизы и работа бизнеса не останавливаются ни на одном из этих этапов.
Что делать, если тестов на старую систему почти нет?
Начать с тестов-характеристик: они фиксируют реальное поведение системы на реальных данных, а не то, что система «должна» делать по документации. Этого достаточно, чтобы безопасно сравнивать старую и новую реализацию, не дожидаясь полного тестового покрытия.
Нужно ли останавливать деплой новых фич на время рефакторинга?
Нет — именно для этого нужны feature flags: новый и старый код живут в одной ветке, CI/CD продолжает катить обычные релизы, а флаг отдельно решает, какая реализация активна для конкретного пользователя или процента трафика.
Как понять, что пора прекратить рефакторинг и переписать модуль целиком?
Если границу логического модуля невозможно выделить без правки половины кодовой базы, постепенная замена перестаёт быть постепенной. В этом случае экономика может быть на стороне полного переписывания — критерии такого решения разобраны отдельно.
Кто должен принимать решение — своя команда разработки или внешний подрядчик?
Если у внутренней команды нет выделенного времени вести миграцию параллельно с текущими задачами поддержки, разумнее привлечь подрядчика с готовым процессом непрерывного рефакторинга, а внутреннюю команду оставить на приёмке и бизнес-экспертизе.
Как объяснить бизнесу, зачем платить за рефакторинг, если «всё работает»?
Перевести риск в деньги: посчитать, сколько часов команда уже тратит на обходные решения и инциденты в проблемном модуле, и сравнить со стоимостью постепенной замены через Strangler Fig, которая не останавливает текущие продажи и заявки.



