(java || kotlin) && devOps
369 subscribers
6 photos
1 video
6 files
306 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем привет!

Я вернулся из отпуска, значит настало время для нового поста.
Сегодня хотел бы рассказать о об одном своем провальном проекте. Ведь далеко не все проекты попадают в ПРОМ.
И это нормально, главное - делать выводы из ошибок.
Поехали.

Задача стояла такая. Есть две БД с одинаковой схемой - структурой таблиц.
Данные в БД - пользователь + связанная с ним информация. А это еще порядка сотни таблиц, причем их число растет с каждым релизом.
Требуется периодически переносить часть пользователей из одной БД в другую. Назовем утилиту, которая будет это делать - мигратор.
Навскидку видится три варианта:
1) ETL
2) самописный скрипт БД
3) Java мигратор, работающий на основании метаданных из Hibernate. Да, забыл уточнить, есть Java приложение, работающее со всеми таблицами пользователя через Hibernate.

Наша команда занималась третьим вариантом. Какие я сейчас вижу проблемы у этого варианта:

1) Java мигратор самый сложный и непрозрачный из всех вариантов. Главный его плюс - он практически убирает необходимость ручной доработки мигратора с выходом новых релизов. И убирает двойную работу - другие варианты требуют сначала обновления скриптов версионирования БД, а потом обновления мигратора. Где может выстрелить сложность Java мигратора? БД сопровождают специально обученные люди - DBA. Они достаточно консервативны, т.к. во-первых они сопровождение, а во-вторых - DBA) В нашем случае на ПРОМ скрипты накатывались вручную, хотя разработка предоставляла Liquibase скрипты. Изначально со стороны DBA было заметно недоверие к Java мигратору. Чтобы его снизить решили, что мигратор будет реконструировать схему БД, создавать список таблиц, связанных с пользователем, а DBA всегда будут иметь возможность отфильтровать этот список. Т.е. миграция данных идет по "белому списку". Сопровождение предварительно одобрило такой. При этом активно в процессе выставления требований и тестирования не участвовало.

2) отсутствие внятной процедуры приемки скриптов. Снизить непрозрачность мигратора можно с помощью создания набора тест-кейсов со 100% покрытием на ПРОМ like обезличенных данных. С согласованием процедуры у DBA. Мы этого не сделали. Т.е. тестирование конечно было, но оно проводилось на одном тестовом клиенте, нормального плана не было, консультации с DBA были фрагментарными.

3) растянутость разработки во времени из-за недостатка времени. Задача была экспериментальной, разработка шла больше года, с переодическим переключением на другие задачи. Это привело к падению качества кода. Ни я как тимлид, ни разработчики не дошли до нормального рефакторинга. Модульных тестов было мало. Плюс использовалась рефлексия, что еще больше усложнило код. Когда к моменту принятия решения о внедрении или не внедрении Java мигратора когда я смотрел на код - мне было страшновато(((

4) задача не была вовремя закрыта. На задачу спалили больше человекогода. В результате на ПРОМ использовался самописный SQL мигратор. Сейчас я бы попробовал получить от заказчика четкое ОК на внедрение, создав совместно с ним план тестирования и приемки. Agile и все такое) А если бы этого ОК не было - прекратил бы разработку.

#projects #JPA #fuckup
10) горизонтальное масштабирование. Поддерживается Kafka (хотя она не является в чистом виде хранилищем), Cassandra, Riak и многими noSQL СУБД. Проблемы: переход с реляционной БД на noSQL не всегда возможен из-за структуры БД, отсутствия опыта работы с noSQL. Кроме того к проблемам несогласованного чтения добавляются проблемы несогласованной записи, они же конфликты записи. Тоже отдельная большая тема.

#storage #performance #jpa
Всем привет!

Есть куча способов работать с реляционными СУБД в Java приложениях.
JPA, JPA JPQL, JPA Native Query, JPA Criteria API, Spring Data JDBC, Spring Data JPA, MyBatis, Jooq. Нативный JDBC в конце концов. Чистый Hibernate API не беру в расчет, т.к. подозреваю, что JPA его заборол)

А недавно я узнал про еще один - в нем соединяются JPA и стримы.
Речь о JPAStreamer https://jpastreamer.org/
Плюс статья на хабре https://habr.com/ru/post/568794/

Идея кажется интересной, т.к. благодаря автогенерации недостающих классов получаем строгую проверку типов на этапе компиляции. И запрос в теле метода, а не в аннотации.
При этом код выглядит более читаемый по сравнению с Criteria API, который так и не взлетел.
Если попытаться сравнить еще с чем-то - код похож на Jooq, но на основе JPA и со стримами. И на .NET LINQ.

Возникла мысль: неплохо бы сделать сравнение вышеперечисленных технологий. Имеет смысл?

#jpa #jdbc #rdbms
Всем привет!
При использовании JPA в проекте может возникнуть вопрос - нужно ли JPA Entity мапить на DTO, а точнее когда это нужно делать?
Вот хорошая статья с ответом на этот вопрос: https://thorben-janssen.com/object-mapper-dto/
#jpa #mappers
Всем привет!

Есть много способов получить данные из БД с помощью JPA:
1) JPQL
2) JPQL Native Query
3) HQL
4) Spring Data JPA Repository
5) Criteria API
6) QueryDSL
...

Предположим, нам нужно вернуть набор строк. Задать параметры запроса можно по-разному, а итог будет один - List или другая коллекция (Collection) с набором данных. Верно? Не совсем)
Если посмотреть на список возвращаемых Spring Data JPA данных https://docs.spring.io/spring-data/jpa/reference/repositories/query-return-types-reference.html#appendix.query.return.types то там можно увидеть много чего интересного. В т.ч. Stream.
А вот пример его использования: https://vladmihalcea.com/spring-data-jpa-stream/
Аналогично можно вернуть Stream и из обычного JPA - см. метод getResultStream, вот пример: https://thorben-janssen.com/jpa-2-2s-new-stream-method-and-how-you-should-not-use-it/

Зачем это может быть нужно?

Во-первых это просто красиво... Шучу. Если вы используете Stream в бизнес-логике - то кажется логичным использовать их и при обращении к БД.
А во-вторых: главная особенность стриминга - равномерная выборка данных. И в каждый момент данных в обработке будет одна запись.
Рассмотрим кейс, когда нужно обработать на клиенте миллион записей.

Ремарка: если у вас такой кейс - подумайте, нет ли проблем в архитектуре. Данные лучше обрабатывать на сервере СУБД. Если все же проблем нет - продолжим)

Так вот, какие у нас варианты:
1) вытащить на клиент миллион записей. Запрос к БД будет один, она выдержит, но с неплохой вероятностью можно убить клиент через Out of Memory.
2) организовать пагинацию, например, вот так: https://www.baeldung.com/spring-data-jpa-iterate-large-result-sets. Данных на клиенте в моменте не много, по размеру страницы, но запросов к БД ... тысяча.
3) использовать стримы. Запрос к БД один, данных на клиенте немного. Не обязательно одна запись, но в любом случае немного, детали ниже.

К слову, стриминг по БД с JPA аналогичен перемещению курсора по ResultSet в JDBC. С накладными расходами и плюшкам, которые дает сессия JPA, конечно.

И про объем данных на клиенте. Казалось бы - вытаскиваем записи поштучно. Но если не указать fetch size - объём предварительной выборки - для некоторых СУБД Hibernate вытащит на клиента все данные за раз, и мы вернемся к варианту 1 (((

#jpa #java_streams #rdbms