Без ORM
UPD Продолжение
В текущем проекте мы используем SQL. Запросы, миграции, триггеры – все это чистый скуль, написанный нами. Сперва было непривычно, за годы работы с Джангой я напрочь забыл язык запросов. Теперь, напротив, меня дико прет. Рассказываю плюсы и минусы такого подхода.
Прежде всего, мы используем библиотеку
HugSQL. Работает она любопытным образом. Вы пишете
обычный .sql
файл с запросами. Перед каждым запросом размещаете
структурированный комментарий. В нем указываете имя функции и дополнительные
директивы. Затем библиотека парсит файл и динамически создает в модуле функции с
аналогичными названиями.
Пример:
-- :name create-user! :<!
-- :doc creates a new user record
INSERT INTO users
(first_name, last_name, email, username, password, phone)
VALUES (:first_name, :last_name, :email, :username, :password, :phone)
RETURNING *
(let [user (db/create-user! {:username "ivan"
:email "test@test.com"
:password "123"
:phone "223-322"
:first_name "test"
:last_name "test"})])
Разберу минусы данного подхода. Во-первых, приходится писать больше кода. В
Джанге или Рельсах достаточно вызвать у объекта метод .save()
. В зависимости
от состояния объекта будет выполнен запрос вставки или обновления. В нашем
случае нужно писать два отдельных запроса.
Во-вторых, приходется потратить время на повторное изучение SQL и конкретной базы данных, в нашем случе – Постгреса. Потому что все ORM-системы превращают базу в хранилище, то есть черный ящик. Есть модели, пользуйся, а внутрь не лезь. И вообще, объекты предлагают больше синтаксического сахара.
Плюсов, на мой взгляд, больше. Прежде всего, приходит понимание того, что происходит в БД. Как устроена структура, какие фукнции и триггеры объявлены, как связаны сущности.
Появляется возможность свободно строить джоины, объединения. Мы активно используем триггеры чтобы нормализовать поля. Добавляем констрейнты (ограничения), чтобы предотвратить запись неверных данных.
Если база сопровождается ORM-системой, скорее всего, работать с ней из другого языка будет невозможно. Потому что значения по-умолчанию, триггеры и авторизация пользователей, как правило, реализованы силами ORM, а другая система ничего про это не знает. У нас такое невозможно. Что Кложа, что Питон не смогут записать в базу кривые данные.
Мы активно используем расширения Постгреса и специальные типы данных. JSON, геолокация, генерация токенов и случайных величин. Не приходится писать это в коде. Например, если из двух разных мест выполнить вставку в эту таблицу, будет сгенерирован случайый токен на уровне БД. А если делать это в коде, придется копипастить.
В логах Постргреса я вижу написанные в своем стиле запросы. ORM, как правило,
генерит адский поток, который невозможно прочесть. Если ORM-запрос содержит
что-то посложней чтения или вставки, например, group by
, having
, join
,
union
, приходится его дебажить. Потому что далеко не факт, что результат будет
таким, как вы хотите. Например, Алхимия в Питоне не может правильно сделать
union
, хоть убей. А как указать, что тебе нужен именно левый джоин, а не
внутренний?
Не приходится перенастраивать мозги с одной ORM на другую. Помню, одновременно работал в двух проектах, в одном Джанга, в другом Алхимия. Так замучился запоминать особенности каждой. А чистый скуль не врет.
Выражаясь терминами Рича Хики, ORM это легко (easy), а SQL – просто (simple). Это не синонимы. Легко значит – быстро, а просто – прозрачно. Здесь я не буду умничать, а просто советую послушать доклад.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter
Lens, 11th Nov 2016, link
Благодаря чтению вашего блога, крепко подсел на кложу )). Сперва было непривычно очень. А теперь "прет", если позволите. Пока я где-то в начале пути, что-то написать сложное с использованием Люминус, например, не могу, но задачки на codewars или очень простое с помощью compojure, ring, http-kit, вполне получается. Так что как минимум одного человека, можете записать себе в актив :). В качестве пожелания: пишите про кложу больше.
Что до SQL, то в свое время именно благодаря тому, что столкнулся с чистым оракловым SQL - стал вообще программировать, и от инженерии переквалифицировался в программисты. Всегда было интересно писать чистые запросы, есть в этом какая-то магия или тайна. Потом же наоборот столкнулся с миром ORM. И магии стало больше, но пропала возможность писать запросы вообще, т.к. пишешь только get() save() insert() и тд. и в дебаг-панелях только простыни из запросов, в которых, и правда, трудно что-то найти.
А на кложе видел DSL библиотеку для написания sql, почему ее не используете? Кажется Korma называлась или ей подобная. Мне кажется это более удобным, правда может быть читаемость чистого SQL выше наверное, как более привычная. Тогда если сравнивать не ORM, а DSL в Korma или ей подобной библиотеке с чистым SQL, то что из этого считать simple, а что easy )
P.S. простите за многословность )
Ivan Grishaev, 11th Nov 2016, link , parent
Да, Корма -- почти полноценная ORM, а кроме нее есть DSL для описания запросов структурами данных. Но, во-первых, HugSQL -- часть Luminus, а во-вторых, у ORM и DSL трудности со сложными запросами. Так или иначе придется писать куски на сыром скуле.
Lens, 11th Nov 2016, link , parent
тогда выбор конечно более очевиден, если хочется гомогенности кода, чтобы не было кусков на DSL, скажем, и кусков на чистом SQL там где это необходимо. Я ошибаюсь или в Django тоже проблемы со сложными запросами, и именно это имеют ввиду когда говорят о недостатках Django ORM, и там тоже приходится прибегать к сырому SQL? Почему-то чаще я слышал об этом именно в контексте Django ORM. Хотя есть и те кто считают, что просто их не умеют готовить.
toporovvv, 12th Nov 2016, link
Тоже недавно думал над этим вопросом. Меня дико бесит работать с Doctrine ORM: получается, что вместо получения данных мне всё время приходится с ней бороться. Почему вместо нормального SQL я должен учить какой-то DQL? Почему я не могу нормально использовать функции базы и агрегацию - приходится объявлять перемнные в запросе и подготавливать данные на php. Это раздражает неимоверно.
Очень хочется найти бибилиотеку для работы с базой, где были бы простые методы для простых вещей (all(), filter(), insert(), update(), delete() - всё-таки ОРМ делает много "черновой работы") и при этом можно было бы писать на чистом SQL сложные запросы с автомаппингом на модели (чтобы не думать, как перевести запрос с многоэтажными джойнами, агрегацией и каким-нибудь условным ORDER BY в запрос на ОРМе).
С другой стороны, переносить логику работы в базу (увлекаясь хранимыми процедурами и триггерами, например) не рекомендуется, потому что стороннему человеку потом сложно будет сопоставить логику кода приложения и базы в единое целое.
Ivan Grishaev, 13th Nov 2016, link , parent
В Джанго есть трудности со сложными запросами, так же как и в любой другой ОРМ. Это случается редко, но все же. В основном, коде требуются возможности именно этой БД, которых нет в ОРМ. Например, рекурсивные запросы. Я лично не вижу ничего страшного в сыром скуле, но в среде тех, кто работает исключительно с РОМ, это считается моветоном. Поэтому если сразу писать на SQL, становишься свободен от этих предрассудков.
Ivan Grishaev, 13th Nov 2016, link , parent
Бизнес-логику переносить не стоит, конечно, например, расчет скидок или начисления бонусов. Потому что бизнес-логика постоянно меняется. А вот утилитарные вещи, например, приведение емейла к нижнему регистру -- вполне норм.
Lens, 13th Nov 2016, link , parent
Спасибо, в общем и целом мне нравится в сыром SQL один-два момента, но оказалось что уже написано продолжение ). А предрассудки, на мой взгляд, это всегда плохо. Я бы даже сказал, что это совершенно идиотская вещь. Они ограничивают человека, по определению.