D7 ORM против старого API: как безболезненно мигрировать legacy-код Битрикс24
Строки GetList(), Add() и CIBlockElement всё ещё кормят тысячи коробочных Битрикс24. Код работает, но разработчики боятся в него лезть, а каждый новый разработчик задаёт один и тот же вопрос: «а почему не D7?». Плавный переход с legacy-кода на D7 ORM — это не про «переписать всё за раз», а про выгоду, которую можно получать инкрементально, без остановки портала. В этой статье разбираем, почему D7 orm Битрикс24 стал стандартом качества, где старый API ещё оправдан и как мигрировать без инцидентов.
Писать будем для тех, кто принимает решения: CTO, тимлидов и ведущих разработчиков, которым нужны не абстрактные «лучшие практики», а цифры, риски и последовательность действий.
Материал основан на реальных проектах нашей команды: в одном из них мы за четыре месяца перевели на D7-ORM пять самых «горячих» модулей портала на 1 200 пользователей — без единого окна простоя. Ниже — пошаговая методика, типичные ошибки и примеры «до/после» с замерами.
Содержание
- Чем D7 лучше GetList: сравнение подходов
- Почему вообще стоит мигрировать
- Типичные ошибки при переходе на D7 ORM
- Поэтапный рефакторинг без остановки портала
- Примеры «до/после» с замерами
- Как тестировать и мониторить миграцию
- Вывод
- FAQ
Чем D7 лучше GetList: сравнение подходов
Старый API — это процедурные функции, строковые поля и магия в префиксах (ACTIVE_DATE, !ID). D7 — объектный слой поверх тех же таблиц: сущности (DataManager), типизированные поля, чейнинг запросов и единая точка контроля.
| Критерий | Старый API (GetList / CIBlockElement) | D7 ORM (Entity / DataManager) |
|---|---|---|
| Типизация | Строковые ключи массива, легко опечататься | Строгие классы полей, автодополнение в IDE |
| Кеширование | Ручное через nPageSize/кеш-бэкенд, непоследовательно | Единый кеш через табличные классы, правила в одном месте |
| Запросы | Фильтр-массивы без композиции | Чейнинг: select→where→order→limit→fetch |
| События и расширяемость | Глобальные хуки с строковыми именами | Классовые события и валидация на уровне сущности |
| Совместимость | Deprecated-ветки, поведение меняется между версиями | Стабильный контракт, покрыт документацией 1С-Битрикс |
Практический выигрыш — скорость разработки и сопровождаемость: в нашем опыте новый разработчик начинает править D7-код в два-три раза быстрее, чем legacy-модуль.
Отдельный плюс — предсказуемость запросов. В GetList легко незаметно получить выборку со всеми свойствами и макросами; в D7 вы явно указываете, что читаете, и это видно в код-ревью, а не в slow query log.
Почему вообще стоит мигрировать
Три аргумента, которые слышит CTO:
- Производительность. Табличный кеш D7 и отказ от избыточных JOIN позволяют ускорить типовые выборки на 30–60% — замер ниже.
- Обновляемость. Строки старого API всё чаще помечаются deprecated; на новых версиях коробки часть сценариев ломается тихо.
- Найм и онбординг. Рынок знает D7; костыли из 2012 года — нет.
Когда мигрировать не стоит
Честности ради: если модуль три года никто не трогает, а бизнес планирует переход в облако — силы лучше бросить на миграцию платформы (мы делаем и это), а не на косметику кода, который скоро уйдёт в архив. Решение всегда принимаем от ценности модуля для бизнеса.
Если портал растёт и нуждается в кастомных модулях, посмотрите на услугу разработки модулей — там где речь про сопровождение, D7 считаем обязательным стандартом.
Типичные ошибки при переходе на D7 ORM
Переписать «всё и сразу»
Самый частый сценарий провала. Монолитный рефакторинг ветвится, тестовый покрытия нет, и через шесть недель код замораживают «до лучших времён». Решение — вертикальные срезы по модулям, а не горизонтальный «большой взрыв».
Игнорировать семантику фильтров
В старом API пустое значение в фильтре часто «проглатывается»; в D7 пустая строка — валидное значение и попадёт в WHERE. Не проверив 10-критерийные фильтры, вы получите выборки, «случайно» расширившиеся на все записи.
Потерять «магию» макросов
PROPERTY_123 и IBLOCK_ID из старого API не мигрируют один-в-один. Свойства инфоблоков в D7 живут в отдельных сущностях — их нужно явно джойнить, иначе выборка молча вернёт пустые поля.
Забыть про события и права доступа
Старые обработчики OnAfterIBlockElementAdd срабатывают даже при записи через новый API, а вот кастомные хуки модуля — нет. Карту событий проверяем до, а не после релиза.
Поэтапный рефакторинг без остановки портала
Методика, отработанная на миграциях коробочного Битрикс24 (см. внедрение коробочной версии):
- Инвентаризация. Ищем все вызовы GetList/Add/Update по проекту, классифицируем: готовое ядро / аналог в D7 / нужна своя таблица.
- Выбираем пилот. Один модуль с высоким трафиком чтения и низким — записи.
- Пишем параллельный слой. Новые методы на ORM, старые помечаем
@deprecated, но не удаляем. - Сравнительный прогон. Включаем теневой режим: результаты старого и нового кода сравниваются и логируются на расхождения.
- Переключение и наблюдение. Меняем вызов в конфиге/фиче-тогле, держим 1–2 недели релиз-мониторинга.
- Удаление legacy. Следующий релизный цикл, после подтверждения стабильности.
Ключевой приём — feature toggle: одна константа или настройка модуля откатывает поведение за минуту, без реверта кода.
Из практики: на портале с 1 200 пользователей мы переводили отчётный модуль по ночам, включая новый слой на 10% трафика, потом на 50%, и только потом полностью. Весь переход занял три недели, пользователи ничего не заметили.
Примеры «до/после» с замерами
Выборка 5 000 элементов инфоблока с двумя свойствами, коробка на PHP 8.2, MySQL 8:
// Было: старый API
$res = CIBlockElement::GetList(
['DATE_CREATE' => 'DESC'],
['IBLOCK_ID' => 14, 'ACTIVE' => 'Y'],
false, ['nTopCount' => 5000]
);
while ($el = $res->GetNext()) { /* ... */ }
// Стало: D7 ORM
use Bitrix\Iblock\Elements\ElementDealsTable;
$rows = ElementDealsTable::query()
->setSelect(['ID', 'NAME', 'DATE_CREATE'])
->addFilter('ACTIVE', 'Y')
->setOrder(['DATE_CREATE' => 'DESC'])
->setLimit(5000)
->fetchAll();
Замеры на тестовом контуре с прогревом кеша:
- Замер кода «до»: 1 240 мс среднее из 100 прогонов.
- Замер кода «после»: 610 мс среднее, кеш-хит — 90 мс.
В одном из наших проектов аналогичный перевод шести отчётов снизил нагрузку на базу на 40% и убрал таймауты в часы пиковых отчётов.
Что меняется для записи
// Старый API: добавление элемента
$el = new CIBlockElement();
$id = $el->Add($fields); // false при ошибке, текст в $el->LAST_ERROR
// D7: явный результат и валидация
$result = ElementDealsTable::add($fields);
if (!$result->isSuccess()) {
$errors = $result->getErrorMessages();
}
Главное здесь не скорость, а контроль: ошибки возвращаются объектом, валидация описывается в классе сущности, а поведение не зависит от побочных эффектов глобальных переменных.
Как тестировать и мониторить миграцию
Миграция — это фактически замена движка на лету, поэтому тестирование здесь важнее самого рефакторинга. Минимальный набор:
Чек-лист перед каждым переключением модуля:
- Юнит-тесты на оба набора фильтров: граничные значения, пустые строки, UTF-8-символы.
- Сравнение результатов старого и нового кода на продовой выгрузке данных (по 10 000 записей на сущность).
- Проверка прав доступа: выборка «под сотрудником», «под админом», «аноним».
- Логи slow query включены на время пилота.
- План отката: фиче-тогл и сохранённый legacy-код до конца релизного цикла.
На длинных миграциях полезно смотреть в смежные темы производительности — например, оптимизацию MySQL под Битрикс24, чтобы ORM-слой не маскировал проблемы схемы базы.
После переключения держим «неделю тишины»: алерт на slow query, ошибки PHP и расхождения в сверочных логах. Только после неё переходим к чистке legacy-кода.
Сохраняем артефакты каждого этапа: список переведённых вызовов, замеры до/после и решения по спорным местам — через полгода они станут инструкцией для следующих релизов.
Вывод
- D7 orm Битрикс24 — это зрелый стандарт: типизация, кеширование и сопровождаемость выигрывают у GetList почти по всем критериям.
- Мигрировать нужно вертикальными срезами модулями, с теневым прогоном и фиче-тоглом — остановка портала недопустима.
- Типовые ловушки: семантика пустых фильтров, свойства инфоблоков, события — проверяются на пилоте, а не на проде.
- Ожидаемый эффект от перевода «горячих» выборок — ускорение в 1,5–2 раза и снижение нагрузки на MySQL на 30–40% в реальных проектах.
- Устаревший код удаляем только после релизного цикла стабильной работы нового слоя.
Если в вашем портале накопилось legacy, которое тормозит развитие, напишите нам — проведём аудит модулей и предложим план миграции с оценкой по этапам.
FAQ
Обязательно ли переписывать всё на D7 ORM?
Нет. Правильный критерий — частота изменений и нагрузка модуля. Стабильный код в глубоком бэкофисе можно оставить как есть, а вот CRM-интеграции, отчёты и обмены с 1С переводить в первую очередь.
Старый API перестанут поддерживать в коробке?
Формально он объявлен legacy ещё несколько мажорных версий назад. 1С-Битрикс сохраняет обратную совместимость, но новые возможности (события, валидация, производительность) появляются в D7, а в старом слое фиксируются только баги.
Что делать, если модуль тесно завязан на старые события?
Оставляем обработчики на месте: D7-записи через таблицы инфоблоков по-прежнему дергают OnAfterIBlockElementAdd. Кастомные хуки переносим на классовые события по мере перевода модуля.
Как выбрать, с какого модуля начинать?
Двумерная матрица: частота изменений кода × количество обращений к данным. Берём верхний правый квадрант — например, отчёты и виджеты CRM, которые читают инфоблоки на каждой странице карточки. Быстрый выигрыш там мотивирует команду и даёт измеримый аргумент для продолжения миграции перед руководством.
Сколько занимает такая миграция?
В наших проектах: пилотный модуль — 2–3 недели, портал со 100–200 кастомными вызовами GetList — 3–5 месяцев поэтапно. Точная оценка — после инвентаризации, которую делаем за 3–5 дней.
Можно ли использовать D7 в облачном Битрикс24?
Нет, D7-разработка — прерогатива коробочной версии, где есть доступ к файловой системе и собственным модулям. В облаке кастомизация идёт через REST и локальные приложения; для таких задач смотрите внедрение облачного портала. Если вы на коробке и думаете о переезде — вопрос миграции кода встанет отдельно.
bitrix