Как стать автором
Обновить

Комментарии 12

  1. Невозможно проверить бизнес-логику с помощью unit-тестов. Обязательно нужны интеграционные (и довольно много).

  2. Если домен сложный, подобный подход быстро приведет к спагетти-коду.

  3. Риск дублирования кода, который может привести к неожиданным багам при дальнейшей эволюции системы.

  1. Если вы пишете тесты не ради галочки и покрытия, а в целях повышения качества, то вам все равно не обойтись без интеграционных тестов БД со всеми ее фокусами.

  2. Хибер и альтернативные решения как-то принципиально защищены от спагетти-кода при росте сложности? На каких примерах вы замеряли "быстроту" сползания джука в спагетти-код?

  3. Хибер и альтернативные решения как-то принципиально защищены от риска дублирования кода и неожиданных багов?

Итого 2 ваших "минуса" джука на самом деле являются особенностями разработки ПО в целом. Соответственно, все дальнейшие рассуждения идут из сомнительного тезиса.

  1. не соглашусь т.к отдельно тестировать бд и бизнес логику это одно, намного проще, а вот тестировать бизнес логику и бд совместно это абсолютно разные вещи. Я уже устал править тесты на 20 и более ассертов просто потому что 'иначе не получится', а нафига вы сильную связность создали.

Случай, когда вы прям вынуждены тестировать вместе бизнес-логику и БД - это вопрос к вашей архитектуре, а не к джуку или другому фреймворку. Здесь у автора тоже имеет место избиение чучела. Хоть на хибере, хоть на голом JDBC можно наваять очень труднотестируемые вещи.

Что используете у себя на проекте?

Не используем ORM

Соглашусь с автором что для каждой конкретной цели есть свой инструмент. Единственный момент - возможно вы упустили или не указали в статье, что у Hibernate также есть возможность проверки кода во время компиляции. Для этого нужно использовать Criteria API и библиотеку генерации метамоделей классов hibernate-jpamodelgen.

Приведу примеры кода с использованием метамодели и Criteria API.

Репозиторий:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface SpeakerRepository extends JpaRepository<Speaker, Long>, JpaSpecificationExecutor<Speaker> {
}

Сервис с использованием метамодели Speaker:

import lombok.RequiredArgsConstructor;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class SpeakerService {

    private final SpeakerRepository speakerRepository;

    public List<Speaker> findByLastName(String lastName) {
        return speakerRepository.findAll(hasLastName(lastName));
    }

    private Specification<Speaker> hasLastName(String lastName) {
        // Используется сгенерированная метамодель Speaker_.java
        return (root, query, cb) -> cb.equal(root.get(Speaker_.lastName), lastName);
    }
}

Метамодель Speaker_.java генерируется во время компиляции и её можно использовать для проверки корректности составленных запросов (типы данных, наименование полей).

Да, вы правы, что jpametamodelgen помогает в построении валидных запросов с помощью Criteria API. Тем не менее, функциональность не такая продвинутая как у JOOQ. Последний может проверить, допустим, что вы используете поле именно из правильной таблицы, проверить типы данных в соответствии с колонками и т д. Jpamodelgen просто сгенерит константы с названиями атрибутов из сущностей. Это, конечно, лучше чем просто использовать строки в коде. Но JOOQ здесь явно ушел дальше)

То что вы описали, а именно бизнес логика в доменных объектах можно сделать и с помощью JOOQ судя по тому по примеру как пишутся запросы на нем. Я лично не пользовался этой библиотекой, но пользуюсь кажется почти аналогом skunk на скале. А там это отлично делается, причем изначально код получается максимально оптимизированным. А сама техника не смешивать бизнес логику с запросами в базу данных или любыми другими эффектами вроде логично и особенно практикуется в функциональном программировании. Бизнес логика должна получать данные и возвращать результат, ничего более, и это очень облегчит тестирование. Более подробно можете поискать "Moving IO to the edges of your app: Functional Core, Imperative Shell"

НЛО прилетело и опубликовало эту надпись здесь

Поддерживаю. Годы идут, усталость от "магических" проблем все выше. Все больше достает вопрос а какой в итоге запрос получится? Если говорить про хибер, то всякие автозапросы и n+1.... В итоге чем старше и опытнее становишься, тем больше хочется иметь понятные написанные руками аккуратно лежащие где-то запросы, вместо этой магии удобства популярных апи и начинаешь мечтать о старом добром jdbcTemplate или хотя бы простой и понятной батис модели ))))

Да просто включите логгирование запросов в локальном профайле и будет вам счастье, все эти джуки и майбатисы превращаются в неконтролируемого и сложнотестируемого монстра, когда проект более менее разрастается. И добавление одного поля может поломать всю систему, когда все поотваливается в ран тайме.

Статья приписывает недостатки JDBI всем Transaction Script решениям. И выдает спорные решения в Hibernate за преимущества.

DynamicUpdate, например, в Hibernate отключен по умолчанию, так как в обмен на уменьшение данных, передаваемых по сети, он не использует кэш запросов, чем повышает нагрузку на сервер.

"Spring Data JDBC" позволяет код из первого примера сделать втрое короче и в разы читабельнее. С ним удобно работать и с SQL-запросами в репозитории, и с Entity-классами через привычные методы CrudRepository.

При этом он не имеет недостатков Hibernate:

  1. Проблемы N+1 и N+M+1 даже в Eager-режиме.

  2. Проблемы перегрузки соединениями БД из-за неудачно реализованного Lazy-режима и попытки это исправить, используя OSIV.

  3. Проблемы метода save/persist не выполняемого в момент вызова, не позволяющего сразу получить id записи в базе. Это вынуждает прописывать транзакции, где они не требуются по бизнес-логике, с высоким риском замедлить базу избыточными блокировками.

Бизнес-логика сконцентрирована в одном месте, в доменных объектах.

А как-же SpeakerService? В нем тоже фрагмент бизнес-логики.

Когда передадут в реализацию еще 10 API, использующих эту таблицу базы, все методы с их бизнес-логикой будут перемешаны в Entity-классех? Вот уж спагетти, так спагетти.

Завязывать доменную модель приложения на схему базы данных - странное решение. Получается, мы нюансы хранения данных тащим в бизнес логику. А без такого подхода Hibernate не будет работать.

Т.е. мне сама идея ORM, где схема данных матчится 1 к 1 в бизнес сущности приложения, кажется нарушением DDD, Clean Architecture и проч.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории