Честный взгляд на Spring Data JPA

«Я всегда прав, на этот раз прав как никогда». Linus Torvalds

Стоит сразу сказать, что задача этой статьи не в том чтобы кого-то обидеть, а в том чтобы развенчать миф «нормально делай — нормально будет» в контексте Spring Data JPA. Неконтролируемый паровоз движется в случайном направлении. Можете считать это криком души, моим «хватит»!

a44f134b94e25c3c74e8c9f93f9e2610.png

@Entity это плохо

Энтити это чудовищное, неполноценное изобретение. Энтити просто не позволяют реализовать все необходимые сценарии. Энтити фиксируют схему, что фактически означает монопольный доступ к СУБД. Кстати, как насчет запроса к промежуточной таблице в случае n: n связи? Чтобы сделать миграции, вам придется использовать sql-мигратор, a.k.a flyway. Также энтити не дадут вам sql-проекций из коробки. Если учесть все эти минусы напрашивается закономерный вопрос, а зачем нам @Entity. Ответ прост, вы добавляете энтити потому что без них не запустится Spring Data JPA.

Сложность получения проекций базы данных

Вообще, думаю мало кто поспорит (пишите в комментарии), что сделать проекцию с базы данных должно быть просто, даже структурированную. Но постойте, вам придется использовать Spring Data JPA! Выбирайте на любой вкус: JPQL (весьма ограниченный), EntityGraph (ну это вообще шутка), Criteria API, программирование на строках в аннотациях Spring, ваше любимое программирование на интерфейсах, программирование на именах методов, возможно еще XML или квери-билдер. Часто это кончается тем, что люди забивают на все это и просто отправляют полный EntityGraph на фронтенд, пример: https://github.com/spring-petclinic/spring-petclinic-rest/tree/master. 

1749385f5027324f7bc922c919615b3d.png

Тем временем когда аналитики пишут 100кк проекций в секунду на превосходном SQL с complete набором функций, попивая куба-либре на Мальдивах, нам приходиться с этим возиться.

Невероятное количество документации и технологий

Hibernate это база Spring Data JPA, он один вносит 600+ страниц демеджа документации и миллионы строк кода. Думаю если бы кто-то решил распечатать полную документацию на Spring Data JPA и его друзей, лесам Амазонки пришлось бы тяжко. Функциональность этих библиотек постоянно пересекается, то есть надо тратить мозго-часы на решение задачи выбора. И всё вот это вот ради того чтобы делать тривиальные вещи, как мы сюда попали? Сравните это с JDBC + SQL, на которых можно сделать всё, почему мы так много платим?

Отвратительное дебагабилити

Абсолютно неясно что там Spring сгенерировал и как всё это отлаживать в общем случае. Вся валидация исключительно в Runtime, всё работает на Reflection API. Вставляются специальные костыли чтобы это работало с AOT Java Compiler. Вам нужно прожать все кнопки в приложении чтобы убедиться, что вы где-то неправы, это называется руками жар загребать (стакан водки и за станок).

Названия методов как язык запросов

  1. Нарушает Java naming convention. (в принципе дальше можно не читать)

  2. Write-only.

  3. Ограничено одной таблицей.

  4. И зачем было начинать?

Пример в студию (https://vladmihalcea.com/spring-data-query-methods/):

List findAllByPostAndStatusAndReviewLikeAndVotesGreaterThanEqualOrderByCreatedOn(
    Post post,
    PostComment.Status status,
    String reviewPattern,
    int votes
);

Автора статьи заботливо указывает:

TL; DR, Don«t write query methods that cannot even fit on the screen.

Лично на мой экран не влезло.

20 лет нерешенных проблем с оптимизацией

Сколько нужно еще времени чтобы решить проблемы с оптимизацией? Может ещё 20? Не говоря о том что у этой штуки жуткий code-base, на самом деле получилось так, что проблемы с оптимизацией решать придется нам, контролировать форму запросов, профиль нагрузки и т.д. Это помимо того, что нам еще и в СУБД эти запросы придется оптимизировать. Умножаем сложность. А вот если просто писать native-query в СУБД, этой проблемы нет. Лично по моему мнению вообще все эти затеи с хранением какого-то состояния базы данных на Java-сервере, это химера, но об этом дальше.

Я уже лично и не жду

Я уже лично и не жду

Ортогональность приложения. Контроллер, сервис, репозиторий, дао, энтити, мапстракт

На типовом проекте вам нужно поменять порядка 10 файлов для того чтобы добавить/изменить хоть какую-то функциональность. Не зря люди стараются убежать от этой реальности в low-code решения. Переиспользование энтити в разных контроллерах/сервисах уменьшает ортогональность (single-responsibility). Даже самим java-программистам в лом писать эти груды кода, что приводит к экономии на декомпозиции и появлению вот таких вот карликовых монстров, сервисных классов с 24 методами: https://github.com/spring-petclinic/spring-petclinic-rest/blob/master/src/main/java/org/springframework/samples/petclinic/service/ClinicService.java. И при этом мы, не замечая бабайки, продолжаем рассказывать про SOLID принципы на собеседованиях.

Стейтфул глина. Транзакции

Современное программирование стремится к большей декларативности кода, явности и минимизации количества состояний системы. Здесь же мы получаем полный букет в виде: Entity Life Cycle, Implicit границ транзакций, мутных propagation.requires_new, потенциальных неявных savepoint«ов, detached коллекции, кеша второго уровня (который думает что он один в системе). Видя ваши циклы в которых вы месите коллекции , «Senior»-разработчики думают, что они не зря писали свои лабы на паскале именно в таком стиле.

Вывод

Паровозик прицепил уже слишком много вагонов и мосты (спины программистов) уже вышли из проектного режима эксплуатации. Надо что-то с этим делать. Давайте думать, _, подсказывайте. Что вы мозги _, подскажите как _ сделать _, по красоте! (Паша Техник)

х/ф Майор Пейн

х/ф Майор Пейн

© Habrahabr.ru