![](https://habrastorage.org/storage2/3de/65e/252/3de65e252192f3b1c457c44354ea61aa.jpg)
«Вот что я имею в виду под производящим произведением или, как я называл его в прошлый раз, «opera operans». В философии существует различение между «natura naturata» и «natura naturans» – порожденная природа и порождающая природа. По аналогии можно было бы образовать – «cultura culturata» и «cultura culturans». Скажем, роман «В поисках утраченного времени» строится не как произведение, а как «cultura culturans» или «opera operans». Это и есть то, что у греков называлось Логосом.»
// Мераб Мамардашвили «Лекции по античной философии»
Постановка задачи
Классический подход в разработке информационных систем — это, очевидно, построение модели предметной области с помощью структур данных и программного кода. Структуры данных включают в себя: структуры в оперативной памяти и в протоколах передачи, в файлах на диске и в базах данных, а программный код — это активная (императивная, событийная или функциональная) модель решаемой задачи над моделируемыми данными.
Существует множество подходов и технологий, для которых модель является статической, т.е. зафиксированной на продолжительный срок (период жизни одной версии ПО). В таких статических технологиях применяются те или иные средства синхронизации структур данных постоянного хранения и структуры объектов в программном коде. Но есть класс задач, и он становится все актуальнее, для которого подобные технологии не являются приемлемым решением, т.к. требуют вмешательства разработчиков и выпуска новой версии системы при любом изменении в модели предметной области, а в конечном итоге, требуют пересборки всех компонентов информационной системы. При таких изменениях требуется повторное развертывание этих компонент на рабочих местах пользователей и серверах, а для веб-приложений процесс этот более мягкий, т.к. развертывание касается только серверов. Однако, в любом случае, изменение модели связано со следующими необходимыми действиями:
- прерывание штатной работы системы на определенное время при развертывании (прерывание сессий пользователей, временная недоступность сервиса),
- конвертация данных в постоянном хранилище из старых форматов в новые,
- внесение изменений в программный код (что предусматривает выделение времени на разработку, отладку, тестирование),
- ревизия всех связей с другими подсистемами (как на уровне данных, так и на уровне программных вызовов).
Ограничим класс задач, которые требуют принципиально другого подхода:
- задачи с динамической предметной областью, где изменение структуры и параметров модели является нормальным штатным режимом функционирования,
- задачи обработки слабо-связанных данных или данных с непостоянными структурой, параметрами или логикой обработки,
- задачи в которых количество классов обрабатываемых объектов сравнимо с количеством их экземпляров или количество экземпляров всего на один-два порядка выше,
- задачи в которых от скорости интеграции обновленной модели с другими подсистемами зависит успешность модели бизнеса (в идеале требуется интеграция в реальном времени или приближенная к реальному времени),
- задачи межкорпоративного обмена данными, межсистемной интеграции (включая интеграцию гетерогенныех распределенных приложений),
- прикладные задачи, не связанные с массовым пользователем.
Особо отмечу, что в класс задач не входят типичные коммуникационные или информационные задачи для которых можно создать ПО с долгим сроком жизни, как то: электронная почта, документооборот, системы CRM, системы мгновенных сообщений, социальные сети, новостные или информационные веб-ресурсы и т.д. Сфера применения подобных технологий скорее сводится к таким отраслям:
- корпоративные прикладные информационные системы,
- приложения баз данных,
- аналитические системы, системы построения отчетов, системы принятия решений,
- системы интеграции между компаниями-партнерами.
Такие задачи традиционно считаются слабо автоматизируемыми или ограниченно автоматизируемыми. Но если искать путь их решения, то естественно предположить, что повышение уровня абстракции программного решения позволит покрыть более широкий круг задач, в который войдут и смежные задачи, с измененными параметрами и структурой. Назовем такую модель белее общей задачи, метамоделью и предложим способ ее динамического отображения (проецирования) на предметную область, при котором мы сможем динамически получить несколько моделей предметной области из одной метамодели в зависимости от подаваемых в систему метаданных. Такие метаданные должны дополнять и конкретизировать метамодель (доописывать структуру и параметры).
Какие существуют сложности на пути повышения абстракции программных компонентов и структур данных:
1. Связывание по зашитым в программный код идентификаторам. Обращения к структурам данных и к программным интерфейсам осуществляются с помощью логических идентификаторов, которые преобразуются в конечном итоге в адреса вызовов, относительные адреса в оперативной памяти и сетевые вызовы. И при статическом (раннем) связывании и при динамическом (позднем) связывании, идентификаторы зашиты в программном коде компонентов системы, более того — разбросаны по коду. А для повышения абстракции код не должен содержать идентификаторов, указывающих на модель предметной области, а только идентификаторы, указывающие на метамодель.
2. Применение статической типизации переменных. Для задач с динамической предметной областью характерным является не только то, что мы заранее не знаем тип переменной (объекта, класса, выражения, константы, функции), но этот тип может быть даже неизвестен во время компиляции. Как минимум, язык программирования, подходящий для решения подобных задач должен поддерживать интроспекцию и динамическое создание типов, классов и переменных вновь созданных типов.
3. Смешивание в одних классах модели предметной области и решения системных задач. Например, класс «автомобиль» не должен знать ни какими визуальными контролами, библиотеками или тегами он выводится на экран, ни то, как ему нужно сериализироваться и с помощью каких синтаксических структур, как ему храниться на диске или в базе данных, как ему передаваться по сети, с помощью каких протоколов или форматов данных, или в каком виде он должен быть развернут в оперативной памяти.
Я не утверждаю, что приведенные техники программирования не имеют места, они вполне применимы и незаменимы для решения задач со статической моделью предметной области. А статическое и динамическое связывание подходит для разработки системных аспектов программного обеспечения с динамической предметной областью, но приведенные техники не должны быть связаны с обработкой модели или метамодели предметной области.
Динамическая интерпретация метамодели
Перед тем, как описать принцип динамической интерпретации, мы уточним, что мы будем понимать под используемыми терминами.
Метамодель — информационная модель более высокого уровня абстракции, чем конкретная модель предметной области. Метамодель описывает и покрывает функционалом не отдельную задачу, а широкий круг задач с выделением в этих задачах общих абстракций, правил обработки данных и управления бизнес-процессами. К необходимой конкретике и специфике метамодель адаптируется уже в момент исполнения, преобразовывая метаданные в динамический код и обеспечивая их динамическое связывание со средой запуска (виртуальной машиной, операционной системой или облачной инфраструктурой).
Метаданные — данные, описывающие структуру и параметры поступающих в информационную систему данных. Метамодель интерпретируя метаданные динамически строит модель предметной области, которая уже интерпретирует поступающие данные. Метаданные могут содержать декларативные и императивные структуры, например: типы, правила обработки, сценарии, регулярные выражения и т.д. Без метаданных поступающие данные не полны и метамодель не может без них составить динамическую модель решаемой задачи, то есть, метаданные дополняют описание данных и дополняют средства метамодели по интерпретации полученных данных.
Прикладная виртуальная машина — среда динамической интерпретации, имеющая связь с операционной системой, виртуальной машиной или облачной инфраструктурой. Прикладная виртуальная машина в отличие от виртуальной машины обслуживает не системные задачи, а прикладные, обеспечивает создание модели из метамодели, метаданных и данных с помощью динамического связывания, а так же кеширование развернутых фрагментов модели в оперативной памяти для быстрого к ним доступа.
![](https://habrastorage.org/storage2/490/79e/617/49079e6175bc030fdbb2dbfd6586f8ea.png)
Итак, метамодель находится в каждом компоненте ИС (см. схему) и содержит абстрактную функциональность для широкого класса задач. При запуске компонента метамодель разворачивается в прикладной виртуальной машине, но для ее динамической интерпретации, т.е. для преобразования ее в модель предметной области или решаемой задачи, необходимо получить данные и метаданные из системы постоянного хранения, машины состояний или другого компонента ИС. Динамическая интерпретация метамодели — процесс создания модели предметной области из метамодели, метаданных и данных. Динамическая интерпретация происходит как на клиенте, так и на сервере в момент исполнения. При динамической интерпретации модель предметной области не строится полностью в памяти, а интерпретируется фрагментарно, по мере обработки поступающих данных и может кешироваться в прикладной виртуальной машине, чтобы избежать расходов вычислительных ресурсов на многократную интерпретацию.
Метамодель содержит спецификацию метаданных, которые необходимы для динамической интерпретации. Если это первый сеанс работы компонента и в доступном для него постоянном хранилище и машине состояний еще нет метаданных, то их получение может быть произведено с помощью идентификатора (адреса) или запроса, введенного пользователем или переданного от другого компонента системы (но не зашитого в компоненте). Этим процессом управляет сессионный компонент прикладной виртуальной машины. В дальнейшем, метаданные могут кешироваться, как кешируются данные для минимизации запросов, а обновляться только при изменении версии или контрольной суммы в источнике (системе хранения или удаленном компоненте) или при получении события от источника. Получение измененных метаданных приводит к перестройке модели предметной области в памяти в оперативной памяти. В большинстве случаев оптимальнее делать не полную перестройку, а «ленивую» (по мере обращения).
Метаданные, поступившие таким образом в компонент системы, дополняют метамодель своими декларативными параметрами и императивными сценариями таким образом, что становится возможным динамическое построение классов предметной области, их наполнение полученными данными и обработка с помощью динамически же построенной бизнес-логики. В результате, как функциональность компонента, так и интерфейсы взаимодействия с другими компонентами могут изменяться в широком классе решаемых задач без перекомпиляции системы, а многие изменения возможны при простом задании новых параметров метаданных (даже без модификации сценариев).
Динамически построенные прикладные структуры данных и прикладные сценарии (события, методы обработки данных) опираются на вызовы API прикладной виртуальной машины, в которой запущена динамическая модель. Такое API, в свою очередь, «садится» на API среды запуска (например, на API операционной системы, мобильной операционной системы, виртуальной машины, API облачной инфраструктуры и т.д.). Динамическое построение модели происходит как в серверных, так и в клиентских (пользовательских) компонентах ИС, т.е. интерфейс пользователя строится динамически, а роль API тут выполняет используемая библиотека визуализации (компоненты GUI) или среда отрисовки «Renderer» (например: HTML5, Flash, SilverLight, Adobe AIR). Сетевые интерфейсы так же могут строиться динамически, однако, протоколы передачи и форматы обмена данными, конечно же, должны быть зафиксированы (вкомпилированы в компонент) или выбираемы из доступного набора, доступного на платформе (например JSON, XML, YAML, CLEAR, CSV, HTML, и т.д.).
Пользователь инициирует события в GUI, которые приводят к локальной обработке данных или сетевым вызовам. Смысл динамической интерпретации в сетевом взаимодействии заключается в том, что идентификаторы вызываемых удаленных процедур, их параметры и структура возвращаемых данных заранее не зашита в вызывающий компонент, а получаются из метаданных во время динамической интерпретации метамодели. Удаленная же сторона так же не имеет фиксированного интерфейса (заранее зашитых в откомпилированную компоненту методов, доступных через сетевые вызовы), вместо этого, заранее известен только метапротокол (форматы передачи данных, типы параметров, обработка которых поддерживается) и механизм интроспекции, позволяющий динамически считывать структуру удаленного сетевого интерфейса. Например, такой метапротокол можно создать из декларативных структур, объединив их с протоколами HTTP, JSONP, SSE, WebSockets и интерфейсом интроспекции.
Роль машины состояний в динамической интерпретации в том, чтобы сохранять сессию с необходимым набором данных как на клиенте, так и на сервере между сетевыми вызовами. Это необходимо для того, чтобы обеспечить последовательную или интерактивную человеко-машинную обработку данных, при которой действия пользователя приводят модель в определенное состояние, а каждый последующий сетевой вызов зависит от предыдущего в пределах транзакции. Кроме того, машина состояний позволяет существенно сократить расходы трафика и вычислительных ресурсов, кешируя метаданные, данные и даже саму динамически построенную модель в оперативной памяти. Реализация машины состояний возможна с помощью структур в оперативной памяти (для языков программирования), локального хранилищу («Local Storage» для HTML5 приложений) или сервера memcached (в основном для серверных компонентов).
Постоянное хранение данных в информационных системах с динамической интерпретацией возможно в СУБД: реляционных базах с параметрическим подходом к схемам данных или с применением интроспекции метаданных схемы хранения, базах данных класса ключ-значение («Key-value») или бессхемных хранилищах («Schemaless»). Стоит отметить, что бессхемные хранилища (например MongoDB) более естественные для систем с динамической интерпретацией, т.к. предусматривают динамическую типизацию и гибкое управление структурами (близкое к языкам программирования со слабой типизацией). Для реляционных СУБД применяется следующий подход: кроме основных таблиц, хранящих модель предметной области, в БД помещаются дополнительные таблицы для хранения метаданных, и эти таблицы содержат дополненную информацию о структуре основных таблиц (расширенные типы данных, параметрах обработки, дополненную классификацию связей и императивные сценарии).
Выводы
Таким образом, многослойная структура компонентов ИС с динамической интерпретацией метамоделей замыкается снизу на самоописывающее хранилище (ограниченное уровнем абстракции метамодели), а сверху замыкается на пользователя, который может модифицировать не только данные, но и метаданные, переналаживая ИС под постоянно меняющиеся требования решаемой задачи, в этом и состоит гибкость подхода и упрощение модификации систем, снижение необходимого уровня квалификации пользователя при внесении изменений в структуру и функции. Место же архитектора программных решений и программистов в создании программного обеспечения с повышенным уровнем абстракции, т.е. в реализации метамодели (что является, естественно, более трудной инженерной задачей). Но в конечном итоге, подход окупает себя, благодаря повышению повторного использования кода с высокой абстракцией, автоматизации многих задач связывания компонентов, снижению влияния человеческого фактора при модификации и интеграции систем и упрощении интеграции между компонентами программных систем.
Дополнительные материалы
1. Метапрограммирование
2. Применение метамодели при проектировании баз данных с несколькими абстрактными слоями:
Часть 1 и Часть 2
3. Интеграция информационных систем