Хабрахабр

[Из песочницы] За что я ненавижу Eloquent ORM

image

Хочу перед вами исповедаться и рассказать немного о том, что я чувствую, когда разрабатываю на Laravel. Всем привет. Нет, не подумайте, я обожаю этот фреймворк и безумно благодарен команде, которая его создала и поддерживает, они делают крайне крутое дело и, на мой взгляд, Laravel является лучшим продолжением не менее горячо любимого мною Symfony.

Тупой в том смысле, что даже через 10 лет, если заказчик попросит тебя внести изменения в него, ты сможешь сделать это не вникая во всю логику, даже будучи после пятничного корпоратива, ничего в старом коде не сломав. Я обожаю тупой код. Но есть в Laravel Eloquent ORM одно архитектурное решение, которое заставляет меня плакать. И тупой в том смысле, что не нужно прикладывать никаких когнитивных усилий, чтобы его понять. Заходите под кат. Интересно?

Умные люди уже давным давно все придумали за нас: OOP, Паттерны проектирования, SOLID, DDD и другие страшные словечки, которые так пугают по-началу, а потом применяются по наитию.

Они позволяют писать максимально тупой и защищенный код прямо из коробки. Этим мне нравится Laravel и Symfony. У каждого из них есть свои недостатки… Но в Laravel есть один, который меня раздражает больше всего. Да. Это использование Active Record Pattern (AR) для работы с моделями.

Что это вообще такое? Для начала — немного об этом паттерне. Этот паттерн представляет собой коллекцию. Для понимания, следует пойти к родителю этого опуса проектирования приложений — паттерну Repository. В 90 из 100 процентах случаев, таким местом хранения являются различные базы данных. Коллекцию сущностей (Entity), которые может извлекать, изменять, сохранять, удалять, в общем, управлять ими в абстрактном месте хранения. Но может быть и файловая система, и какой-то кэш, и даже внешнее API.

Кроме того, благодаря этому подходу, реализуется слабая связанность — нам не важно, каким именно образом в приложении хранится что-либо, мы работаем с Entity, когда хотим работать непосредственно с объектным представлением данных и работаем с Repository, когда нам нужно взаимодействовать с хранилищем. Такой подход полностью соответствует принципу единой ответственности и подходу DDD.

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

То есть объект становится представлением конкретной записи в базе данных. AR — паттерн, который сопоставляет Entity и Repository в одну Model. К чему это приводит и почему это так раздражает? И… Что?

Это важно, ведь в рамках моей системы я не хочу передавать по цепочке вызовов строчку из бд в объектном представлении. Во первых, мы нарушаем тот самый принцип единой ответственности — логика работы с хранилищем в одном месте, а логика работы с сущностью в другой. Мне должно быть наплевать, как она получается, изменяется и сохраняется. Я хочу передавать модель. Мне нужно иметь те методы, которые позволяют взаимодействовать только с моделью, а не со строками в БД.

Да, мы можем сделать это в конфигурации, изменив это сразу для всех, в рамках поддерживаемых баз данных. Во вторых, мы не можем (как следствие того, что Persistent слой — слой хранения — связан со слоем сущности), простым образом изменить место хранения модели. Или изменить только для конкретной модели (при всем при этом, мы не убираем никакие методы query builder'а, ведь нельзя избавиться от методов базового класса) и напороться на тонну вероятных ошибок в коде или, не дай Бог, если его кто-то другой поддерживать будет (а такое случается сплошь и рядом).

Мне хочется тестировать свои сущности. В третьих. А, как показывает практика, в случае с AR ты этого сделать не можешь, потому что нарушен чертов принцип единой ответственности! Мне хочется, черт возьми, быть уверенным, что изменения, которые я вношу не сломают мою бизнес-логику. Тестировать модели можно, просто… Немного не просто. Хотя тут я немного лукавлю.

Хотя весь его плюс в том, что это "быстро, просто, не задумываясь". Тем не менее, нельзя не сказать о плюсах этого паттерна. Это также, позволяет избавиться от лишних проблем на этапе формирования MVP, который обязательно (практика показывает, что такое случается редко, но все же) планируется переписать. Сливая два близких по логике своего действия и постоянно использующихся вместе паттерна, мы получили удобное средство, которое немного сокращает объем кода (в сторону усложнения, мы же помним о "тупом коде"?). Это позволяет сместить мысли с вопроса "как мы делаем" на вопрос "что мы делаем", то есть избавиться от лишних вопросов о технологиях и перейти к бизнес-логике.

Active Record зло во плоти? К какому же выводу я пришел за несколько лет использования Laravel Eloquent ORM? Но это невозможная для работы вещь, когда твое приложение вырастает и тебе приходится работать с большим количеством источников данных, писать код со 100% покрытием тестами, начинаются большие проблемы. Да нет, это крутейший инструмент для некоторых ситуаций, особенно для этапа, когда пишется простенькое приложение или прототип такого приложения.

Но все же хочется немного больше свободы от фреймворка, тем более, что он так многим хорош! Да, придумываются новые фишки (Trucker?), да идем на ухищрения.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»