Рефакторинг в Битрикс: как устроен код под нагрузкой
В 1С-Битрикс рефакторинг — это не только перенос старых функций в D7. Нужно учитывать события, ORM, агентов, кеш и границы модулей, иначе после «улучшения» сайт станет медленнее и сложнее для поддержки.

В 1С-Битрикс рефакторинг часто начинается с безобидной задачи: заменить старый вызов API, вынести обработчик события или убрать дублирование в компоненте. Но один и тот же код в этой CMS проходит через события, модули, ORM, кеш и шаблоны. Если менять только внешний слой, можно получить проект, который формально работает, но делает лишние SQL-запросы, теряет кеширование и ломается после обновления ядра. Ниже — разбор для 1С-Битрикс: Управление сайтом 24.x и близких актуальных веток, без привязки к конкретной редакции лицензии.
Почему рефакторинг в Битрикс нельзя свести к «переписать на D7»
В старом проекте обычно сосуществуют несколько поколений кода. Рядом с процедурными функциями ядра находятся классы пространства имён Bitrix\, компоненты, обработчики событий и собственные модули. Это не просто разный синтаксис. У каждого слоя свои точки расширения и свои риски.
- Процедурный API часто скрывает побочные эффекты: загрузку модулей, работу с глобальными объектами и неочевидные запросы.
- D7 даёт классы модулей, ORM, сервисы и более явные зависимости, но не превращает старую бизнес-логику в безопасную автоматически.
- Компонент отвечает не только за PHP-код. Его результат зависит от параметров, кеша, шаблона и режима AJAX.
- События связывают независимые части системы. Изменение порядка или места подключения обработчика может изменить поведение каталога, заказа или авторизации.
- Агенты выполняют отложенные задачи, но их запуск зависит от настроек сайта и способа обработки cron или хитом.
Поэтому цель рефакторинга — не заменить все старые вызовы на новые классы. Цель — сделать поток данных явным, уменьшить число скрытых зависимостей и сохранить контракт, на который рассчитывают компоненты и модули.
В Битрикс безопасный рефакторинг меняет место и способ принятия решения, но не ломает события, кеш и формат данных, от которых зависят соседние модули.
Как проходит запрос через типичный проект
Упрощённая цепочка выглядит так: точка входа сайта загружает ядро, определяется текущий раздел, подключается компонент, компонент вызывает код модуля или ORM, затем формируется результат и применяется шаблон. На каждом этапе могут сработать обработчики событий, проверки прав, правила кеширования и отложенные операции.
Точка входа и окружение
Публичная страница обычно попадает в Битрикс через файл раздела, компонент или контроллер. До выполнения бизнес-логики уже могут быть подключены настройки сайта, группы пользователей, модули и события. Код, который напрямую обращается к глобальным переменным или рассчитывает на порядок подключения, трудно переносить в другое место.
При рефакторинге сначала зафиксируйте, какие данные приходят в функцию и что она возвращает. Если метод одновременно читает глобальный объект пользователя, ищет товар, меняет корзину и пишет в лог, его нельзя безопасно улучшить одним переименованием. Сначала разделите чтение, принятие решения и запись.
Компонент и его кеш
Компонент в Битрикс — это не обычный контроллер. Его параметры, результат и шаблон образуют связку. Перенос запроса из компонента в отдельный класс может изменить время жизни данных: раньше результат попадал в кеш компонента, а после рефакторинга запрос начинает выполняться на каждом обращении.
Проверяйте как минимум четыре режима: неавторизованный пользователь, авторизованный пользователь, отключённый кеш и AJAX-вызов. Отдельно смотрите страницы с разными группами и региональными настройками. Если ключ кеша не учитывает параметр, результат одного пользователя или раздела может быть показан другому.
Модуль, событие и ORM
Собственный модуль стоит использовать как границу бизнес-логики: компонент получает входные параметры и отображает результат, а модуль решает, как читать и изменять данные. D7 ORM помогает описать выборку через таблицы и сущности, но не отменяет необходимость проверять SQL, индексы, фильтры и количество возвращаемых строк.
Событие добавляет ещё одну зависимость. Обработчик может изменить объект до сохранения, отменить операцию или запустить дополнительную запись. Перед переносом логики найдите все регистрации события и проверьте, не вызывается ли тот же код из административной части, агента, обмена или очереди.
Сноска. D7 — набор объектных API 1С-Битрикс, куда входят пространства имён модулей, ORM и связанные сервисы. Это не отдельный фреймворк, который можно включить вместо всего старого API.
Что проверять в рефакторинге: четыре слоя риска
| Слой | Что меняется при неосторожной правке | Что измерять и проверять |
|---|---|---|
| Данные | Лишние выборки, другой порядок сортировки, потеря фильтра | SQL-запросы, план выполнения, число строк, индексы |
| События | Двойной запуск обработчика или пропуск проверки | Порядок вызовов, аргументы, ошибки, повторяемость операции |
| Кеш | Постоянные запросы к базе или устаревший результат | Попадания и промахи кеша, состав ключа, время генерации |
| Интеграции | Нарушение обмена, уведомлений или фоновых задач | Логи, формат данных, повторный запуск, идемпотентность |
Идемпотентность означает, что повторный запуск одной операции не создаёт второй заказ, дубль записи или повторную отправку уведомления. Для агентов, вебхуков и обработчиков событий это критично: повторный запуск после тайм-аута вполне реален.
Как разбирать участок перед изменением
- Зафиксируйте внешний контракт. Запишите входные параметры, возвращаемый результат, права пользователя, события и побочные эффекты. Для компонента добавьте параметры кеша и шаблон.
- Найдите все точки вызова. Ищите не только имя функции или класса, но и регистрацию событий, подключение компонента, агентов, CLI-скрипты и административные страницы. Один обработчик может использоваться за пределами публичного сайта.
- Снимите базовые показатели. Зафиксируйте время ответа, число SQL-запросов, общее время SQL, объём ответа и частоту ошибок. Для страницы с кешем измеряйте холодный и тёплый запрос отдельно.
- Отделите чтение от записи. Запросы, изменение сущностей, отправку уведомлений и логирование не должны быть спрятаны в одном методе без явного порядка.
- Сделайте маленький перенос. Сначала вынесите один сценарий в класс или метод модуля, сохранив входные данные и результат. Большая миграция без промежуточной проверки не показывает, на каком шаге появилась ошибка.
- Сравните поведение. Проверьте гостя и авторизованного пользователя, разные сайты и языки, пустой результат, отсутствие прав, повторный вызов и отключённый кеш.
- Проверьте обновление и откат. Изменения должны лежать вне файлов ядра. Перед релизом подготовьте обратную миграцию данных, если меняется схема или формат сохранённых значений.
Что ломается первым
Запрос в цикле компонента
Классический дефект появляется, когда список элементов загружается одним запросом, а для каждого элемента отдельно читаются свойства, остатки или цены. На небольшом каталоге это незаметно. На странице с сотнями строк число обращений к базе растёт вместе со списком.
Проверяйте не только количество вызовов ORM, но и фактический SQL. Объединённая выборка не всегда быстрее: сложные соединения могут создать дубликаты строк или тяжёлый план. Сравнивайте запросы на данных, похожих на продакшен, а не на десяти тестовых товарах.
Событие, которое меняет данные повторно
Обработчик сохранения может сам вызвать сохранение той же сущности или обновить связанный объект, который снова запускает цепочку событий. Итог — дублирование, рекурсия или несколько одинаковых записей в журнале.
Для каждого обработчика укажите условие входа и признак уже выполненной операции. Не используйте глобальный флаг как универсальное решение: он может вести себя непредсказуемо при долгоживущем процессе или параллельных задачах. Лучше сделать операцию явной и проверить уникальные ограничения на уровне базы, когда это уместно.
Потеря кеша после выноса логики
Если старый компонент кешировал готовый результат, а новый сервис вызывается из шаблона или обработчика без кеширования, нагрузка на базу вырастет даже при неизменном интерфейсе страницы. Обратная проблема опаснее: кеш может не учитывать идентификатор пользователя, группу, сайт или фильтр.
Как измерять эффект, если готовых замеров нет
Не подставляйте универсальные цифры: результат зависит от версии PHP, конфигурации Битрикс, СУБД, объёма каталога, кеша и диска. Для сравнения используйте один и тот же стенд, одинаковый набор данных и одинаковый сценарий.
- снимите несколько холодных и тёплых запросов, а не один случайный прогон;
- запишите p50 и p95 времени ответа, если есть инструмент нагрузочного тестирования;
- сравните количество SQL-запросов и суммарное время SQL;
- проверьте ошибки PHP, исключения ORM и записи в системном журнале;
- посмотрите, не изменилось ли число вызовов внешних сервисов и фоновых задач.
Для продакшена важнее не только среднее время. Рост p95, очереди агентов, блокировки базы и промахи кеша часто показывают проблему раньше, чем жалобы пользователей.
Где такой подход ломается
Маленький перенос логики в собственный класс не решит проблему, если источник нагрузки находится в архитектуре: компонент строит отчёт по миллионам строк, обмен запускает полную синхронизацию, а агент обрабатывает все записи за один проход. В таких случаях нужны отдельные решения — пакетная обработка, индексы, очередь или пересмотр модели данных. Инвалидация кеша — тоже самостоятельная тема: здесь важно лишь не потерять её при переносе.
Есть и организационный предел. Если проект не имеет тестовой копии, журналов и воспроизводимого сценария, крупный рефакторинг превращается в проверку на пользователях. Сначала создайте минимальный контур наблюдаемости, затем меняйте код.
Что делать дальше
Выберите один медленный или часто изменяемый сценарий: страницу каталога, оформление заказа или обработчик импорта. Нарисуйте его цепочку от входа до записи в базу, зафиксируйте SQL и кеш, затем вынесите только один участок в модульный класс. После релиза смотрите p95 ответа, число SQL-запросов, ошибки обработчиков и очередь агентов. Если показатели не изменились или стали хуже, откатывайте правку и ищите следующий участок цепочки, а не добавляйте ещё один слой абстракции.
Агент-продажник: Скрипты B2B-продаж, обработка возражений по BANT и SPIN.
Спросить за 20 ₽Источники: Документация разработчика 1С-Битрикс: D7, Документация разработчика 1С-Битрикс: события
Частые вопросы
Нужно ли переписывать весь старый код Битрикс на D7?
Как понять, что рефакторинг действительно ускорил сайт?
Может ли рефакторинг сломать обработчик события?
Почему после выноса кода в класс страница стала медленнее?
Что делать, если после обновления Битрикс поведение изменилось?
Нужно ли начинать рефакторинг с создания собственного модуля?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.