В большинстве фреймворков у вас есть классы моделей, которые представляют строку в базе данных.
Например, php-код:
class User extends Model {}
Я привожу красноречивый пример Laravel, но это верно для большинства php-фреймворков.
Затем вы добавляете отношения в класс:
public function pictures()
{
return $this->hasMany('App\Picture');
}
Затем вы добавляете такие методы:
public function deleteComments()
{
// delete comments code here
}
Мой первый вопрос: является ли это хорошей архитектурой дизайна, потому что через годы, когда проект станет большим, у вас будет много взаимосвязей (изображения, комментарии, сообщения, подписки и т. д., Связанные с пользователем). Класс может превратиться в 10 тысяч строк кода или около того.
В этом случае класс станет очень большим и трудным в обслуживании. Кроме того, принцип единой ответственности может быть нарушен из-за того, что у вас слишком много методов в одном классе.
Также, если я хочу использовать этот класс в другом приложении, я не могу просто потому, что мне придется вытаскивать изображения, комментарии и т. д. Во втором приложении (веб-сайте).
Если я сделаю другие классы, такие как «UserPictures», «UserPictureDeleter», код станет более сложным.
Итак, это хорошая практика, и если нет, у вас есть какие-либо предложения о том, как сделать код не перегруженным таким количеством методов, но простым в использовании.
Вы согласны с тем, что все эти методы относятся к классу User?






Laravel и некоторые другие фреймворки предоставляют концепцию Активная запись в своих базовых классах модели. Основная идея Active Record - это представление строки таблицы как объекта, включающего данные строки и методы работы с базами данных.
Использование шаблона Active Record полностью оправдано в небольших простых приложениях, поскольку этот шаблон дает возможность быстро разработать ваше приложение. Но если в вашем приложении много кода и сложная бизнес-логика, Active Record создаст много проблем в архитектуре вашего приложения. Active Record может вызвать следующие проблемы:
Решением этих проблем является использование абстракций ООП вместо абстракций строк таблицы. Например, вы можете использовать Модель домена и Домен-ориентированный дизайн. Этот подход лучше, чем шаблон Active Record для больших приложений.
К сожалению, эти концепции слишком объемны для объяснения в этом посте, но вы можете прочитать «Domain Driven Design» Эрика Эванса. Это хорошая книга о дизайне приложений. Кроме того, вы можете найти множество статей об этих концепциях в Google. Например Построение модели предметной области, Реализация доменно-ориентированного дизайна в PHP (Laravel)
Я добавил в пост несколько статей с примерами
Я думаю, что обсуждение активных записей и доктрин - это всего лишь вопрос личного выбора. Утверждать, что Active Record предназначен для небольших / простых приложений, просто неправильно! Вы будете удивлены «масштабом» компаний, использующих Active Record. Если вы не Facebook или Google, это даже не имеет значения. И если да, то вы, вероятно, собираетесь разработать свой собственный фреймворк.
Любой выбор узоров или выбор любых технологий - это всегда личный выбор. Но это не лишает проблем паттерна Active Record. Размер компании не показывает ситуации, в которых применяется шаблон
Итак, вы признаете, что ваш комментарий об ActiveRecord, предназначенном для небольших приложений, неверен? Паттерн Доктрина также имеет недостатки / проблемы. Это вопрос выбора, но у обоих есть свои плюсы и минусы. То, что Doctrine делает тысячами строк кода, ActiveRecord достигает сотнями.
Есть причина, по которой популярные фреймворки, такие как Laravel и Rails, приняли ActiveRecord, а не Doctrine.
Где я признал, что мое мнение об ActiveRecord неверно? Вы можете попробовать разработать большое приложение со сложной бизнес-логикой с помощью Active Record, но у вас будет много проблем с поддержкой этого приложения. Где я рассказывал о Доктрине? Я говорил об использовании DDD и модели домена, Doctrine - это не шаблон, Doctine - одна из многих ORM.
Модель - это не одна строка из базы данных, модель не всегда содержит только отношения. Модель должна содержать бизнес-логику. Если вы попытаетесь создать Active Record с множеством взаимосвязей и богатой бизнес-логикой, вы удивитесь, сколько проблем с поддержкой в течение длительного времени у вас будет. Active Record используется для быстрой разработки, но не для создания качественного кода. В этом преимущество Active Record. Laravel предоставляет не только Active Record в своем Eloquent ORM, но вы также можете использовать любой ORM в Laravel.
Doctrine - это ORM, реализующий шаблон DDD. Модель должна содержать только логику базы данных, а не бизнес-логику. Проблемы, о которых вы говорите, возникают из-за того, что вы добавили в модели бизнес-логику, что является плохой практикой. Вы можете использовать любой ORM в любом фреймворке или разработать свой собственный. Laravel и Rails из коробки поддерживают ActiveRecord, а не Doctrine по какой-то причине.
Хорошо, в этом случае у нас есть: 1. не-oop объекты, которые не работают со своими состояниями 2. нарушение принципа TDA 3. нарушение принципа информационного эксперта (GRASP) 4. все еще нарушение принципа единой ответственности - Active Record - это объект и репозиторий одновременно 5. все еще нарушается принцип низкой связи (GRASP), вся бизнес-логика зависит от структуры базы данных 6. все еще грязные абстракции, которые показывают структуру базы данных
@Paras Я думаю, вам нужно больше исследовать архитектуры приложений в целом, в частности Active Record. Я бы порекомендовал блог Мартина Фаулера или его знаменитую книгу Patterns of Enterprise Application Architecture. Я бы использовал Active Record, скажем, в простом приложении со списком дел, но как приложение Todoist.
Вы можете улучшить свою модель с помощью интерфейсов. Если вам нужно, чтобы один класс наследовал определенное поведение, общее для другого, разработав интерфейс, вам нужен новый класс только для реализации интерфейса.
The class could become 10k lines of code or so
Каждая функция отношений представляет собой 2-4 строки кода, поэтому, если у вас нет 2500-5000 отношений, этот класс не будет содержать 10 тысяч строк кода. Если да, значит, у вас уже плохой дизайн базы данных.
Also the Single Responsible Principle maybe is violated because you have too many methods in one class.
В SRP нигде не говорится, что нельзя иметь слишком много методов в одном классе. В нем говорится, что у класса должна быть только одна ответственность / причина для существования.
Also if I want to use the class it in another app I cannot, simply because I'll have to pull also the pictures, comments and etc in the second application(website).
Этот класс является классом модели. В его обязанности входит представление одной таблицы базы данных. Если у вас такая же структура таблиц в других приложениях, то да, вам следует использовать этот класс, и вам нужно будет также добавить изображения, комментарии и т. д., Поскольку у вас такая же структура таблицы. Если нет, не втягивайте его. Я не вижу здесь никаких проблем.
Спасибо, я указываю также на другие методы, принадлежащие модели, а не только отношения. Например: deleteUser (), getFullname (), activateUser () и так далее. Класс становится большим, и его трудно поддерживать. Если бы у меня как-то были только базовые функции для User без отношений и этих методов, я мог бы вытащить этот простой класс и использовать его в другом приложении, но это может быть сложно, потому что вам нужно продумать сложную структуру, и даже тогда вы не сможете понять все возможности .
Я не думаю, что deleteUser, activateUser должны даже существовать в классе, отличном от User. Если у вас есть сообщение, связанное с пользователем, и вы хотите выполнить действие над пользователем сообщения, вы бы предпочли сделать $post->user->activate(), а не $post->activateUser(). Кроме того, для каждой модели будут только ограниченные действия, а не тысячи.
Да, это всего лишь пример, количество действий ограничено, но в большом проекте их могут быть сотни. Некоторые из них трудно сказать, относятся они к классу User или нет. Например: $ user-> disablePayments (), $ user-> blockAccount () и представьте, есть ли у вас сотни подобных методов. Некоторые могут сказать, что они не принадлежат к классу пользователей, но я бы сказал, почему бы и нет? $ user-> blockAccount () мне кажется правильным.
blockAccount вроде нормально, но сколько таких методов у вас на модели? Не думайте, что они будут исчисляться тысячами для таблицы с горсткой столбцов.
Это да, но есть методы, по которым сложно сказать, должны ли они быть в пользовательской модели или отдельном классе. Например, $ user-> sendActivationEmail (). Я предполагаю, что они могут быть извлечены в разные классы, но в любом случае это усложняется. У вас есть один класс с 500 методами или у вас есть 100 классов с 5 методами.
Я не знаю, как у вас получается 500 методов в одном классе модели. Кажется непостижимым. Даже если у вас большая таблица с 50 столбцами, 500 методов кажутся чрезмерными. Обычно даже в больших приложениях будет много таблиц (то есть много классов), но это не значит, что у них есть много методов в одном классе. Возможно, некоторые из этих методов применимы к нескольким моделям и должны быть извлечены из признака. Трудно сказать, что происходит, не глядя на класс.
500t были просто примерным счетом, даже если они 20,30, единственная ответственность для меня нарушена. В Laravel, например: у вас есть методы save, get, delete, у вас есть toJson () сериализация, вы можете вызывать события, в основном классы моделей делают все. Не знаю, для меня это плохая практика?
Каким образом получение, сохранение, удаление, моделирование событий и т. д. Нарушает единую ответственность? Модель отвечает за взаимодействие с базой данных. Все это связано с запросами / событиями базы данных. Это не нарушение.
toJson не связан с базой данных, события - нет, sendActivationMail - нет.
toJson - это сериализация класса. Может быть для любого класса. События не связаны, но события базы данных / красноречивых действительно связаны с базой данных. SendActivationEmail должен быть частью трейта, а не моделью. Нет нарушения SRP
Пользователь зависит от SendActivationEmail, поэтому я не могу повторно использовать модель в приложении, где у меня нет черты или класса SendActivationEmail.
Рассмотрим следующий говорить от Адама Уотана. Он решает проблему именования, которая приводит к раздуванию классов. Если вы рассмотрите его методологию именования методов и перекладывания ответственности, вы получите классы меньшего размера и более легкий для чтения код.
Кроме того, не позволяйте себе навязывать некоторые правила и «законы», существующие в программировании. Если вам нужен класс, состоящий из 10 тыс. Строк, но он читабельный, тогда действуйте.
Спасибо, хороший ответ, но с моделью предметной области не означает ли это, что у меня будет больше повторного использования кода? Вместо «присоединений» активных записей, например, я буду использовать пользовательские записи во всех моделях предметной области (пользователь, изображения и т. д.). Можете ли вы предоставить очень простой способ с кодом (php, java, что угодно), просто чтобы понять. Спасибо