Сегодняшние проблемы 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 страниц. При этом, широко известные проблемы с композицией ставят в тупик даже стреляных синьоров.

Разработчики молчаливо поддаются искушению дешёвых CRUD операций
Разработчики молчаливо поддаются искушению дешёвых CRUD операций

Чего мы на самом деле хотим?

Сейчас мы опустим разные вопросы, типа того, что жаль что 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.

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

Доктор едет-едет сквозь снежную равнину.

Порошок целебный людям он везёт.

Человек и кошка порошок тот примут,

И печаль отступит, и тоска пройдёт.

Ноль - Человек и кошка

Комментарии (30)


  1. PrinceKorwin
    28.01.2025 11:18

    Вы, случайно, не ActiveRecord изобрели?