Показаны сообщения с ярлыком orm. Показать все сообщения
Показаны сообщения с ярлыком orm. Показать все сообщения

2014-12-13

Пол года с Groovy и Grails

Пол года уже как пишу на Groovy/Grails и пора бы уже сформулировать отношение к этим вещам в письменном виде. Сравнивать буду, естественно, с Python/Django. Совсем немного пощупал cherrypy/jinja когда готовил олимпиаду для студентов, но они не сильно отличаются.
TL;DR версия: groovy восхитителен, джависты, для мелких тасков крутейшая штука, берите и используйте, grails не нравится потому, что рвет связность кода, особенно заметно на больших масштабах и совершенно немодульный.

Дальше будет описание отдельных аспектов и иногда сравнение.

2014-08-07

Про истинный смысл ORM

В программировании есть несколько тем, которые любят объяснять люди не готовые к этому. Мои любимые темы:
* рекурсия на примере факториала - что за бред
* тестирование на примере арифметических операций, которое примитивно до невозможности, чтобы объяснить тестирование нужно сначала вкурить SOLID и рассмастривать сложные примеры близкие к реальности
* ООП на примере калькулятора - не надо натягивать сову на глобус, или графических фигур - чуть лучше, но неопытный объяснятель может не знать про LSP и рано или поздно скатывается в проблему квадрата-ромба. Еще одним открытием может стать множество видов полиморфизма. Чтобы объяснить параметрический полиморфизм, нужно сначала понять обобщенное программирование. Проблема курицы и яйца. Сюда же rich vs anemic, AOP и другие вопросы.
* Что-то мне подсказывает что большая часть статей про монады объясняют совсем не то что нужно.

Недавно меня накрыло на тему ORM. Главной причиной всех танцев с абстракцией от БД подается возможность легко заменить базу данных. Что?! За?! Бред?! За все годы работы я видел две смены БД в проекте: с Oracle 9 переехали на Oracle 10 XE, а с MySQL переехали на MariaDB. Под этим флагом идет безнадежная борьба за чистоту запросов: только JPQL/HQL, скажем нет нативным запросам. Вдруг мы захотим сменить БД. К сожалению, рано или поздно наступает момент, когда выразить запрос средствами ORM становится невозможно, либо он достигает совсем неприличных размеров и, скрепя сердце и зажмурившись, программист пишет нативный SQL.

Внезапно все меняется, если посмотреть на ORM как на оптимизатор рутиного CRUD-а и не более. Если для сложной выборки быстрее написать SQL, то не нужно мучить ORM, рядом можно нарисовать DTO-шку, чтобы ORM закинул в него данные. Пуристы забывают про то что это нужно для экономии времени и сокращения количества ошибок в программе со 100500 формочками. Время машины стало дешевле времени человека и мы можем себе позволить неэффективность в маленькой области, выигрывая в целом.

2013-12-08

Groovy shell в веб-приложении Java

Доступ к доменной модели

При разработке иногда часто хочется иметь под рукой доменную модель со всеми сервисами и доступом к актуальной базе, чтобы можно было нагенерить нужных данных и положить их в базу, замерить производительность выборок, простестировать работоспособность отдельного куска кода. Это особенно удобно, если контейнер долго запускается. Впервые я это увидел в Django: dbshell, что весьма удобно. Мы имитировали этот шелл, положив запускабельный класс в папку с тестами, который инициализировал доменную модель и необходимый набор сервисов.

POC веб-консоли

Но хочется большего. В серверных приложения за время работы может накопиться невоспроизводимое состояние, либо в целом приложение начинает вести себя неадекватно. Основной способ борьбы - выводить подробные логи, а потом вдумчиво курить стектрейсы, строя гипотезы, как исключение могло возникнуть. А потом перезапустить приложение. Но что если доступаться к живому приложению? Возможности по съему телеметрии стали бы неограниченными: нам доступно для чтения и изменения все состояние живого приложения (правда неосторожными действиями можно его легко убить).

Оптимизация страничной выборки со сложной фильтрацией

В продолжение темы о решении проблемы N+1 в Hibernate.

Постановка задачи

Нужно сформировать отчет, содержащий 100к строк и фильтрацию по нескольким полям. Выборка объективно не укладывается в отведенные рамки: годовая выборка - 30 секунд. Приходится грузить данные на клиента маленькими чанками по сто записей. При этом мы столкнулись с тем, что один чанк загружается в течении 2 секунд, помножив на 1000 чанков получаем более получаса на получение отчета. Вся выборка ведется по двум таблицам в отношении One-to-Many, причем Many часть почти на 100% состоит из 1 записи, но СЦУКО могут встречаться > 1.

2013-11-04

Решение проблемы N+1 в Hibernate

Введение

В нашем проекте для большинства сущностей их количество не превышает сотни, а там где начинаются проблемы, хватает индексов - поэтому можно не заморачиваться. Но тут внезапно появилась дичайшая просадка производительности - клиент отваливался по таймауту на старте при попытке запросить один справочник. Быстро выяснилось, что справочник содержал 1000+ сущностей, на каждую из которых приходилось по пятку дочерних на трех уровнях (да, это всё нужно было), в итоге это давало несколько тысяч запросов при попытке сериализовать все это добро. Спойлер: в общем проблему за несколько часов удалось решить сократив количество запросов меньше чем до десяти.

Если специально не заниматься оптимизацией, то ORM зачастую приводит к проблеме, называющейся "N+1": у нас имеются две связанные сущности (не важно 1-*, *-1 или 1-1) и дочерняя загружается лениво, то, при итерации по родительским сущностям и обращении к дочерним, будет в сумме N+1 обращений к базе, чтобы инициализировать ленивые прокси. Главное препятствие для лобового решения (вытянуть всё в один запрос) - то, что из-за пустых коллекций и null-ов некоторые или все джойны должны быть внешними, а разложить после этого результат по сущностям не получится. При маппинге мы разово указываем поведение коллекции LAZY или EAGER и тонко тюнинговать не получается. Разухабистая глава в документации Hibernate про оптимизацию не очень помогает. Вообще, проблема крайне распространенная, может еще еще одно проявление impendace mismatch. Давно уже писал про ORM, ничего не поменялось, хотя уже почти не напрягает, за исключением отдельных случаев типа N+1.