Сегодняшние проблемы ORM
Проблемы ORM хорошо известны - именно поэтому вы и читаете эту статью. Подробно о проблемах конкретной реализаций ORM на Java мы писали ранее. Все тезисы этой статьи распространяются и на Python с SQLAlchemy и другие ЯП. Начнем с определения ORM в контексте, например, Java.
ORM - СУБД, написанная на Java в качестве бекэнда которой является другая СУБД.
Почему так?
свой язык декларации схемы данных
свой язык запросов (Criteria Api, HQL, JPQL)
свой оптимизатор (anti N+1)
свой pl/SQL - API вокруг Entity Manager, Sessions со скриптингом на Java
Буква “О” в названии нужна по двум причинам. Во-первых потому что Java (как и многие другие) - это объектно ориентированный язык (что бы это не значило). Во-вторых – подчеркнуть размеры дыры в абстракции ØRM.
В такой постановке сразу виден корень зла ORM – вы используете сразу ДВЕ СУБД вместо одной. Например, Hibernate и PostgreSQL.
Всеобъемлющий мануал прикладного программиста (включая вопросы производительности и сам язык запросов, pl/SQL) для PostgreSQL, составляет около 700 страниц. Middle Vulgaris уверенно знает страниц 200 из них. Hibernate, как минимум, удваивает необходимый объем знаний, добавляя еще 600 страниц. При этом, широко известные проблемы с композицией ставят в тупик даже стреляных синьоров.
Чего мы на самом деле хотим?
Сейчас мы опустим разные вопросы, типа того, что жаль что ORM фреймворки так и не научились самостоятельно решать вопросы оптимизации, композиции и сдвинули все эти проблемы на Петровича. Самое важное это нейро-моторесурс разработчика и на что его потратить. Его можно потратить на то чтобы научиться делать нормальный софт (например, научиться обрабатывать ошибки), либо запрыгнуть в паровозик Spring Data JPА.
Давайте, наконец, признаемся, что нам нужна просто хорошая библиотека для подключения к базе данных, легко решающая типовые задачи backend разработки.
Правильный API для взаимодействия с базой.
Весь нужный нам API:
connection.fetch(query, args) -> result
И это не шутка. Немного развернем идею:
Query пишется на нативном языке базы (например, SQL)
Query проверяется на этапе компиляции, типы аргументов тоже
Typeof(result) выводится автоматически, что избавляет от ручного написания DTØ. Это приводит к образованию единого типового пространства между бэкэндом и схемой базы
С помощью SQL вы по месту получаете нужные вам проекции с базы. Это позволит отказаться от некоторых сомнительных “слоев” вроде сущностей, репозиториев и “мэпперов”. Ситуацию с сервисами мы описывали ранее.
SQL базы имеют некоторую специфику, вроде результата в табличной (строковой) форме и некоторых дополнительных усложнений, вроде разницы между “просто запросом” и вызовом хранимых процедур, всяких дополнительных вещей типа generated keys и update count, доступ к которым не всегда есть на уровне запроса. Все это тоже немного влияет на итоговый API.
Не торопитесь писать, что это очередная статья, которая к чему-то призывает, но не дает никаких решений! Новое безальтернативное решение появится совсем скоро.
Доктор едет-едет сквозь снежную равнину.
Порошок целебный людям он везёт.
Человек и кошка порошок тот примут,
И печаль отступит, и тоска пройдёт.
Ноль - Человек и кошка
PrinceKorwin
Вы, случайно, не ActiveRecord изобрели?