Сохранение в базу, отправка email - это вещи которые не связаны с доменным ядром системы. Это все уже делается на других слоях (о чем, собственно, статья и говорит). В ядре системы должны быть лишь операции, меняющие саму бизнес-сущность. И да, для каких-то сложных сущностей может получится достаточно внушительный по размеру класс. Но как по мне, гораздо безопаснее держать в одном месте все методы (функции), которые могут менять бизнес-сущность и легко получать их список, чем иметь простую структуру данных и менять ее поля в разных функциях, которые по всему проекту раскиданы. Гораздо удобнее, когда у каждой бизнес-сущности есть "владелец", который единственный, кто может ее менять и предоставлять другим частям системы ограниченный API для взаимодействия. Так почему же не объединить это в одном куске кода (классе) - в этом и была главная задумка классов и ООП. Если на примере веб приложения говорить, то мне больше нравится, когда контроллер получает бизнес сущность из слоя работы с базой, вызывает у сущности метод с нужной бизнес логикой для ее изменения, передает измененную сущность для сохранения. А вот уже на слое сохранения данных в базу как раз и формируются все нужные ивенты, на которые потом триггерится отправка email, например. Но гораздо более популярен подход, когда контроллер дергает некую функцию, в которой по факту мешанина из бизнес логики и работы с внешними системами (база, очереди, другие сервисы). В результате, отправка email до комита транзакции выглядит вполне себе даже хорошим решением (на самом деле - не делайте так)
Мне кажется ООП уже несколько лет как в опале и даже в исконно-оопешых языках уже все пишут в "функциональном" (по факту, в процедурном) стиле. Когда есть объекты для хранения данных (структуры) и есть объекты-сервисы, содержащие функции для обработки переданных данных. Но как по мне, так ООП вполне хорошо подходит для написания бизнес логики (ядра системы). Так называемая, rich model, когда объект позволяет собрать в одной программной сущности данные и логику их обработки. Очень удобно, когда у тебя вместо модуля из набора структур и функций есть экземпляр объекта 'Курс', например, и любой редактор выдаст тебе список доступных действий с ним (его публичные методы). Правда давно уже не видел, чтоб кто-то такой подход практиковал. Во многом из-за опасений, что мутабельный стейт создаст проблем при многопоточной обработке. Но как часто в реальности есть потребность менять один экземпляр предметной области в ядре системы несколькими параллельными потоками?
А на сколько сложно сделать, чтоб плагин граф зависимостей между классами и пакетами строил на основании импортов? У меня чаще в больших легаси проектах как раз задача правильно структуру проекта переделать, чтоб обеспечить low coupling, high cohesion и вот это вот все. Тулы для визуализации зависимостей очень этот процесс упрощают
но большой minp map, который, по сути, рисует то же дерево у вас, как я понимаю, только в виде "солнышка" тоже мало поможет. Ну либо у вас на карте получается более понятная структура, чем текущая структура папок. Но тогда что мешает сделать рефакторинг и перестроить структуру папок аналогично той структуре, котрую в mind map строится? Тогда не будет "лишнего" промежуточного слоя в виде аннотаций, которые могут начать отставать от развития проекта (как выше в комментариях отмечают)
Спасибо, теперь я понял в чем различие наших взглядов. Просто я к CRUD отношу еще сервисы, которые что-то берут из базы, меняют и сохраняют изменения обратно. Т.е. когда у нас объекты-энтити мутабельные. Для таких сценариев да, ORM идеальное решение. А вот Spring Data Jdbc как раз не про "синхронизацию" с базой. Это просто более простой способ делать jdbc запросы и мапить результаты на объекты. Тут нет энтити в понимании ORM, т.к. у них нет жизненного цикла. Поэтому для сервисов, в которых база, это лишь как еще одна внешняя система (например, некий аналитический сервис), я и предпочитаю использовать немутабельные ентити и что-то полегче, чем полноценный ORM.
На мой взгляд, задача классического ORM (и JPA в частности) - "синхронизировать" состояние объектов приложения (энтити) с соответствующими записями в таблицах базе, учитывая все их связи между собой. А это, по сути, и есть CRUD операции.
Поэтому очень хотелось бы, чтоб вы как-то более детально раскрыли ваше видение философии ORM и суть энтити
Если нет потребности обновлять энтити в базе, то вся мощь JPA становится не особо нужна, даже наоборот начинает мешать. А если не пользуешься основным функционалом большой библиотеки, то как-то избыточно ее в проект затаскивать ради каких-то второстепенных удобств, которая она может дать
Да, но как отметил в ps, в этом конкретном случае на старой версии Oracle средствами базы не удалось найти способа id вытащить из insert запроса. Если только процедуру в базе писать
Я очень много использовал JPA и использую, когда это оправдано. JPA это идеальное решение для CRUD сервисов. Но когда нужны сложные запросы к базе, то даже на голом jdbc получается проще писать и поддерживать. Именно поэтому Spring Data JDBC манит своей идеей получить преймущества из обоих миров
В концепции DDD и гексагональной архитектуры entity запросто может быть особым типом dto для взаимодействия с внешним хранилищем. А для dto рекорды вполне себе удобны, при остуствии дата-классов. Хотя, согласен, что, могут быть сценарии, когда это может привести к проблемам
Если использовать SQL для запросов, то, конечно, придется затачиваться под конкретную базу данных. Но если при этом все запросы собраны в одном месте, а не разбросаны по коду, то миграция на другую базу не занимает много времени. Зато полная свобода в оптимизации запросов с учетом специфики конкретной базы
JOOQ пока ни разу нигде не попадался, потому не могу его сравнить со спринговым JDBC. Но в приведенном примере не увидел, какое преймущество он добавляет. При этом запрос на SQL, на мой взгляд, проще поддерживать, т.к. SQL больше людей знает, чем api JOOQ
Сохранение в базу, отправка email - это вещи которые не связаны с доменным ядром системы. Это все уже делается на других слоях (о чем, собственно, статья и говорит).
В ядре системы должны быть лишь операции, меняющие саму бизнес-сущность.
И да, для каких-то сложных сущностей может получится достаточно внушительный по размеру класс. Но как по мне, гораздо безопаснее держать в одном месте все методы (функции), которые могут менять бизнес-сущность и легко получать их список, чем иметь простую структуру данных и менять ее поля в разных функциях, которые по всему проекту раскиданы. Гораздо удобнее, когда у каждой бизнес-сущности есть "владелец", который единственный, кто может ее менять и предоставлять другим частям системы ограниченный API для взаимодействия. Так почему же не объединить это в одном куске кода (классе) - в этом и была главная задумка классов и ООП.
Если на примере веб приложения говорить, то мне больше нравится, когда контроллер получает бизнес сущность из слоя работы с базой, вызывает у сущности метод с нужной бизнес логикой для ее изменения, передает измененную сущность для сохранения. А вот уже на слое сохранения данных в базу как раз и формируются все нужные ивенты, на которые потом триггерится отправка email, например. Но гораздо более популярен подход, когда контроллер дергает некую функцию, в которой по факту мешанина из бизнес логики и работы с внешними системами (база, очереди, другие сервисы). В результате, отправка email до комита транзакции выглядит вполне себе даже хорошим решением (на самом деле - не делайте так)
Мне кажется ООП уже несколько лет как в опале и даже в исконно-оопешых языках уже все пишут в "функциональном" (по факту, в процедурном) стиле. Когда есть объекты для хранения данных (структуры) и есть объекты-сервисы, содержащие функции для обработки переданных данных.
Но как по мне, так ООП вполне хорошо подходит для написания бизнес логики (ядра системы). Так называемая, rich model, когда объект позволяет собрать в одной программной сущности данные и логику их обработки. Очень удобно, когда у тебя вместо модуля из набора структур и функций есть экземпляр объекта 'Курс', например, и любой редактор выдаст тебе список доступных действий с ним (его публичные методы).
Правда давно уже не видел, чтоб кто-то такой подход практиковал. Во многом из-за опасений, что мутабельный стейт создаст проблем при многопоточной обработке. Но как часто в реальности есть потребность менять один экземпляр предметной области в ядре системы несколькими параллельными потоками?
Не очень понял, зачем так усложнять в примере с "Выполнение частых Scheduled задач". Почему просто не взять newSingleThreadScheduledExecutor?
Если речь только про Kafka, то там есть Schema registry (https://docs.confluent.io/platform/current/schema-registry/index.html). На нем прекрасно реализуется API First подход
А на сколько сложно сделать, чтоб плагин граф зависимостей между классами и пакетами строил на основании импортов?
У меня чаще в больших легаси проектах как раз задача правильно структуру проекта переделать, чтоб обеспечить low coupling, high cohesion и вот это вот все. Тулы для визуализации зависимостей очень этот процесс упрощают
но большой minp map, который, по сути, рисует то же дерево у вас, как я понимаю, только в виде "солнышка" тоже мало поможет. Ну либо у вас на карте получается более понятная структура, чем текущая структура папок. Но тогда что мешает сделать рефакторинг и перестроить структуру папок аналогично той структуре, котрую в mind map строится? Тогда не будет "лишнего" промежуточного слоя в виде аннотаций, которые могут начать отставать от развития проекта (как выше в комментариях отмечают)
А почему бы просто не сделать понятную структуру проекта? То же дерево получится. Ну разве что http методы не будут видны.
Спасибо, теперь я понял в чем различие наших взглядов. Просто я к CRUD отношу еще сервисы, которые что-то берут из базы, меняют и сохраняют изменения обратно. Т.е. когда у нас объекты-энтити мутабельные. Для таких сценариев да, ORM идеальное решение.
А вот Spring Data Jdbc как раз не про "синхронизацию" с базой. Это просто более простой способ делать jdbc запросы и мапить результаты на объекты. Тут нет энтити в понимании ORM, т.к. у них нет жизненного цикла. Поэтому для сервисов, в которых база, это лишь как еще одна внешняя система (например, некий аналитический сервис), я и предпочитаю использовать немутабельные ентити и что-то полегче, чем полноценный ORM.
oracle 8-ка
На мой взгляд, задача классического ORM (и JPA в частности) - "синхронизировать" состояние объектов приложения (энтити) с соответствующими записями в таблицах базе, учитывая все их связи между собой. А это, по сути, и есть CRUD операции.
Поэтому очень хотелось бы, чтоб вы как-то более детально раскрыли ваше видение философии ORM и суть энтити
Если нет потребности обновлять энтити в базе, то вся мощь JPA становится не особо нужна, даже наоборот начинает мешать. А если не пользуешься основным функционалом большой библиотеки, то как-то избыточно ее в проект затаскивать ради каких-то второстепенных удобств, которая она может дать
Да, но как отметил в ps, в этом конкретном случае на старой версии Oracle средствами базы не удалось найти способа id вытащить из insert запроса. Если только процедуру в базе писать
да для батчей тут совсем примитивные вещи только, приходится на обычный jdbc переключаться
> вы пытаетесь сидеть на двух стульях
именно ) И пока Spring Data JDBC мой основной кандидат на средство, которое позволит этого достичь.
> Подозреваю что все развитые библиотеки-помошники в работе с JDBC вкурсе об этой возможности
Собственно удивление, что Spring Data JDBC это не умеет и предлагает это решать, на мой взгляд, кривовато, и стало причиной этой статьи
Я очень много использовал JPA и использую, когда это оправдано. JPA это идеальное решение для CRUD сервисов.
Но когда нужны сложные запросы к базе, то даже на голом jdbc получается проще писать и поддерживать. Именно поэтому Spring Data JDBC манит своей идеей получить преймущества из обоих миров
В концепции DDD и гексагональной архитектуры entity запросто может быть особым типом dto для взаимодействия с внешним хранилищем. А для dto рекорды вполне себе удобны, при остуствии дата-классов. Хотя, согласен, что, могут быть сценарии, когда это может привести к проблемам
Если использовать SQL для запросов, то, конечно, придется затачиваться под конкретную базу данных. Но если при этом все запросы собраны в одном месте, а не разбросаны по коду, то миграция на другую базу не занимает много времени.
Зато полная свобода в оптимизации запросов с учетом специфики конкретной базы
JOOQ пока ни разу нигде не попадался, потому не могу его сравнить со спринговым JDBC. Но в приведенном примере не увидел, какое преймущество он добавляет. При этом запрос на SQL, на мой взгляд, проще поддерживать, т.к. SQL больше людей знает, чем api JOOQ
Spring Data JDBC не использует Hibernate. И reflection, вроде, тоже
Как раз jpa (hibernate) и не хочется использовать..