Pull to refresh

Мета-данные. На пути к идеалам управления моделями данных

Java
О чём этот пост

  1. Это пост-обзор вариантов управления моделями данных, известных автору, на основе опыта, слухов, и чтения инструкций
  2. Также этот пост — попытка классификации существующих вариантов управления моделями данных
  3. Напоследок приводится идея и начальные штрихи в реализации системы управления моделями данных, которая не должна содержать недостатков предыдущих


Определения и ограничения

Предполагается, что читатель является (или когда-нибудь станет) разработчиком Enterprise Application, которому часто нужно писать быстро и качественно, но не боящегося лезть в дебри JPA/JTA/RMI чтобы «подкрутить напильником» особо тонкие места.

Данные — то, что хранится в базе данных приложения. Данные о клиентах, пользователях, заказах и т.п.

Метаданные — описание структуры данных. Описание того, какие типы объектов хранятся в базе данных, какие у них есть поля (аттрибуты, элементы), описание зависимостей между объектами. В общем случает типы могут наследовать атрибуты родительского типа, а один атрибут в общем случае может присутствовать у двух и более типов, несвязанных отношением наследования.


Enterprise Application работает с использованием (чаще всего) Application Server'а (WebLogic, JBOSS) и некоторой РСУБД (Oracle, Informix, MySQL). Хотя автор не видит ничего зазорного в самостоятельной сборке AS на основе Tomcat/Hibernate/JOTM/DBCP/etc, это очень и очень интересно, но за рамками данного топика.

В качестве РСУБД предполагается одна из тех стандартных, которая поддерживается Hibernate/OpenJPA.

В топике используются термины из XML Schema: пространство имён, тип, атрибут. Последним двум в некоторой степени соответствуют понятия Java класс (объект класса, бин) и свойство (property, aka get+set, также иногда просто поле, field).

Введение. Простейший случай


Большие приложения — чаще всего это не только приложения с большим объёмом данных. Чаще всего это приложения работающие с большим количеством разнородных данных, имеющих разную структуру с точки зрения бизнес-логики. (Кстати, последнее важно — структура данных может быть различной на уровне СУБД, на уровне приложения и даже внутри него)

Самым простым случаем является определение модели данных в виде набора классов и соответствующих ему набору таблиц в базе данных. Грубо говоря: один класс — ода таблица в базе данных. Каждое свойство объекта представлено свойством (property) класса-бина и колонкой в базе данных. Однако, подобный механизм имеет недостатки, которые проявляются при разработке и использовании Enterprise приложения:
  • Добавление или изменение модели данных потребует изменения как структуры базы данных, так и кода программы с последующей перекомпиляцией и т.д.
  • Как следствие, нельзя это сделать «на лету»
  • Сложные изменения, такие как перенос атрибута из дочернего типа в родительских, потребует также написание ручных скриптов (DDL+DML) на обновление структуры базы
  • Изменение структуры требует от специалиста знания SQL/Java


Нужно, однако, отметить и плюсы подобного подхода:
  • Лучшая цена за хорошую производительность. Буквально «out-of-the-box» мы получаем самую прозрачную структуру хранения данных, самую очевидную как для JPA-прослойки (hibernate, etc), так и для РСУБД (и её администратора).
  • С точки зрения программиста бизнес-логики, не меняющего структуру данных, самый удобный API мы также получаем out-of-the-box


Заметьте в последнем предложении важное уточнение — «бизнес-логики». Речь идёт об описании процессов взаимодействия структур данных, их изменении и пр. — то есть кода, который должен знать и знает о структуре данных. Но если, например, мы говорим про редактирование бинов через WEB-интерфейс (или любым другим способом), то для написания редактора, который может редактировать 80% объектов, не зная заранее их структуры (т.н. generalized), нам придётся разбираться с Reflection/Beans/etc и другими, в принципе, не очень страшными словами. (Страшные — в конце топика).

Современные средства проектирования позволяют автоматизировать часть процессов связанных с обновлением, например, структуры базы данных по коду, либо наоборот — сгенерировать или обновить код по описанию структуры данных. Не уверен, но, думаю, существуют средства создания одновременно и кода, и структуры базы данных на основе некой абстрактной схемы данных, записанной, например, в виде XML Schema. (Код так точно можно сгенерировать — см. XML Beans и пр.). Однако все эти средства работают в «offline» и не затрагивают работающее приложение (если вы, конечно, не сделаете обновление прямо по «живому», но ничего хорошего из этого не бывает).

Кстати, некоторые из вспомогательных утилит можно заставить и формочки для каждого типа объектов нарисовать.

Гибкие структуры данных


Самой гибкой можно считать структуру, в которой каждый объект хранится как запись в базе данных в виде, ну, например, XML. То есть большая-большая таблица, в которой две колонки — ID объекта и его содержание в виде XML. Как вы правильно догадываетесь, основной недостаток подобной структуры — очень низкая производительность базы данных в тот момент, когда нам нужно будет вычислить, ну например, всех клиентов из города «Москва». Для этого придётся базе данных распарсить каждое значение.

Чтобы структура осталось гибкой, но поменьше нагружать базу данных, объект разбивают на кусочки и выносят в отдельные таблицы. Например,
— Объекты: ID, обязательное поле 1, обязательное поле 2
— Значения: ID объекта, идентификатор аттрибута, значение

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

Ещё недостатки:
За гибкость нужно платить. Во-первых, слой работы с данными придётся писать самостоятельно. Во-вторых, возникает большое желание сэкономить и оставить для бизнес-логики API, который бы отражал структуру базы данных:
— дай объект ID такой-то
— дай аттрибут ID такой-то
— обнови значение
— запиши аттрибут ID такой-то объекта такой-то
— обнови версию объекта (+1)

Конечно, с точки зрения программиста generalized редактора данных очень удобно иметь методы вроде getAllAttributes(). Однако с точки зрения бизнес-логики это неудобно, особенно если нужно помнить все ID нужных атрибутов (они могут быть и числовыми).

Нужно отметить, однако, что API в общем случае не обязан совпадать со структурой базы данных. Главное — чтобы 80% действий выполнялись самым простым и очевидным способом. То есть если у нас в базе хранятся клиенты, получение имени клиента или его адреса должна быть одна строка кода вроде client.getAddress(). Однако для гибких структур написание таких оболочек может сильно подорвать производительность, во-вторых, структуры имеют обыкновение меняться…

Однако если такие оболочки не пишет тот, кто отвечает за написание процедур доступа к данным, будьте готовы, что через пару лет у вас будет столько оболочек «упрощённого» доступа к данным, сколько инициативных программистов работают со «стандартным» API.

Структуры с ограниченными возможностями


В этом разделе хочется рассказать ещё об одном подходе, которая используется в одной малоизвестной CMS.

С точки зрения кода доступ к атрибутам объекта осуществляется таким же образом, как и у гибких структур — через методы вроде getAttribute / getAllAttributes / etc. Однако для CMS, основная задача которой редактировать объекты по отдельности (без relations между объектами), а также просто вывести объект в XML для дальнейшей обработки — данного API вполне хватает.

Интересно то, что список типов данных хранится в некотором конфигурационном файле. Также в этом файле для каждого типа хранится список аттрибутов и их тип. На основании конфигурационного файла при запуске создаётся или обновляется структура таблиц. В дальнейшем «на лету» при изменении структуры данных таблицы обновляются.

Плюсы:
— очевидная модель данных для СУБД
— гибкость «на лету»
Минусы
— с точки бизнес-логики API слишком гибкий (см. предыдущий раздел)
— нужно писать свою систему доступа к данным, которая в настоящий момент, к сожалению, в отличии от системных объектов (пользователи, группы, etc) игнорирует транзакции, кеши и прочие прелести

Классификация… попытка


Если мы рассматриваем метамодель, то для её описания нужно ответить на следующие вопросы:
  • что является отправной точкой для описания модели? (разумеется, это должна быть одна точка) Где хранится информация об объектах и их аттрибутах?
  • как организовано хранение данных в БД?
    • выполнены ли требования первой нормальной формы?
    • Два разных простых (не multiple) атрибута хранятся:
      • в виде двух разных колонок
      • в виде двух разных строк
  • как организован доступ к данным на уровне Application Server'а?
    • используются стандартные методы JPA (EntityManager, etc)
    • используются свои классы доступа к данным
  • как организован доступ к данным на уровне бизнес-логики?
    • используются стандартные методы вроде getName(), getAddress(), etc
    • используются нестандартный API вроде getAttribtute(ID...)
  • есть ли доступ к мета-данным из программы?
    • есть, и даже можно изменять
    • есть
    • только через Reflections / Hibernate Mapping / etc

Хочу… идеальная для автора


Из предыдущего пункта легко выводятся требования к идеальной (с точки зрения автора) системе описания и оперирования моделями данных:
— описание структуры данных должно быть в базе данных, что позволит оперативно изменять описание модели, возможно — через само приложение
— сами данные при этом должны хранится в нормализованной (вплоть до 3-4 формы) базе данных, где каждому типу соответствует своя таблица данных. Система управления должна сама заботится о поддержании схемы базы данных в соответствии с мета-данными.
— доступ к данным должен осуществляться через стандартные интерфейсы JPA / EntityManager.
— с точки зрения бизнес-логики основные поля основных объектых типов должны быть доступны через простой API без дополнительного resolving / casting / narrowing (т.е. сразу после загрузки из EntityManager)
— но система должна также обеспечивать доступ к мета-данным. В том числе для конкретного объекта — получения списка всех полей.

В настоящее время автор занимается написанием подобной системы, используя:
— Hibernate — как драйвер доступа к данным
— CGLIB / ASM — для динамического конструирования классов на основе их описания, включая аннотации для Hibernate
— XML Schema — для описания типов данных и их атрибутов

Но об этом в следующий раз.
Tags:модель данныхjavajpa
Hubs: Java
Total votes 9: ↑6 and ↓3 +3
Views5.2K

Popular right now

Top of the last 24 hours