Рассогласованность объектного и реляционного подходов
Ни один разработчик, которому приходилось использовать объектные и реляционные наборы данных, не будет удивлен, если сказать ему, что эти наборы данных строятся несколько по-разному. За исключением простейших ситуаций невозможно не признать, что способ разработки реляционного хранилища данных тонко – но, тем не менее, серьезно – отличается от способа разработки объектной системы.
Объектные системы обычно характеризуются четырьмя базовыми компонентами: идентификацией (identity), состоянием (state), поведением (behavior) и инкапсуляцией (encapsulation). Идентификация в большинстве объектно-ориентированных (ОО) языков является неявным понятием, состоящим в том, что у любого объекта имеется уникальный идентификатор, отделенный от его состояния (значения внутренних полей объекта) – два объекта с одинаковым состоянием являются отдельными самостоятельными объектами, несмотря на то, что зеркально отображаются один на другой. Отсюда происходят дискуссии относительно «идентичности и эквивалентности» объектов в языках, подобных C++, C# или Java, где разработчикам необходимо различать операции «a == b» и «a.equals(b)». Поведение объекта довольно легко наблюдать, оно определяется набором операций, которые могут вызываться клиентом для манипулирования объектами, их изучения или для какого-либо взаимодействия с ними. (Это отличает объекты от пассивных структур данных в процедурных языках, подобных C.) Инкапсуляция является важным элементом объектного подхода, предотвращающим внешнее манипулирование внутренними частями объекта и обеспечивающим возможность эволюции интерфейса объекта. (Как ни странно, применение инкапсуляции для упрощения сопровождения программного обеспечения оказалось важным побуждающим мотивом почти во всех новшествах языковой компьютерной науки (Linguistic Computer Science). Исследователи процедурной, функциональной, объектной, аспектной и даже реляционной технологий (([Date02]) и других языков указывают на «инкапсуляцию» как на один из наиболее важных факторов.) Из этих понятий можно вывести более интересные понятия, такие как тип – формальное объявление состояния и поведения объектов; ассоциация, позволяющая типам ссылаться друг на друга на основе легковесных ссылок вместо того, чтобы включать в один объект состояние другого объекта (что иногда называют композицией); и полиморфизм – возможность подстановки некоторого объекта там, где ожидается наличие объекта другого типа.
Реляционные системы предоставляют возможность хранения знаний и их выборки на основе логики предикатов и истинных утверждений. По существу, каждая строка таблицы является утверждением о некотором факте реального мира, и SQL позволяет эффективно выбирать факты с использованием логики предикатов для вывода следствий из этих фактов. Дейт ([Date04]) и Фассел ([Fussell]) полагают, что реляционная модель характеризуется понятиями отношение, атрибут, кортеж, значение отношения и переменная отношения. Отношение в своей основе является смысловым предикатом о реальном мире, утверждением о фактах (атрибутах), которые обеспечивают смысл этого предиката. Например, можно определить отношение PERSON как {SSN, Name, City}; соответствующий предикат утверждает, что «существует человек (PERSON) с номером карточки социального страхования (social security number) SSN, проживающий в городе City и именуемый Name. Заметим, что в отношении полностью отсутствует упорядоченность атрибутов. Кортеж – это истинное утверждение в контексте некоторого отношения, множество значений атрибутов, соответствующее требуемому множеству атрибутов данного отношения, например, "{PERSON SSN='123-45-6789' Name='Catherine Kennedy' City='Seattle'}. Заметим, что два кортежа считаются идентичными, если они относятся к одному и тому же отношению, и значения одноименных атрибутов в них совпадают. Тогда значение отношения – это комбинация отношения и множества кортежей, соответствующих этому отношению, а переменная отношения, как и большинство других переменных, – это место для размещения значений заданного отношения. Например, можно определить переменную отношения People для хранения значений отношения {PERSON}, и эта переменная отношения может содержать следующее значение:
{ {PERSON SSN='123-45-6789' Name='Catherine Kennedy' City='Seattle'},
<{PERSON SSN='321-54-9876' Name='Charlotte Neward' City='Redmond'},
<{PERSON SSN='213-45-6978' Name='Cathi Gero' City='Redmond'} }
Переменные отношений обычно называют таблицами, кортежи – строками, атрибуты – столбцами, а набор переменных отношений – базой данных. Эти базовые элементы можно комбинировать с использованием набора операций (более подробно описанных в гл. 7 книги [Date04]): ограничения (restrict), проекции (project), декартова произведения (product), соединения (join), деления (divide), объединения (union), пересечения (intersection) и вычитания (difference), и эти операции образуют базис формата и подхода SQL, всемирно признанного языка для взаимодействия с реляционными системами с консолей операторов или из программ на языках программирования. Использование этих операций позволяет создавать порождаемые значения отношений, отношения, которые вычисляются на основе других значений отношений, хранимых в базе данных, – например, путем применения операций проекции и ограничения к определенной выше переменной отношения People можно создать значение отношения, показывающее номера карточек социального страхования людей, живущих в конкретном городе.
Уже сейчас достаточно очевидно, что имеется четко выраженной различие между тем, как представляется «правильная» разработка системы в реляционном и объектном мирах, в с течением времени это различие станет еще более очевидным. Однако важно заметить, что, поскольку программисты предпочитают использовать для доступа в реляционным хранилищам данных объектно-ориентированное программирование, всегда будет иметься некоторая разновидность объектно-реляционного отображения – эти две модели слишком сильно различаются, чтобы можно было их потихоньку соединить. (Вероятно, то же самое верно и для объектно-ориентированного и процедурного программирования, но это совсем другая тема.) ОР-отображения могут существовать в разнообразных формах, из которых проще всего понимаются средства автоматического ОР-отображения, такие как TopLink, Hibernate/NHibernate
и Gentle.NET. В другой форме для организации ОР-отображения требуется кодирование вручную с использованием инструментальных средств, ориентированных на работу с реляционными базами данных, таких как JDBC или ADO.NET.
Эти средства обеспечивают доступ к реляционным данным и их извлечение «вручную» в форме, более привлекательной для объектных разработчиков. В третьей форме реляционные данные просто принимаются в качестве модели, с которой следует работать, и объекты подстраиваются под этот подход. В своем лексиконе паттернов Фаулер называет эту форму ОР-отображения «шлюзом к табличным данным» (Table Data Gateway [Fowler, стр. 144]) или «шлюзом к строчным данным» (Row Data Gateway [Fowler, стр. 152]). Этот подход используется во многих слоях доступа к данным в Java и .NET. Его комбинирование с генерацией кода облегчает разработку этих слоев. Иногда объекты строятся вокруг реляционной/табличной модели, в них добавляются операции доступа к реляционной базе данных, и это называется «активными записями» (Active Record, [Fowler, стр. 160]).
Действительно, этот базовый подход – подчинить одну модель терминам и подходу другой модели – является традиционным решением проблемы несоответствия моделей. По сути дела, проблема решается путем игнорирования ее половины. К сожалению, авторы большинства подобных разработок, подобно администрации Кеннеди, не хотят доводить эту идею до логического конца с полным предпочтением одного подхода перед другим. Например, хотя большинство групп разработки программного обеспечения было бы счастливо принять «исключительно объектный» подход, это привело бы к использованию объектно-ориентированной системы управления базами данных (ООСУБД), что часто не одобряется высшим руководством корпоративных групп управления данными. Обратный подход – «исключительно реляционный» – почти бессмысленно рассматривать при наличии той технологии, которая используется разработчиками во время написания этой статьи.
Невозможность «разрешить объектам использовать все свои возможности», как сказал бы генерал Уэстморленд, заставляет использовать некоторый гибридный подход к организации ОР-отображения, предпочтительно, как можно более автоматизированный, чтобы разработчики могли концентрироваться на модели своей предметной области, а не на деталях ОР-отображения.И вот здесь, к сожалению, начинается потенциальная трясина.