Когда существующий Laravel-проект нужно переписывать, а когда достаточно привести его в порядок

Старый Laravel-проект часто выглядит хуже, чем работает.

Разработчик открывает код и видит контроллеры на сотни строк, устаревшие зависимости, практически полное отсутствие тестов и непонятные связи между модулями. Первая реакция довольно предсказуема: «Это проще переписать с нуля».

Но для бизнеса такое решение может оказаться самым дорогим вариантом.

Мы поговорили с Laravel-разработчиком о том, когда проект действительно пора переписывать, а когда правильнее не устраивать большую революцию, а постепенно привести существующую систему в порядок.

О чём разговор

Формат
Интервью, ~20 вопросов
Тема
Legacy-код, технический долг, рефакторинг и переписывание Laravel-проекта
Для кого
Владельцы бизнеса и руководители, которые решают, что делать со старым Laravel-проектом
Связанные материалы
граница между CMS и бизнес-системой · критерии автоматизации процессов

Начнём с неприятного вопроса. Если разработчик первым делом говорит: «Это нужно переписать», стоит насторожиться?

Да.

Не потому, что переписывать проекты никогда не нужно. Иногда это действительно единственный разумный вариант.

Проблема в другом: переписывание с нуля очень легко предложить и очень сложно правильно обосновать.

Для нового разработчика существующий проект почти всегда кажется неудобным. Он написан другим человеком, в другом стиле, с другими архитектурными решениями.

Гораздо приятнее создать:

  • новую структуру проекта;
  • красивые сервисные классы;
  • свежие зависимости;
  • понятные модели;
  • современный frontend;
  • аккуратную архитектуру.

Но бизнесу платят не за красоту архитектуры.

Бизнесу нужно, чтобы:

  • заказы продолжали поступать;
  • менеджеры могли работать;
  • интеграции не ломались;
  • данные не терялись;
  • новые функции можно было добавлять;
  • стоимость поддержки оставалась разумной.

Поэтому вопрос должен звучать не «нравится ли разработчику этот код?», а «мешает ли состояние системы развитию бизнеса?»

А что вообще считать legacy-кодом?

Legacy часто ошибочно переводят как «плохой код».

Это не совсем правильно.

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

Она может работать пять или десять лет.

В ней могут быть:

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

Сам по себе возраст проекта ещё ничего не говорит.

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

То есть старую версию Laravel можно вообще не трогать?

Можно. Но нужно понимать последствия.

Если проект работает на старой версии Laravel и бизнесу в ближайшие годы не понадобится серьёзное развитие системы, иногда разумнее оставить всё как есть.

Но со временем появляются проблемы:

  • PHP обновляется;
  • серверное окружение меняется;
  • старые зависимости перестают поддерживаться;
  • появляются известные уязвимости;
  • новые библиотеки требуют более свежих версий;
  • найти разработчика, который хочет работать со старым стеком, становится сложнее.

Поэтому обновление лучше рассматривать не как косметическую процедуру, а как управление техническим риском.

Не обязательно срочно обновлять проект при каждом новом релизе Laravel.

Но если проект отстал на несколько крупных версий, стоимость следующего обновления обычно начинает быстро расти.

Хорошо. Проект работает. Зачем вообще трогать код?

Если он действительно работает и его не нужно развивать — возможно, трогать его вообще не нужно.

Проблемы начинаются, когда бизнес хочет добавить что-то новое.

Например:

  • новый личный кабинет;
  • другую систему оплаты;
  • интеграцию с CRM;
  • новые роли пользователей;
  • API;
  • автоматическую обработку заказов;
  • новые отчёты;
  • интеграцию с учётной системой.

И внезапно задача, которая в нормальном проекте должна занимать несколько дней, начинает занимать несколько недель.

Почему?

Потому что любое изменение затрагивает пять других частей системы.

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

Какие признаки говорят, что проект пора сначала привести в порядок?

Я бы смотрел не на отдельные некрасивые участки кода, а на повторяющиеся симптомы.

Например:

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

Особенно показателен один симптом:

простая функция начинает стоить слишком дорого.

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

Но тестов нет почти в половине старых проектов. Это уже повод всё переписывать?

Нет.

Отсутствие тестов — серьёзная проблема, но не повод автоматически выбрасывать рабочий проект.

Более того, переписывать систему без тестов особенно опасно.

Потому что старая система содержит огромное количество неочевидных правил.

Например:

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

Этого правила может не быть ни в техническом задании, ни в документации.

Оно просто существует в коде уже пять лет.

Когда систему переписывают, такие детали очень легко потерять.

Поэтому перед серьёзным рефакторингом я предпочитаю сначала поставить защиту вокруг наиболее важной бизнес-логики:

  • тесты ключевых сценариев;
  • журналирование;
  • мониторинг ошибок;
  • резервные копии;
  • проверку критичных интеграций.

После этого можно менять внутреннее устройство системы намного спокойнее.

То есть вы предлагаете писать тесты на плохой код?

Да.

Тесты нужны не для того, чтобы подтвердить, что код красивый.

Они нужны, чтобы зафиксировать текущее поведение системы.

Это особенно важно перед рефакторингом.

Сначала мы определяем:

«Вот это система делает сейчас».

Затем меняем внутреннюю реализацию.

После изменений проверяем:

«Она всё ещё делает то же самое?»

Без этого рефакторинг превращается в довольно рискованный эксперимент.

А что такое постепенный рефакторинг на практике? Разработчики будут год приводить код в порядок?

Если поставить задачу «сделать архитектуру идеальной», проект действительно можно улучшать бесконечно.

Я предпочитаю другой подход.

Мы не переписываем весь проект сразу.

Сначала определяем участки, которые:

  • чаще всего изменяются;
  • чаще всего ломаются;
  • тормозят разработку;
  • содержат критическую бизнес-логику;
  • мешают будущим задачам.

И работаем именно с ними.

Допустим, компания планирует серьёзно развивать модуль заказов.

Нет необходимости сначала переделывать каталог, новости, административную панель и ещё двадцать разделов.

Можно привести в порядок именно цепочку:

Корзина → заказ → оплата → склад → уведомления.

После этого новые функции вокруг заказов уже будет значительно проще добавлять.

Но разве не получится ещё больший бардак? Половина проекта новая, половина старая.

На определённом этапе — да.

И это нормально.

Практически любой большой проект состоит из кода разного возраста.

Главное, чтобы была понятная граница между старой и новой логикой.

Например, старый модуль можно постепенно изолировать через:

  • сервисный слой;
  • интерфейсы;
  • адаптеры;
  • отдельные модули;
  • API;
  • очереди;
  • события.

Таким образом новые части системы уже строятся нормально, а старая логика продолжает работать до момента, когда её станет разумно заменить.

Это намного безопаснее, чем пытаться одновременно переделать всю систему.

Давайте всё-таки определим: когда переписывание действительно оправдано?

Есть ситуации, когда постепенный рефакторинг действительно может оказаться дороже.

Например, если изменился сам смысл продукта.

Допустим, раньше система была небольшим каталогом с формой заказа.

Через несколько лет бизнес хочет превратить её в полноценную платформу с:

  • организациями;
  • пользователями;
  • ролями;
  • сложными правами доступа;
  • API;
  • интеграциями;
  • автоматическими процессами;
  • десятками внутренних модулей.

Получается, что новая система концептуально почти не имеет отношения к старой.

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

Какие ещё причины могут быть у полного переписывания?

Я бы рассматривал такой вариант, когда совпадают сразу несколько факторов:

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

Но даже тогда я бы очень осторожно относился к формулировке:

«Сейчас выключим старую систему и запустим новую».

Для крупного рабочего проекта это один из самых рискованных сценариев.

Почему переписывание с нуля так часто затягивается?

Потому что разработчики обычно оценивают код.

А нужно оценивать поведение системы.

Пусть в проекте условно 100 000 строк кода.

Разработчик смотрит и думает:

«Я напишу то же самое значительно компактнее».

И, возможно, действительно напишет.

Только потом выясняется, что старая система за годы накопила сотни маленьких правил:

  • исключения;
  • специальные статусы;
  • нестандартные скидки;
  • ограничения;
  • права пользователей;
  • старые интеграции;
  • ручные операции;
  • странные, но важные сценарии.

И всё это нужно сначала обнаружить, описать и воспроизвести.

Поэтому при переписывании главная проблема обычно не написание нового кода. Главная проблема — понять всё, что на самом деле делает старый проект.

Как тогда безопаснее переписывать большую систему?

Постепенно.

Например, сначала новая система начинает отвечать только за один процесс.

Допустим, за заказы.

Старый проект продолжает обслуживать:

  • каталог;
  • пользователей;
  • административную часть;
  • контент.

А новый модуль уже принимает и обрабатывает заказы.

Позже переносится следующая часть.

Так бизнес продолжает работать, а команда постепенно уменьшает зависимость от старой системы.

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

А что делать, если исходный разработчик исчез, документации нет, а код никто не понимает?

Это очень распространённая ситуация.

Я бы не начинал с изменений.

Сначала нужно провести техническое обследование проекта.

Посмотреть:

  • версию Laravel и PHP;
  • зависимости;
  • структуру базы данных;
  • фоновые задачи;
  • очереди;
  • cron-задачи;
  • интеграции;
  • файловое хранилище;
  • отправку почты и сообщений;
  • авторизацию;
  • роли пользователей;
  • основные бизнес-процессы;
  • серверное окружение;
  • резервное копирование.

После этого полезно отдельно восстановить карту ключевых процессов.

Например:

Заказ создан → оплата → резерв → уведомление менеджеру → изменение статуса → отправка клиенту.

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

Насколько вообще опасно принимать чужой Laravel-проект на поддержку?

Опасен не чужой код.

Опасно состояние, которое никто не понимает.

Перед серьёзными изменениями я бы обязательно проверил:

  • есть ли доступ к репозиторию;
  • можно ли поднять копию проекта отдельно от production;
  • существует ли актуальная резервная копия;
  • можно ли восстановить её;
  • где хранятся секреты и ключи;
  • какие внешние сервисы используются;
  • что выполняется автоматически;
  • как отслеживаются ошибки.

Особенно важен вопрос резервного копирования.

Фраза:

«У нас вроде сервер делает backup»

для рабочего бизнеса меня обычно не успокаивает.

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

Самый неудобный вопрос: почему разработчики вообще доводят проекты до такого состояния?

Потому что технический долг возникает не только из-за плохих разработчиков.

Очень часто проект развивается примерно так:

«Нужно сделать быстро».

Потом:

«Сейчас запустим, а после релиза нормально переделаем».

После релиза появляется следующая задача.

Потом ещё одна.

Через два года временное решение уже является центральной частью системы.

Бизнес в этот момент тоже можно понять.

Когда есть выбор между:

А. Потратить неделю на внутренний рефакторинг

и

Б. За неделю запустить функцию, которая принесёт деньги

обычно выбирают вариант Б.

Проблема начинается, когда вариант Б выбирают двадцать раз подряд.

Значит, технический долг — это нормально?

Да.

У проекта без технического долга есть два возможных объяснения:

  • проект очень молодой;
  • в нём почти ничего не происходит.

Задача не в том, чтобы полностью уничтожить технический долг.

Задача — контролировать его стоимость.

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

А если другой модуль изменяют каждую неделю и каждое изменение вызывает проблемы — туда имеет смысл инвестировать время.

Как владельцу бизнеса понять, что разработчик предлагает рефакторинг не ради рефакторинга?

Нужно попросить объяснить проблему без терминов.

Не:

«Здесь нарушены SOLID и DDD».

А:

«Из-за текущей структуры изменение одного типа заказа требует правок в шести местах. Поэтому задача занимает три дня вместо одного и увеличивается риск ошибки».

Хорошее техническое решение должно иметь понятное практическое объяснение.

Например:

  • уменьшить количество ошибок;
  • ускорить выпуск функций;
  • упростить обновление проекта;
  • убрать зависимость от устаревшей библиотеки;
  • подготовить систему к новой интеграции;
  • сделать критическую логику тестируемой.

Если объяснить пользу невозможно, возможно, изменение действительно не является необходимым.

Можно ли вообще привести очень плохой Laravel-проект в нормальное состояние без полной остановки разработки?

Чаще всего — да.

Обычно процесс выглядит не как один большой рефакторинг, а как серия небольших изменений:

Сначала

стабилизируем инфраструктуру и резервные копии.

Затем

разбираемся с наиболее опасными зависимостями.

После этого

добавляем тесты для критичных процессов.

Далее

постепенно выносим бизнес-логику из самых проблемных участков.

И уже потом

обновляем архитектуру там, где это действительно необходимо.

При этом обычная разработка может продолжаться.

Если сформулировать совсем коротко: переписывать или ремонтировать?

Я бы сначала исходил из того, что рабочую систему лучше сохранить.

Переписывание должно быть результатом анализа, а не первой реакцией на неприятный код.

Если система выполняет свою задачу, а основные проблемы можно постепенно изолировать и устранить — чаще разумнее рефакторить.

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

Самое важное — не ставить задачу:

«Сделайте нам красивый код».

Лучше задать другой вопрос:

«Что сейчас мешает этому проекту безопасно развиваться и сколько стоит устранить эти ограничения?»

Ответ на него обычно гораздо полезнее для бизнеса.

Вместо вывода

Старый Laravel-проект не обязательно нужно переписывать.

Часто достаточно:

  • провести технический аудит;
  • определить самые проблемные участки;
  • обновить критические зависимости;
  • добавить тесты для важных процессов;
  • постепенно разделить бизнес-логику;
  • стабилизировать интеграции;
  • настроить журналирование и мониторинг;
  • поэтапно рефакторить систему вместе с обычной разработкой.

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

Во всех остальных случаях аккуратная модернизация существующего проекта часто оказывается быстрее, дешевле и безопаснее.

Обсудить проект

Нужен похожий контур — обсудим. Услуги на Laravel.

Связаться

Связанные материалы

кейсы внедрённых проектов · система заказов кухонь на заказ · AI-автоматизация бизнеса