Pull to refresh

Comments 31

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

Ну и на практике, два примера, которые среди меня до сих пор основа сомнений, оба про SQL Alchemy.

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

  • Нужно было сделать простой листинг записей с разбиением на страницы. В ORM был метод paginate, его и использовал. Всё было норм на тестовых данных, когда же загрузил пару сотен тысяч, внезапно оказалось, что SQL, который генерит ORM запрашивает все данные из таблицы, а потом выбирает нужный диапазон. Могли предупредить хотя бы :(

После этого к подобным оберткам отношусь скептически.

Второй пункт - чистой воды skill issue. Тот же EF пишет в логи весь sql, который он генерирует. И если вы не читали доки фреймворка, с которым работаете, то вам уже ничего не поможет

Sql я прочитал, когда мне это понадобилось. Но, используя ORM, я не предполагал ,что мне это понадобится.

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

Так бывает, что библиотекам может понадобиться мажорная миграция. Алхимии она определённо пошла на пользу(ИМХО).
А при необходимости поправить старый код, документация к легаси версии 1.4 всё ещё доступна.

Нужно было сделать простой листинг записей с разбиением на страницы. В ORM был метод paginate, его и использовал.

После этого к подобным оберткам отношусь скептически.

Возможно вы действительно использовали не голую алхимию, а обёртку над ним? Не припоминаю в sqlalchemy метода paginate да и вообще вспомогательного функционала для пагинации. В этом плане он всегда был близок к нативному sql, заставляю использовать offset/limit или самописные курсоры. Гугл выдаёт что метод paginate есть в flask_sqlalchemy, возможно дело в нём.

да, flask_sqlalchemy. Возможно, из любопытства проверю, как у текущей версии с этим paginate. Как сделать это на чистом SQL знаю, но вопрос "ну как так можно было сделать"?

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

Алхимия не менялась тыщу лет. Потом выкатил вторую версию и вот "оно постоянно меняется". При этом синтаксис второй версии намного ближе к тому что происходит в бд.

И нет, sql не один на всех. Попробуйте limit offset в разных СУБД, особенно пятнадцатилетней давности

Да, для каждого sql есть особенности, но это именно особенности, основа одинаковая. А ORM могут отличаться вообще в корне.

у ORM собственно тоже основы одинаковые. Это либо Active Record, либо Data Mapper. Соотсвтенно, там может быть или отсутствовать Identity Map и UnitOfWork. Я смотрю на условный c# Entity Framework после алхимии и не вижу кардинальных отличий, только особенности связанные с использованием другого языка программирования.

Тут суть скорее в том, что если вы не используете ORM, но хотите иметь сущности бизнес логики, не дай бог с коллекциями, но у вас всё равно получится слой, сильно напоминающий ORM, только менее продуманный и никому не известный (а скорее всего ещё и без документации). Я такое видел, это очень больно, готовые ORM лучше.

В документации алхимии можно выбрать версию. И да, прям изменения были при переходе с 1 на 2 версию, при этом в 1.4 пользователей максимально плавно готовили к обновлению, после которого миграция на 2 версию была элементарной (а ещё можно было и не обновляться, выбор каждого)

Когда начинаешь работать в реале, то понимаешь для чего нужна ORM. Потому что это модель(!) "чистый SQL" эту модель описать не может в силу ограничений в принципе. ORM даёт связи, события, кеширование, вменяемую валидацию, где не обязательно выкидывать исключение, а достаточно преобразования типа как на запись так и на чтение. ORM это уровень абстракции который приходится писать в любом случае если проект отличен от уровня "hello world". Но самое главное, грамотная ORM тебе даст подсветку ошибок и подсказки в редакторе кода.

Обидно, что не упомянут linq2db, даже на картинке

Вот очередная статья про ORM и опять речь про маппинг объектов. Но обходят стороной самый главный отличительный функционал ORM - Change Tracker. То, собственно, благодаря чему и происходит значительное сокращение времени разработки.

Просто в моём понимании ORM - это object-relational mapping. А про трекер я что-то забыл совсем. Он мне кажется таким естественным, что о нём и упоминать не надо. Вроде как у всех так должно быть.

Я сторонник чистого sql.

Но если мне придется делать очередной CRUD, то буду использовать ORM. ИМХО он только для этого и годится.

ORM менее подвержен ошибкам. Легко ошибиться в одном из тридцати полей, набирая запрос руками.

Очень забавное утверждение)

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

Это ещё даёт типобезопасность. Тип поля в классе всегда будет соответствовать типу данных колонки.

А это еще почему ? Если я запрошу

Select 1::int as field_a

А класс будет содержать field_a с типом string, то каким образом ORM обеспечит соответствие типов ? Если каким-то встроенным тайп-кастом, то, на мой взгляд, это не очень хорошо, так как не всегда понятно что к чему приводить(кто является эталоном - БД или приложение).

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

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

Согласен с тем, что в голом SQL через пару лет может что-то подзабыаться.

Но не совсем понимаю этот момент:

Это если используется ORM, тогда программа просто не скомпилится

Разве ORM при компиляции делает какие-то проверки между моделями и таблицами DB? Это какой-то функционал EF или в других ORM есть похожий механизм(могу судить только по SQLAlchemy - там такого нет)

Или речь про тесты ? В таком случае разницы между rawSQL и ORM быть не должно(все упрется в логику тестов).

В NET есть весьма интересный механизм - деревья выражений (в очень грубом описании, это исходники кода внутри кода). Этот механизм позволяет таким ORM как EF сопоставлять запросы с заранее зарегистрированными моделями таблиц в ORM на уровне компиляции. Ответственность за синхронность структур между моделями ORM и таблицами в DB, по-прежнему, лежит на разработчике. Но есть механизмы сильно упрощающие эту задачу. К примеру, автоматизированная генерация миграций для изменения структуры таблиц в DB (работает на рефлексии) при изменении моделей ORM. Таким образом можно добиться того, работая с таким ORM не нужно писать не единого терма из sql. И почти все твое взаимодействие с DB будет проверяться ещё на этапе компиляции. А также на этапе написания кода за счёт сложностей ide. Кстати, по этой же причине у многих в NET складывается неверное представление, что при использовании ORM не нужно знать SQL. Но это только до первой проблемы с производительностью.

Как может выглядеть задача на переименование колонки с такой orm, если в проекте отсутствуют sql вставки:

  1. Переименовывается поле в моделе ORM. Попутно переименовываются все места использования этого поля в коде за счёт средств рефакторинга ide.

  2. Генерируется миграция для DB через утилиту ORM. Здесь по хорошему нужно перепроверять правильность миграции.

  3. Код компилируется.

  4. При запуске приложения миграция сама изменяет структуру таблиц в DB.

Да, отношение к ORM в NET полностью отличается от других платформ разработки.

Ого, не знал о такой особенности в NET. Я знал, что там у ребят вообще отдельная кухня, но чтоб там ORM были настолько прокаченными - нет.
Благодарю за ответ.

Сущность ORM первоисточник, его отражение это запись в базе. И тут есть варианты в зависимости от структуры. ORM может создавать таблицы под себя с учётом описываемых полей, и/или может отдавать и принимать данные в нужном типе, например когда свойства объектов хранятся в одной таблице и имеют разные типы, классический пример это wordpress.

Ни слова не сказано про основную боль работы с базами данных, это миграции, когда меняется структура базы данных. Единственная orm, которая хороша в этом, это redbeans, так как автоматически меняет структуру бд в соответствии с кодом. А Entity core неплохо реализована авто генерация миграций, в других с этим вообще глухо и непонятно, как разрабатывать софт для декстопа или мобилок, если нет нормальной реализации миграций

Хороший вопрос. Но упоминанием тут не обойтись, это отдельная и глубочайшая кроличья нора.

Я считаю, что задача ORM - работать в рантайме. Весь тулчейн вокруг процесса разработки должен обеспечиваться внешними инструментами. Собственно, я такой инструмент и делаю. Для миграций я сделал отдельный вид генераторов, которым на вход попадает дифф базы данных, а генератор уже под конкретный орм делает миграцию. Это нужно тем, кому необходимо держать историю миграций и создавать ddl откатов.

Это работает так: вы работаете с тестовой и локальной базой и изменяете её без оглядки на миграцию. Когда ваша фича заработала, вы просто сравниваете модель с базой прода и вам генератор выкатывает миграцию. Можно и без миграции накатить изменения на прод, дифф сразу предлагает выбрать изменения, которые нужно накатить.

Ну вот не надо ORM заниматься миграциями.

Читайте мой, последний пост. Все давно реализовано в крупных корпоративных решениях. Не нужно "изобретать велосипед" .

В наше время ИИ делает использование ORM ещё менее обоснованным. SQL сильнее многих языков похож на человеческий язык, и модели щёлкают его как семечки. Так же кодогенерацию никто не отменял, и можно найти очень неплохие генераторы, которые напишут вам всё на основе SQL, который вы ему дадите.

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

Использование orm требует определенного подхода, это не просто надстройка над sql. В erp odoo трёхслойная надстройка orm над postgresql строит сложную систему моделей данных , связей между ними, наследование и расширение базовых моделей, обеспечивает систему безопасности доступа к ним и к ui пользователя вместе с отображением данных в нем. Так, что здесь SQL некий нижний слой, обеспечивающий orm доступ к данным postrgresql, всю остальную сложную работу по архитектуре бизнес модели системы берет на себя orm. Данную архитектуру современные AI модели знают достаточно хорошо и быстро пишут под нее любую бизнес модель под заданные требования. Роль разработчика сводится не в борьбе с "монстром" в лице orm (который "пилят" 1000 индусов на протяжении 20 лет), а в быстром написании бизнес модели под требования заказчика. Разработчику, не нужно "видеть" как эта "кухня" работает внутри системы, ему достаточного понимать, как быстро "закодить" свою бизнес модель. Вы когда покупаете автомобиль, навряд ли, кроме изучения органов его управления, пытаетесь вмешиваться в работу его двигателя и пытаться там что то переделать. Так и с современными orm системами. Это своего рода готовый автомобиль, которым просто нужно научиться управлять. Что касается разных "не до orm" надстроек, созданных разными любителями типа Lazarus и прочими, здесь, конечно, особого смысла нет их использовать, так как доведение их использования до большой рыночной бизнес модели может потребовать огромных денежных средств и человеческого труда. В современном конкурентном рынке полно уже готовых бизнес orm решений, над которыми крупные компании трудились не один десяток лет.

ORM -- Вьетнамская война в сфере информационных технологий;)))

Я просто отмечу, что на моем опыте оверхед от Hibernate - это 20% CPU profile в среднем по больнице. И обычно в этих 20% происходит примерно ничего полезного с точки зрения бизнес-логики.

Всё равно надо писать свои функции CRUD-операций (Create+Read+Update+Delete),
ORM эти функции сам не пишет, он только помогает их легче написать.
Программисту нужны готовые CRUD-операции, а не ORM.
ORM это лишняя прослойка между программистом и БД.
А готовые функции CRUD-операций сам напишет кодогенератор:
https://github.com/ManyakRus/crud_generator

Sign up to leave a comment.

Articles