Почему все Активные Участники Записи ненавидят?[закрыто]

StackOverflow https://stackoverflow.com/questions/7864

Вопрос

По мере того как я узнаю все больше и больше об ООП и начинаю внедрять различные шаблоны проектирования, я продолжаю возвращаться к случаям, когда люди ненавидят Активная запись.

Часто люди говорят, что он плохо масштабируется (ссылаясь на Twitter в качестве яркого примера), но на самом деле никто не объясняет почему он плохо масштабируется;и / или как реализовать плюсы AR без минусов (с помощью аналогичного, но другого шаблона?)

Надеюсь, это не превратится в священную войну за шаблоны проектирования - все, что я хочу знать, это **** конкретно **** что не так с Active Record.

Если он плохо масштабируется, почему бы и нет?

Какие еще проблемы у него есть?

Это было полезно?

Решение

Там есть ActiveRecord шаблон проектирования и ActiveRecord библиотека Rails ORM, а также есть масса подделок для .NET и других языков.

Это все разные вещи.В основном они следуют этому шаблону проектирования, но расширяют и модифицируют его многими различными способами, поэтому, прежде чем кто-либо скажет "ActiveRecord отстой", это нужно уточнить, сказав: "какой ActiveRecord, там куча?"

Я знаком только с ActiveRecord от Rails, я постараюсь устранить все жалобы, которые были подняты в контексте его использования.

@БлаМ

Проблема, которую я вижу с активными записями, заключается в том, что это всегда только одна таблица

Код:

class Person
    belongs_to :company
end
people = Person.find(:all, :include => :company )

Это генерирует SQL с помощью LEFT JOIN companies on companies.id = person.company_id, и автоматически генерирует связанные объекты Компании, чтобы вы могли делать people.first.company и ему не нужно обращаться к базе данных, потому что данные уже присутствуют.

@pix0r

Неотъемлемая проблема Active Record заключается в том, что запросы к базе данных генерируются и выполняются автоматически для заполнения объектов и изменения записей базы данных

Код:

person = Person.find_by_sql("giant complicated sql query")

Это не рекомендуется, так как это некрасиво, но для случаев, когда вам просто нужно написать необработанный SQL, это легко сделать.

@Тим Салливан

...и вы выбираете несколько экземпляров модели, вы в основном выполняете "выбрать * из ..."

Код:

people = Person.find(:all, :select=>'name, id')

При этом будут выбраны только столбцы name и ID из базы данных, все остальные "атрибуты" в сопоставленных объектах будут просто равны нулю, если вы вручную не перезагрузите этот объект, и так далее.

Другие советы

Я всегда считал, что ActiveRecord хорош для быстрых приложений на основе CRUD, где модель относительно плоская (например, не так много иерархий классов).Однако для приложений со сложными иерархиями OO требуется Преобразователь данных вероятно, это лучшее решение.В то время как ActiveRecord предполагает соотношение 1: 1 между вашими таблицами и вашими объектами данных, такого рода отношения становятся громоздкими в более сложных доменах.В его книга о паттернах, Мартин Фаулер указывает, что ActiveRecord имеет тенденцию ломаться в условиях, когда ваша Модель довольно сложна, и предлагает Преобразователь данных в качестве альтернативы.

Я убедился, что это верно на практике.В случаях, когда у вас много наследования в вашем домене, сопоставить наследование с вашей СУБД сложнее, чем сопоставить ассоциации или композицию.

Способ, которым я это делаю, заключается в том, чтобы иметь объекты "домена", доступ к которым осуществляется вашими контроллерами через эти классы DataMapper (или "service layer").Они не являются прямым отражением базы данных, но действуют как ваше OO-представление для некоторого объекта реального мира.Допустим, у вас есть класс User в вашем домене, и вам необходимо иметь ссылки на другие объекты или коллекции, уже загруженные при извлечении этого объекта User.Данные могут поступать из множества разных таблиц, и шаблон ActiveRecord может сделать это действительно сложным.

Вместо прямой загрузки объекта User и доступа к данным с помощью API в стиле ActiveRecord, код вашего контроллера извлекает объект User, например, вызывая API метода UserMapper.getUser().Именно этот картограф отвечает за загрузку любых связанных объектов из их соответствующих таблиц и возврат завершенного пользовательского объекта "домен" вызывающей стороне.

По сути, вы просто добавляете еще один уровень абстракции, чтобы сделать код более управляемым.Содержат ли ваши классы DataMapper необработанный пользовательский SQL, или вызовы API уровня абстракции данных, или даже сами обращаются к шаблону ActiveRecord, на самом деле не имеет значения для кода контроллера, который получает приятный, заполненный пользовательский объект.

Во всяком случае, именно так я это делаю.

Я думаю, что, вероятно, существует совершенно разный набор причин между тем, почему люди "ненавидят" ActiveRecord, и тем, что в нем "не так".

Что касается проблемы ненависти, то существует много злобы по отношению ко всему, что связано с Rails.Что касается того, что в нем не так, то, скорее всего, это как и все технологии, и есть ситуации, когда это хороший выбор, и ситуации, когда есть лучший выбор.По моему опыту, ситуация, когда вы не можете воспользоваться большинством функций Rails ActiveRecord, заключается в том, что база данных плохо структурирована.Если вы обращаетесь к данным без первичных ключей, с вещами, которые нарушают первую нормальную форму, где для доступа к данным требуется множество хранимых процедур, вам лучше использовать что-то, что больше похоже на оболочку SQL.Если ваша база данных относительно хорошо структурирована, ActiveRecord позволяет вам воспользоваться этим преимуществом.

Чтобы добавить к теме ответа комментаторам, которые говорят, что в ActiveRecord все сложно, с ответом на фрагмент кода

@Sam McAfee Говорит, что у вас есть класс User в вашем домене, и вам необходимо иметь ссылки на другие объекты или коллекции, которые уже загружены при извлечении этого объекта User.Данные могут поступать из множества разных таблиц, и шаблон ActiveRecord может сделать это действительно сложным.

user = User.find(id, :include => ["posts", "comments"])
first_post = user.posts.first
first_comment = user.comments.first

Используя опцию include, ActiveRecord позволяет переопределить поведение отложенной загрузки по умолчанию.

Мой длинный и запоздалый ответ, даже не полный, но хорошее объяснение, ПОЧЕМУ я ненавижу этот шаблон, мнения и даже некоторые эмоции:

1) краткая версия:Активная запись создает "тонкий слой" из "прочная привязка" между базой данных и кодом приложения.Который не решает никаких логических, каких бы то ни было проблем, вообще никаких проблем.ИМХО, это не дает НИКАКОЙ ЦЕННОСТИ, за исключением некоторых синтаксический сахар для программиста (который затем может использовать "объектный синтаксис" для доступа к некоторым данным, существующим в реляционной базе данных).Усилия по созданию некоторого комфорта для программистов следует (ИМХО ...) лучше вкладывать в низкоуровневые инструменты доступа к базе данных, напримернекоторые вариации простого, непринужденного, незамысловатого hash_map get_record( string id_value, string table_name, string id_column_name="id" ) и аналогичные методы (конечно, концепции и элегантность сильно варьируются в зависимости от используемого языка).

2) длинная версия:В любых проектах, основанных на базе данных, где у меня был "концептуальный контроль" над вещами, я избегал AR, и это было хорошо.Обычно я строю многоуровневая архитектура (рано или поздно вы разделяете свое программное обеспечение на уровни, по крайней мере, в проектах среднего и крупного размера):

A1) сама база данных, таблицы, связи, даже некоторая логика, если СУБД это позволяет (MySQL сейчас тоже взрослая)

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

Б) уровень доступа к базе данных (на этом уровне очень приветствуются инструментальные методы, помощники для легкого доступа к данным в базе данных, но AR здесь не предоставляет никакой ценности, кроме некоторого синтаксического сахара)

В) уровень объектов приложения:"объекты приложения" иногда представляют собой простые строки таблицы в базе данных, но в большинстве случаев это соединение объекты в любом случае имеют некоторую более высокую логику, поэтому тратить время на объекты AR на этом уровне просто бесполезно, пустая трата драгоценного времени программистов, потому что "реальная ценность", "более высокая логика" этих объектов должна быть реализована поверх объектов AR в любом случае - с AR и без AR!И, например, зачем вам нужна абстракция "Объектов записи журнала"?Логический код приложения записывает их, но должна ли у него быть возможность обновлять или удалять их?звучит глупо, и App::Log("I am a log message") являются ли некоторые величины более простыми в использовании, чем le=new LogEntry(); le.time=now(); le.text="I am a log message"; le.Insert();.И , например,:использование "объекта записи журнала" в представлении журнала в вашем приложении будет работать для 100, 1000 или даже 10000 строк журнала, но рано или поздно вам придется оптимизировать - и я уверен, что в большинстве случаев вы просто будете использовать этот маленький красивый оператор SQL SELECT в логике вашего приложения (что полностью ломает AR idea ..), вместо того, чтобы оборачивать этот маленький оператор в жесткие фиксированные рамки AR idea с большим количеством кода, обертывающего и скрывающего его.Время, которое вы потратили на написание и / или создание AR-кода, можно было бы потратить на гораздо более умный интерфейс для чтения списков записей журнала (много-много способов, небо - это предел).Программисты должны осмелитесь изобретать новые абстракции реализовать их прикладную логику, соответствующую предполагаемому применению, и не тупо переосмысливать глупые шаблоны, на первый взгляд, это звучит заманчиво!

D) логика приложения - реализует логику взаимодействия объектов и создания, удаления и перечисления (!) объектов логики приложения (НЕТ, эти задачи редко должны быть привязаны к самим объектам логики приложения:указывает ли лист бумаги на вашем столе названия и расположение всех других листов в вашем офисе?забудьте о "статических" методах для перечисления объектов, это глупо, плохой компромисс, созданный для того, чтобы человеческий образ мышления вписывался в мышление [some-not-all-AR-framework-like-]AR)

E) пользовательский интерфейс - ну, то, что я напишу в следующих строках, очень, очень, очень субъективно, но, по моему опыту, проекты, построенные на AR, часто пренебрегали частью пользовательского интерфейса приложения - время тратилось впустую на создание непонятных абстракций.В конце концов, такие приложения отнимают у верстальщиков много времени и кажутся приложениями от верстальщиков для верстальщиков, разбирающихся в технологиях как внутри, так и снаружи.Программисты чувствуют себя хорошо (наконец-то проделана тяжелая работа, все закончено и исправлено, в соответствии с концепцией на бумаге ...), а заказчикам "просто нужно усвоить, что так и должно быть", потому что это "профессионально"..ладно, извини, я отвлекся ;-)

Ну, по общему признанию, все это субъективно, но это мой опыт (исключая Ruby on Rails, он может быть другим, и у меня нет никакого практического опыта работы с таким подходом).

В платных проектах я часто слышал требование начать с создания некоторых объектов "активной записи" в качестве строительного блока для логики приложения более высокого уровня.По моему опыту, это заметно часто это было своего рода оправданием того, что у заказчика (в большинстве случаев компании-разработчика программного обеспечения) не было хорошей концепции, общего представления о том, каким в конечном итоге должен быть продукт.Эти заказчики мыслят в жестких рамках ("в проекте десять лет назад это работало хорошо ..."), они могут конкретизировать сущности, они могут определять отношения между сущностями, они могут разбивать отношения с данными и определять базовую логику приложения, но затем они останавливаются и передают это вам, думая, что это все, что вам нужно...им часто не хватает полной концепции логики приложения, пользовательского интерфейса, удобства использования и так далее, и тому подобное...им не хватает масштабности, и им не хватает любви к деталям, и они хотят, чтобы вы следовали этому образу вещей, потому что..ну, а что, если это сработало в том проекте много лет назад, это заставляет людей быть занятыми и молчаливыми?Я не знаю.Но "детали" отделяют мужчин от мальчиков, или ..каким был первоначальный рекламный слоган ?;-)

По прошествии многих лет (десять лет активного опыта разработки) всякий раз, когда клиент упоминает "шаблон активной записи", у меня звонит тревожный звоночек.Я научился пытаться заполучить их вернемся к этому важному этапу разработки концепции, дайте им дважды подумать, попробуйте показать им их концептуальные слабости или просто избегайте их вообще, если они не распознаются (в конце концов, вы знаете, клиент, который еще не знает, чего он хочет, возможно, даже думает, что знает, но это не так, или пытается бесплатно передать МНЕ работу над концепцией, отнимает у меня много драгоценных часов, дней, недель и месяцев моего времени, жизнь слишком коротка ...).

Итак, наконец-то:ВОТ почему я ненавижу этот глупый "шаблон активной записи", и я избегаю и буду избегать его, когда это возможно.

Редактировать:Я бы даже назвал это Отсутствием Паттерна.Это не решает никакой проблемы (шаблоны не предназначены для создания синтаксического сахара).Это создает много проблем:корень всех его проблем (упомянутых во многих ответах здесь ..) заключается в том, что это просто скрывает старый добрый, хорошо разработанный и мощный SQL, стоящий за интерфейсом, который по определению шаблонов крайне ограничен.

Этот шаблон заменяет гибкость синтаксическим сахаром!

Подумайте об этом, какую проблему AR решает для вас?

Некоторые сообщения сбивают меня с толку.Некоторые ответы будут "ORM" против "SQL" или что-то в этом роде.

Дело в том, что AR - это просто упрощенный шаблон программирования, где вы используете преимущества своих доменных объектов для написания там кода доступа к базе данных.

Эти объекты обычно имеют бизнес-атрибуты (свойства компонента) и некоторое поведение (методы, которые обычно работают с этими свойствами).

AR просто говорит "добавить некоторые методы к этим объектам домена" к задачам, связанным с базой данных.

И я должен сказать, исходя из моего мнения и опыта, что мне не нравится эта схема.

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

Для меня настоящая проблема заключается как раз в заботе об ООП.Шаблон AR заставляет вас каким-то образом добавлять зависимость от вашего объекта к объектам инфраструктуры.Эти объекты инфраструктуры позволяют объекту домена запрашивать базу данных с помощью методов, предложенных AR.

Я всегда говорил, что два уровня являются ключом к успеху проекта.Уровень обслуживания (где логика бизнеса находится или может быть экспортирована с помощью какой-либо технологии удаленного взаимодействия, например, в виде веб-служб) и уровень домена.На мой взгляд, если мы добавим некоторые зависимости (на самом деле не необходимые) к объектам уровня домена для разрешения шаблона AR, наши объекты домена будет сложнее совместно использовать с другими уровнями или (редко) внешними приложениями.

Реализация AR в Spring Roo интересна, потому что она полагается не на сам объект, а на некоторые файлы AspectJ.Но если позже вы не захотите работать с Roo и вам придется провести рефакторинг проекта, AR-методы будут реализованы непосредственно в объектах вашего домена.

Другая точка зрения.Представьте, что мы не используем реляционную базу данных для хранения наших объектов.Представьте, что приложение хранит объекты нашего домена, например, в базе данных NoSQL или просто в XML-файлах.Будем ли мы реализовывать методы, которые выполняют эти задачи, в наших доменных объектах?Я так не думаю (например, в случае XM мы бы добавили зависимости, связанные с XML, к нашим доменным объектам...Я думаю, это действительно печально).Почему же тогда мы должны реализовывать методы реляционной базы данных в объектах домена, как сказано в шаблоне Ar?

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

Вопрос касается шаблона проектирования Active Record.Не является инструментом orm .

Исходный вопрос помечен rails и относится к Twitter, который встроен в Ruby on Rails.Фреймворк ActiveRecord в Rails является реализацией шаблона разработки активных записей Фаулера.

Главное, что я увидел в отношении жалоб на Active Record, заключается в том, что когда вы создаете модель вокруг таблицы и выбираете несколько экземпляров модели, вы в основном выполняете "выбрать * из ...".Это прекрасно подходит для редактирования записи или отображения записи, но если вы хотите, скажем, отобразить список городов для всех контактов в вашей базе данных, вы могли бы выполнить команду "выбрать город из ..." и получить только города.Выполнение этого с активной записью потребует, чтобы вы выбрали все столбцы, но только с использованием City .

Конечно, различные реализации будут обрабатывать это по-разному.Тем не менее, это одна из проблем.

Теперь вы можете обойти это, создав новую модель для конкретной вещи, которую вы пытаетесь сделать, но некоторые люди утверждают, что это требует больше усилий, чем пользы.

Что касается меня, то я копаю Активную Запись.:-)

HTH

Мне нравится, как SubSonic работает только с одной колонкой.
Либо

DataBaseTable.GetList(DataBaseTable.Columns.ColumnYouWant)

, или:

Query q = DataBaseTable.CreateQuery()
               .WHERE(DataBaseTable.Columns.ColumnToFilterOn,value);
q.SelectList = DataBaseTable.Columns.ColumnYouWant;
q.Load();

Но Linq по-прежнему является королем, когда дело доходит до отложенной загрузки.

@БлаМ:Иногда я просто реализовывал активную запись для результата объединения.Не всегда это должна быть таблица отношений <--> Активная запись.Почему бы не "Результат инструкции Join" <--> Активная запись?

Я собираюсь рассказать об Active Record как шаблоне проектирования, я не видел ROR.

Некоторые разработчики ненавидят Active Record, потому что они читают умные книги о написании чистого и опрятного кода, и в этих книгах утверждается, что active record нарушает принцип единой ответственности, нарушает правило DDD о том, что доменный объект должен быть устойчивым к игнорированию, и многие другие правила из подобных книг.

Во-вторых, объекты домена в активной записи, как правило, относятся к базе данных 1 к 1, что может считаться ограничением в некоторых системах (в основном n-уровневых).

Это просто абстрактные вещи, я не видел в ruby on rails реальной реализации этого шаблона.

Проблема, которую я вижу с Активными записями, заключается в том, что это всегда примерно один таблица.Это нормально, пока вы действительно работаете только с одной таблицей, но когда вы работаете с данными, в большинстве случаев у вас где-то будет какое-то соединение.

ДА, Присоединиться обычно это хуже, чем никакого объединения вообще когда дело доходит до производительности, но Присоединиться обычно это лучше, чем "фальшивое" присоединение сначала прочитав всю таблицу A, а затем используя полученную информацию для чтения и фильтрации таблицы B.

Проблема ActiveRecord заключается в том, что запросы, которые он автоматически генерирует для вас, могут вызвать проблемы с производительностью.

В конечном итоге вы выполняете несколько неинтуитивных трюков для оптимизации запросов, которые заставляют вас задуматься, было бы ли более экономичным по времени написание запроса вручную в первую очередь.

Хотя все остальные комментарии, касающиеся оптимизации SQL, безусловно, верны, моя основная жалоба на шаблон active record заключается в том, что он обычно приводит к несоответствие импеданса.Мне нравится содержать свой домен в чистоте и должным образом инкапсулированным, на что шаблон активной записи обычно рушит все надежды.

Попробуйте установить полиморфные отношения "много ко многим".Не все так просто.Особенно если вы не используете ИППП.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top