По мере того, как я узнаю все больше и больше об ООП и начинаю реализовывать различные шаблоны проектирования, я постоянно возвращаюсь к случаям, когда люди ненавидят Active Record .
Часто люди говорят, что он плохо масштабируется (ссылаясь на Twitter в качестве основного примера), но на самом деле никто не объясняет, почему он плохо масштабируется; и / или как достичь плюсов AR без минусов (с помощью похожего, но другого шаблона?)
Надеюсь, это не превратится в священную войну паттернов проектирования - все, что я хочу знать, это **** конкретно ****, что не так с Active Record.
Если он плохо масштабируется, почему бы и нет?
Какие еще проблемы у него есть?
ruby-on-rails
design-patterns
oop
activerecord
Адам Таттл
источник
источник
Ответы:
Есть ActiveRecord Design Pattern и ActiveRecord ORM Library Rails , а также множество подделок для .NET и других языков.
Это все разные вещи. В основном они следуют этому шаблону проектирования, но расширяют и модифицируют его множеством различных способов, поэтому, прежде чем кто-либо скажет «ActiveRecord - отстой», его нужно уточнить, сказав «какой ActiveRecord, есть куча?
Я знаком только с ActiveRecord от Rails, я постараюсь рассмотреть все жалобы, которые были подняты в связи с его использованием.
Код:
Это генерирует SQL
LEFT JOIN companies on companies.id = person.company_id
и автоматически генерирует связанные объекты Company, чтобы вы могли это сделать,people.first.company
и ему не нужно было обращаться к базе данных, потому что данные уже присутствуют.Код:
Это не рекомендуется, поскольку это некрасиво, но в тех случаях, когда вам просто нужно написать необработанный SQL, это легко сделать.
Код:
При этом будут выбраны только столбцы имени и идентификатора из базы данных, все остальные «атрибуты» в сопоставленных объектах будут просто равны нулю, если вы вручную не перезагрузите этот объект и так далее.
источник
Я всегда обнаруживал, что ActiveRecord хорош для быстрых приложений на основе CRUD, где Модель относительно плоская (например, не много иерархий классов). Однако для приложений со сложной объектно- ориентированной иерархией DataMapper , вероятно, является лучшим решением. Хотя ActiveRecord предполагает соотношение 1: 1 между вашими таблицами и вашими объектами данных, такого рода отношения становятся громоздкими с более сложными доменами. В своей книге о шаблонах Мартин Фаулер указывает, что ActiveRecord имеет тенденцию выходить из строя в условиях, когда ваша модель является довольно сложной, и предлагает DataMapper в качестве альтернативы.
Я убедился, что это правда. В случаях, когда у вас много наследования в вашем домене, сложнее сопоставить наследование с вашей СУБД, чем сопоставить ассоциации или композицию.
Я делаю это так, чтобы иметь "доменные" объекты, к которым ваши контроллеры получают доступ через эти классы DataMapper (или "уровень обслуживания"). Они не отражают базу данных напрямую, а действуют как объектно-ориентированное представление некоторого реального объекта. Предположим, у вас есть класс User в вашем домене, и вам нужно иметь ссылки или коллекции других объектов, уже загруженные, когда вы извлекаете этот объект User. Данные могут поступать из множества разных таблиц, и шаблон ActiveRecord может сделать это очень сложно.
Вместо прямой загрузки объекта User и доступа к данным с помощью API в стиле ActiveRecord код вашего контроллера извлекает объект User, например, путем вызова API метода UserMapper.getUser (). Именно этот модуль отображения отвечает за загрузку любых связанных объектов из соответствующих таблиц и возвращение завершенного объекта «Домен» пользователя вызывающей стороне.
По сути, вы просто добавляете еще один уровень абстракции, чтобы сделать код более управляемым. Содержат ли ваши классы DataMapper необработанный пользовательский SQL, вызовы API уровня абстракции данных или даже доступ к самому шаблону ActiveRecord, на самом деле не имеет значения для кода контроллера, который получает красивый заполненный объект User.
Во всяком случае, вот как я это делаю.
источник
Я думаю, что существует очень разный набор причин между тем, почему люди «ненавидят» ActiveRecord, и тем, что с ним «не так».
Что касается ненависти, то есть много яда по отношению ко всему, что связано с Rails. Что касается того, что с этим не так, вполне вероятно, что это похоже на все технологии, и есть ситуации, когда это хороший выбор, и ситуации, когда есть лучший выбор. По моему опыту, ситуация, когда вы не можете воспользоваться преимуществами большинства функций Rails ActiveRecord, - это когда база данных плохо структурирована. Если вы обращаетесь к данным без первичных ключей, с вещами, которые нарушают первую нормальную форму, где для доступа к данным требуется множество хранимых процедур, вам лучше использовать что-то большее, чем просто оболочку SQL. Если ваша база данных относительно хорошо структурирована, ActiveRecord позволяет вам воспользоваться этим.
Чтобы добавить к теме ответа комментаторам, которые говорят, что в ActiveRecord что-то сложно, с помощью реплики фрагмента кода
Используя параметр включения, ActiveRecord позволяет вам переопределить поведение отложенной загрузки по умолчанию.
источник
Мой длинный и запоздалый ответ, даже не полный, но хорошее объяснение, ПОЧЕМУ я ненавижу этот шаблон, мнения и даже некоторые эмоции:
1) краткая версия: Active Record создает « тонкий слой » « сильной связи » между базой данных и кодом приложения. Которая не решает ни логических, ни каких бы то ни было проблем, вообще никаких проблем. IMHO он не предоставляет НИКАКОГО ЗНАЧЕНИЯ, кроме некоторого синтаксического сахара для программиста (который затем может использовать «синтаксис объекта» для доступа к некоторым данным, которые существуют в реляционной базе данных). Усилия по созданию некоторого комфорта для программистов должны (IMHO ...) лучше быть вложены в инструменты доступа к базам данных низкого уровня, например, некоторые варианты простых, легких, простых
hash_map get_record( string id_value, string table_name, string id_column_name="id" )
и подобных методов (конечно, концепции и элегантность сильно варьируются в зависимости от используемый язык).2) длинная версия: в любых проектах, основанных на базе данных, где у меня был «концептуальный контроль», я избегал AR, и это было хорошо. Я обычно строю многоуровневую архитектуру (вы рано или поздно делите свое программное обеспечение на слои, по крайней мере, в проектах среднего и большого размера):
А1) сама база данных, таблицы, отношения, даже некоторая логика, если СУБД позволяет это (MySQL теперь тоже вырос)
A2) очень часто существует нечто большее, чем просто хранилище данных: файловая система (большие двоичные объекты в базе данных - не всегда хорошее решение ...), устаревшие системы (представьте себе, «как» они будут доступны, возможно множество разновидностей .. но это так. не суть ...)
B) уровень доступа к базе данных (на этом уровне методы инструментов, помощники для легкого доступа к данным в базе данных очень приветствуются, но AR не предоставляет здесь никакой ценности, кроме некоторого синтаксического сахара)
C) уровень объектов приложения: «объекты приложения» иногда представляют собой простые строки таблицы в базе данных, но в большинстве случаев они в любом случае являются составными объектами, и к ним присоединена некоторая более высокая логика, поэтому вкладывать время в объекты 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 ...) вместо того, чтобы оборачивать этот небольшой оператор в жесткие фиксированные рамки идеи AR с большим количеством кода, обертывающего и скрывающего его. Время, которое вы потратили на написание и / или построение кода AR, можно было бы вложить в гораздо более умный интерфейс для чтения списков записей журнала (во многих случаях пределом нет). Программистам следует осмелиться изобретать новые абстракции, чтобы реализовать логику своего приложения, которая подходит для предполагаемого приложения, а не тупо повторно реализовывать глупые шаблоны.Звучит хорошо на первый взгляд!D) логика приложения - реализует логику взаимодействия объектов и создания, удаления и перечисления (!) Объектов логики приложения (НЕТ, эти задачи редко должны быть привязаны к самим объектам логики приложения: говорит ли лист бумаги на вашем столе вы имена и расположение всех других листов в вашем офисе? Забудьте "статические" методы для перечисления объектов, это глупо, плохой компромисс, созданный для того, чтобы человеческий образ мышления вписался в [некоторые-не-все-AR-фреймворки -] AR мышление)
E) пользовательский интерфейс - ну, то, что я напишу в следующих строках, очень, очень, очень субъективно, но, по моему опыту, проекты, построенные на AR, часто игнорировали UI-часть приложения - время было потрачено на создание непонятных абстракций. . В конце концов, такие приложения тратят много времени кодировщиков и ощущаются как приложения от кодеров для кодеров, ориентированные на технические аспекты как внутри, так и снаружи. Кодировщики чувствуют себя хорошо (наконец-то тяжелая работа сделана, все закончено и правильно, в соответствии с концепцией на бумаге ...), а заказчики «просто должны понять, что так должно быть», потому что это «профессионально» .. окей извините, я отвлекся ;-)
Что ж, по общему признанию, все это субъективно, но это мой опыт (исключая Ruby on Rails, он может быть другим, и у меня нет практического опыта в этом подходе).
В платных проектах я часто слышал требование начать с создания некоторых объектов «активной записи» в качестве строительного блока для логики приложения более высокого уровня. По моему опыту, это заметно частобыло своего рода оправданием того, что заказчик (в большинстве случаев компания, занимающаяся разработкой программного обеспечения) не имел хорошей концепции, широкого представления, представления о том, каким должен быть продукт. Эти клиенты мыслят в жестких рамках («в проекте десять лет назад он работал хорошо ...»), они могут конкретизировать сущности, они могут определять отношения сущностей, они могут разрушать отношения данных и определять базовую логику приложения, но затем они останавливаются и передайте его вам, и подумайте, что это все, что вам нужно ... им часто не хватает полной концепции логики приложения, пользовательского интерфейса, удобства использования и так далее, и так далее ... им не хватает широкого обзора и любви к подробности, и они хотят, чтобы вы следовали тому образу жизни AR, потому что ... ну, почему это сработало в этом проекте много лет назад, заставляет людей быть занятыми и молчать? Я не знаю. Но «подробности» отделите мужчин от мальчиков, или .. как был оригинальный рекламный слоган? ;-)
По прошествии многих лет (десять лет активного опыта разработки), всякий раз, когда заказчик упоминает «активную схему записи», у меня звонит сигнал тревоги. Я научился пытаться вернуть их к этой важной фазе зачатия , позволить им подумать дважды, попытаться показать свои концептуальные слабости или просто избегать их вообще, если они не различают (в конце концов, вы знаете, покупатель, который еще не знает, чего хочет, может даже думает, что знает, но не знает, или пытается бесплатно передать концептуальную работу МНЕ, стоит мне много драгоценных часов, дней, недель и месяцев моего времени, жить слишком мало ...).
Итак, наконец: ЭТО ВСЕ - вот почему я ненавижу этот глупый «шаблон активной записи», и я ненавижу и буду избегать его, когда это возможно.
РЕДАКТИРОВАТЬ : Я бы даже назвал это без шаблона. Это не решает никаких проблем (шаблоны не предназначены для создания синтаксического сахара). Это создает много проблем: корень всех его проблем (упомянутых во многих ответах здесь ..) заключается в том, что он просто скрывает старый добрый, хорошо разработанный и мощный SQL за интерфейсом, который по определению шаблонов чрезвычайно ограничен.
Этот шаблон заменяет гибкость синтаксическим сахаром!
Подумайте, какую проблему решает для вас AR?
источник
before_save
обратных вызовов для поддержания согласованности в записи 4)after_commit
хуки для триггеров внешней службы. 5) Хороший DSL для организации изменений DDL в ревизии (миграции). (Боль все еще есть, но отсутствие шаблона хуже, когда> 1 разработчик.)Некоторые сообщения сбивают меня с толку. Некоторые ответы относятся к «ORM» против «SQL» или что-то в этом роде.
Дело в том, что AR - это просто упрощенный шаблон программирования, в котором вы используете объекты своей области для написания кода доступа к базе данных.
Эти объекты обычно имеют бизнес-атрибуты (свойства bean-компонента) и некоторое поведение (методы, которые обычно работают с этими свойствами).
AR просто говорит «добавить несколько методов к этим объектам домена» для задач, связанных с базой данных.
И я должен сказать, исходя из моего мнения и опыта, что мне не нравится этот узор.
На первый взгляд это может звучать неплохо. Некоторые современные инструменты Java, такие как Spring Roo, используют этот шаблон.
Для меня настоящая проблема связана только с ООП. Шаблон AR заставляет вас каким-то образом добавить зависимость от вашего объекта к объектам инфраструктуры. Эти объекты инфраструктуры позволяют объекту домена запрашивать базу данных с помощью методов, предложенных AR.
Я всегда говорил, что два уровня - ключ к успеху проекта. Уровень услуг (где находится бизнес-логика или может быть экспортирован с помощью какой-либо технологии удаленного взаимодействия, например, веб-служб) и уровень домена. На мой взгляд, если мы добавим некоторые зависимости (которые на самом деле не нужны) к объектам уровня домена для разрешения шаблона AR, нашими объектами домена будет труднее поделиться с другими уровнями или (редко) внешними приложениями.
Реализация AR в Spring Roo интересна тем, что не полагается на сам объект, а на некоторые файлы AspectJ. Но если позже вы не захотите работать с Roo и вам придется реорганизовать проект, методы AR будут реализованы непосредственно в объектах вашего домена.
Другая точка зрения. Представьте, что мы не используем реляционную базу данных для хранения наших объектов. Представьте, что приложение хранит объекты нашего домена, например, в базе данных NoSQL или просто в файлах XML. Будем ли мы реализовывать методы, выполняющие эти задачи, в наших объектах домена? Я так не думаю (например, в случае с XM мы добавили бы зависимости, связанные с XML, к нашим объектам домена ... Мне действительно грустно). Почему же тогда мы должны реализовывать методы реляционной БД в объектах предметной области, как говорит шаблон Ar?
Подводя итог, можно сказать, что шаблон AR может звучать проще и удобнее для небольших и простых приложений. Но когда у нас есть сложные и большие приложения, я думаю, что классическая многоуровневая архитектура - лучший подход.
источник
Исходный вопрос помечен рельсами и относится к Twitter, который построен на Ruby on Rails. Фреймворк ActiveRecord в Rails - это реализация шаблона проектирования Active Record Фаулера.
источник
Главное, что я видел в отношении жалоб на Active Record, - это то, что когда вы создаете модель вокруг стола и выбираете несколько экземпляров модели, вы в основном выполняете «select * from ...». Это нормально для редактирования записи или отображения записи, но если вы хотите, скажем, отобразить список городов для всех контактов в вашей базе данных, вы можете сделать «выберите город из ...» и получить только города . Для этого с Active Record потребуется выбрать все столбцы, но только с помощью City.
Конечно, разные реализации будут обрабатывать это по-разному. Тем не менее, это одна проблема.
Теперь вы можете обойти это, создав новую модель для конкретной вещи, которую вы пытаетесь сделать, но некоторые люди утверждают, что это больше усилий, чем пользы.
Я копаю Active Record. :-)
HTH
источник
Мне нравится, как SubSonic делает только одну колонку.
Либо
, или:
Но Linq по-прежнему король, когда дело доходит до отложенной загрузки.
источник
@BlaM: Иногда я просто реализовывал активную запись для результата соединения. Не всегда должно быть отношение Таблица <--> Active Record. Почему не «Результат оператора соединения» <--> Active Record?
источник
Я собираюсь говорить об Active Record как об шаблоне проектирования, я не видел ROR.
Некоторые разработчики ненавидят Active Record, потому что они читают умные книги о написании чистого и аккуратного кода, и в этих книгах говорится, что активная запись нарушает принцип единой возможности восстановления, нарушает правило DDD, что объект домена должен быть постоянным игнорирующим, и многие другие правила из таких книг .
Во-вторых, объекты домена в Active Record имеют тенденцию быть 1 к 1 с базой данных, что может считаться ограничением в некоторых системах (в основном n-уровневых).
Это просто абстрактные вещи, я не видел реальной реализации этого паттерна в Ruby on Rails.
источник
Проблема, которую я вижу с Active Records, заключается в том, что это всегда примерно один таблица. Это нормально, если вы действительно работаете только с одной таблицей, но когда вы работаете с данными, в большинстве случаев у вас будет какое-то соединение.
Да, соединение обычно хуже, чем отсутствие соединения вообще, когда дело доходит до производительности, но соединение обычно лучше, чем "фальшивое" соединение, если сначала прочитать всю таблицу A, а затем использовать полученную информацию для чтения и фильтрации таблицы B.
источник
Проблема с ActiveRecord заключается в том, что автоматически генерируемые запросы могут вызвать проблемы с производительностью.
В конечном итоге вы проделываете несколько неинтуитивных трюков для оптимизации запросов, которые заставляют задуматься о том, было бы более эффективным по времени написать запрос вручную.
источник
Хотя все остальные комментарии относительно оптимизации SQL, безусловно, верны, моя основная претензия к шаблону активной записи заключается в том, что он обычно приводит к несоответствию импеданса . Мне нравится, когда мой домен должен быть чистым и правильно инкапсулированным, что обычно сводит на нет все надежды на создание активной записи.
источник
Попробуйте установить полиморфные отношения «многие ко многим». Не так просто. Особенно, если вы не употребляете ИППП.
источник