Битрикс без «шелухи»

Максим Лавриненко, директор по информационным технологиям 30.09.2020

Современные сайты все больше похожи на полноценные приложения — больше логики, блоки зависят друг от друга, данные постоянно обновляются (в том числе с сервера) и должны влиять на отображение. В первую очередь это повышает требования к составляющей, которая формирует внешнее представление, — фронтенд. Здесь на помощь приходят фронтенд-фреймворки — React, Vue, Angular и другие. Они переносят формирование шаблонов на клиента (браузер), организуют структурированное хранение данных и автоматическую перерисовку при изменении этих данных. Так как шаблон полностью переходит на клиент, то от сервера требуется передавать только данные. Таким образом, сервер в подобных приложениях выступает в роли API, принимая запросы от клиента и выдавая данные по определённой схеме.

Приспособлен ли Битрикс для работы по такому подходу? Скорее нет, чем да. С одной стороны Битрикс не имеет полноценных инструментов, соответствующих всем современным стандартам, чтобы делать удобные API. С другой стороны никто нам не мешает реализовать эту составляющую без использования Битрикса.

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

Итак, мы уже используем фреймворк, чтобы принимать API-запросы, но где здесь Битрикс? Битрикс появляется там, где нам нужна функциональность его модулей. Опять же, все современные фреймворки имеют в составе контейнер зависимостей, который упрощает разделение ответственности за решение отдельных задач в приложении путём максимально прозрачной возможности «принять» на вход сервиса, который решает свою задачу, его «зависимости» — другие сервисы, которые он использует для решения своей задачи. Битрикс позиционируется в том числе как Bitrix Framework, а любой фреймворк состоит из отдельных частей — модулей, сервисов. К сожалению, Битрикс содержит очень много устаревшего кода, который тяжело напрямую использовать как сервисы в том понимании, в котором они используются в фреймворках. Но это не беда — у нас есть паттерн «фасад», который заставит нас создать «интерфейс» удобный для фреймворка, а внутри будет использовать «неудобное» внутреннее API Битрикса, скрывая его за этим «фасадом».

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

Может ли Битрикс отдавать нам не ассоциативные массивы, а объекты? Причём не те, которые Битрикс сам придумал — «универсальные», а те, которые спроектировали мы сами, задав удобную модель и схему взаимодействия с ней. К сожалению, нет. Вернее, с определёнными оговорками вы сможете добиться этого, если вы забираете данные через D7 с помощью автоматически генерируемых EO_-классов (Класс объекта). Так или иначе, если у вас есть потребность работать со старым API (а это случается часто, т.к. у него нередко больше возможностей, которые нужны), вам придётся прибегнуть к трансформации ассоциативных массивов, которые возвращают эти методы, в объекты. Благо, есть множество готовых решений, специализирующихся на маппинге одних данных в другие. Не забудьте также, что если вам требуется не только считывать, но и обновлять данные, то придётся трансформировать их назад, причём желательно обеспечивать распознавание изменённых данных, чтобы обновлять в базе только те поля, которые изменились. Само обновление, конечно, должно проводится с помощью фреймворка Битрикс, иначе вы сильно рискуете нарушить консистентность данных уже на уровне базы.

Напомню, абзацем выше мы обсудили, что наше API должно возвращать чётко описанные данные и удобно было бы описать их в самом приложении. Не проблема: создаем нужные модели (классы) и прописываем, как модель приложения трансформируется в модель отображения, которую показывает API. Может возникнуть соблазн использовать одну и ту же модель и в приложении и в API, но вы должны удержаться. Это очень важно! Во-первых, вы разделяете слои отображения (модель API) и предметной области (домена, приложения), и в каждом слое она будет максимально оптимально решать свою задачу, не содержать ничего лишнего. Во-вторых, если что-то изменится в модели приложения, вы порой сможете поправить лишь трансформацию данных, а модель отображения оставить без изменений, что позволит вам не менять фронтенд-составляющую. В третьих, крайне часто модель отображения просто не имеет права выдавать некоторые данные, например, поле хешированного пароля. Вы, конечно, всегда можете реализовать отдельный функционал, использующий специальную конфигурацию, которая определяет, какие поля отображать, но это будет неудобно, и, если вы все таки оставите себе возможность у объекта выдать на отображение «все поля», то это всегда риск — в один «прекрасный» день вы добавите в этот объект поле, оно автоматически начнёт передаваться в API, и что-то может пойти не так (раскроются секретные данные, начнёт передаваться существенно больше информации, и это повысит нагрузку и т.п.).

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

Кто-то может сказать — а зачем здесь вообще Битрикс? Все зависит от ситуации. Битрикс действительно даёт очень много готового функционала, даже на уровне его использования как фреймворка. Самым банальным примером может служить его система настройки скидок, которая довольно гибка и имеет продвинутый интерфейс настройки, не говоря уж о том, что все это работает в комплексе со всем остальным по каталогу и магазину.

Конечно, чтобы воспользоваться рецептами выше, нужно разработать ряд решений, которые подружат фреймворк\библиотеки с Битриксом, однако, большая часть данной работы может быть обособлена в отдельные пакеты и с легкостью переиспользована в будущих проектах. Тем не менее, модель каждого приложения уникальна, равно как и модели отображения API, поэтому эту часть придётся делать для каждого проекта индивидуально. Но важно понимать, обеспечивая консистентность данных, вы существенно уменьшаете риск ошибки. А реализуя методы работы с моделями согласно бизнес-логике, вы не только делаете код более прозрачным, но и начинаете разговаривать на одном языке с людьми, которые пользуются сайтом. Это закладывает хороший фундамент для долгосрочной поддержки проекта.

Но что если приложение попроще и на бэкенде вам нужен не API, а генерация шаблонов? Описанный подход тоже сработает, просто не так важно описывать модель отображения (хотя все ещё полезно), а на фронтенде можно и не использовать продвинутые фреймворки.

Удачного проектирования!

 

Все статьи