Рефакторинг легаси: как не сломать то, что работает

19.06.2026 · 7 мин

Руки печатают на клавиатуре крупным планом

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

Первое правило: сначала понять, потом менять

Соблазн сразу начать переписывать код, который выглядит плохо, очень велик. Но за уродливым на первый взгляд кодом почти всегда стоит история — часто это накопленные исправления реальных багов и обработка граничных случаев, которые не видны из чтения кода поверхностно. Прежде чем менять что-то, я потратил неделю просто на чтение: git blame по ключевым файлам, старые тикеты, связанные с этим кодом, комментарии в коммитах.

Одна строчка кода, которая выглядела как явная ошибка — округление суммы вниз вместо математического округления — оказалась намеренным решением из-за требований бухгалтерского учёта. Если бы я «исправил» её без понимания контекста, это привело бы к реальному финансовому расхождению.

Второе правило: тесты раньше рефакторинга, не после

Без единого теста трогать код оплаты страшно по делу — любое изменение можно случайно что-то сломать, и узнать об этом только после того, как деньги спишутся неправильно. Прежде чем менять хоть одну строчку, я написал характеризационные тесты (characterization tests) — тесты, которые фиксируют текущее поведение системы как есть, включая её странности, а не то, каким это поведение «должно быть».

Эти тесты не проверяют, что код правильный. Они проверяют, что после рефакторинга код делает то же самое, что и до него. Это принципиально разные вещи, и для легаси без документации второе куда важнее на первом этапе.

Третье правило: маленькие шаги, каждый — рабочая версия

Я разбил рефакторинг на цепочку маленьких изменений, каждое из которых можно было задеплоить отдельно и откатить без последствий, если что-то пойдёт не так. Ни одного «большого взрыва», где переписывается всё и сразу, а результат проверяется только в самом конце. Каждый шаг сопровождался прогоном характеризационных тестов и ручной проверкой на staging-окружении с копией продовых данных.

Что в итоге

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

Главный вывод

Рефакторинг легаси — это не про красоту кода ради самой красоты. Это про снижение риска и стоимости следующего изменения. Если после рефакторинга следующую фичу можно добавить за день вместо недели — рефакторинг оправдал себя, даже если сам код по-прежнему не идеален. Идеальный код — не цель; предсказуемый код, которому можно доверять, — цель.