В предыдущем сообщении Event-driven architecture я позволил себе заметить, что сервисная шина (ESB) не является необходимым условием построения сервис-ориентированной архитекутры(SOA). О том, что сервисы должны предоставляться именно приложениями много говорят в SOA School Томаса Эрла, используя термин Intrinsic interoperability На занятиях мы довольно долго пытались его корректно перевести и, по-моему, остановились на «врожденной способностью к взаимодействию». Этот принцип, кстати, вошел в СОА-манифест в формулировке «Intrinsic interoperability over custom integration»
Одним словом, речь идет о том, что задача предоставления [ре]юзабильных повторно-используемых программных интерфейсов отводится именно бизнес-приложениям, а не интеграционной среде. (Под юзабилити я понимаю именно юзабилити, а не эргономику. Чем отличается одно от другого см. Юзабилити глазами архитектора)
Вопрос в том, как такие интерфейсы построить.
Вариант 1. Обнаружить стандарт, описывающий данную предметную область (домен). Я не говорю о стандартах вида WS-* они описывают совершенно другие вещи. Речь идет именно о стандартах CMIS, OSS/J и пр.
Вариант 2. Если стандартов нет, и все знания о предметной области локализованы в головах нескольких посвященных соответствующего тайного ордена, то интерфейс придется разрабатывать. И обычно это делается неправильно. Разработчик системы спрашивает, какие данные вам нужны и предоставляет что-то похожее на то, что вы попросили. В результате получаются хранимые процедуры типа:
СуммВырчкНаУтроGF-ЧудесСтрДураков(Кол-воЗолотых)
О повторном использовании таких сервисов говорить, разумеется, не приходится. Очевидный способ построения повторно-используемых интерфейсов – абстрагирование. Про абстрагирование сказано практически во всех работах по программной инженерии от «Программисткого камня» (рекомендую прочитать эту книжку целиком) до классических работ Г.Буча «Объектно-ориентированный анализ и проектирование», но сказано как-то не очень внятно. Поэтому, вопрос как построить хорошую объектную модель, а значит и reusable API остается открытым. Я тоже не знаю полного ответа на этот вопрос, но готов поделиться некоторыми частными, глубоко субъективными наблюдениями:
- REST лучше чем SOAP, так как оперирует с данными, а не с поведением, а это всегда проще.
- Референсные модели предметной области, по крайней мере такие, в которых нормальный человек может разобраться, имеют право на жизнь.
- Что-то чуть более конкретное, чем «Object-Relations» (см. рисунок, предложенный разработчиками ArchiMate).
- Семь плюс-минус две сущности. Для того, чтоб понять что такое, например WordPress, достаточно посмотреть на структуру его базы данных. В системах, написанных за деньги и на заказ разобраться в структуре данных практически нереально.
- Классы предметной области и отношения между ними не должны присутствовать в сигнатурах методов. Они должны вести в справочниках, доступных через тот же самый API. Тогда интерфейс становится самоописанным.
Буду признателен за более внятные мысли на тему построения повторно-используемых интерфейсов.
«Классы предметной области и отношения между ними не должны присутствовать в сигнатурах методов. Они должны вести в справочниках, доступных через тот же самый API. Тогда интерфейс становится самоописанным.»
Данный пункт не понял. Можете объяснить на примере?
Постараюсь 🙂
Предположим, мы делаем интерфейс к каталогу книжного магазина. Функции
getBookAuthor(…) и
getBookPublisher(…)
— содержат в себе сигнатуры предметной области. Если мы захотим расширить набор свойств книжки, например, добавить ISDN, то нам придется выдумывать новые функции.
Функция: getBookProperty(«author»,…) — смотрится уже лучше. Безусловно, для неё нужно предусмотреть функцию чтения справочника свойств книжки, возвращающую коллекцию свойств. Что-то типа: getBookProperties(…)
Но еще лучше забыть, что мы торгуем именно книжками и реализовать функцию:
getItemProperty(«book»,»author»,…), т.к. в этом случае мы смастерим интерфейс для работы с произвольными предметами
Сценарий использования в предложенном вами примере усложняется после введения функций вида getItemProperty.
С функциями getBookAuthor, getBookPublisher все просто и понятно — открываем WSDL-описание, видим данные функции, вызываем нужную. С getItemProperty же надо получить список Item’ов, получить список Proprty’ей, затем вызвать метод getItemProperty с нужным набором параметров. Кстати, сходу не очень понятно, как в рантайме анализировать список, например, свойств, чтобы выбрать нужное.
Понятно, что описанный вами подход гораздо гибче. Хотя бы с точки зрения больной темы — версионирования — при добавлении нового свойства ненужно добавлять метод в WSDL-описание, а значит оно не изменится.
В принципе, если воспользоваться теми же композитными сервисами Oracle Service Bus, то всегда можно привести один подход к другому: выставить наружу те методы которые удобнее для клиента, а на самом деле вызывать методы, определенные сервисом. Если я правильно понимаю, то данная трансформация и является одной из функций ESB.
Я думаю, что WSDL не справился с теми ожиданиями, которые на него возлагали. Он описывает сигнатуры методов, параметры, исключения и привязку, но совершенно лишен какой-либо семантики. Т.е. задача самоописанности интерфейсов решена только в части синтаксиса.
ESB, конечно, как раз и позволяет трансформировать один из подходов в другой. По сути, две основные функции шины — трансформация и маршрутизация.
>>REST лучше чем SOAP, так как оперирует с данными, а не с поведением, а это всегда проще
REST лучше если на этапе проектирования/разработки не известны процессы которые будут использовать данные.
Если же процессы известны, то поведенческие методы (скрывающие сложность) лучше.
В вашем примере, про магазин, SOA метод «purchase» может скрывать за собой проверку склада, анализ адреса доставки, подготовку счета и т.п.
При этом этот метод будет использоваться часто, и при изменении внтуреннего поведения (теперь у нас 10-к складов) — клиентская часть как была простой так и останется.
Ес-но, если бизнес процессы не определены или очень хочется оставить возможность их расширять то нужно оставлять методы CRUD для каждой сущности (REST даже лучше удобнее искать и всегда есть unique-url для объекта). Для того же магазина, возможно понадобиться реализовавать use case — «книга в подарок», «три по цене двух» и т.п.
Наверное, как-то так.
1. В SOA не стоит отделять API от бизнес-процессов.
Если строить API сервисов (данных и утилит), исходя из потребностей реальных бизнес-процессов, карта которых поддерживается в более менее «продуманном» виде (повторное использование процессов, аудит, классификация и т.п.) — тогда то самое API почти автоматически будет соответствовать реальной потребности, не иметь избыточностей, лишних универсальностей, не нужных элементов предметной области и т.п. — а также, API будет повторно-используемо, из-за повторности использования самих процессов.
2. Сервисы данных Domain (предметной области) — ключевые компоненты.
Если не сериализовывать весь Domain в Xml (типа TMForum SID), а ограничиваться фрагментами необходимых в процессах данных, их CRUD и событиями изменений (например, построение соответствующей Domain TopicMap событий). Создание справочников и т.п. — попытки создания дополнительного, интеграционного уровня могут быть слишком дороги, особенно, если Domain часто меняется.
Посмотрите на подход DDD — чем прозрачнее система и её API использует представления реальных объектов Domain, тем более проще её развивать и поддерживать — код более соответствует тем понятиям, которыми оперирует заказчик; и не так важно — сервисы это или бизнес-логика…
3. Изменения Domain и API.
Да, по мере развития проекта Domain постоянно меняется и дорабатывается, что может приводить к необходимости изменения и самого API (особенно в свете п.2:) — «разделяй и властвуй»! Проксируя изменяющиеся сервисы через ту же ESB, мы можем использовать шлюзы старого API, скрывая изменения Domain — для потребителей сервисов (процессов или др.) API не меняется, либо меняется постепенно, «когда у них руки дойдут перейти на новую версию API». Т.е. используя шлюзы на уровне ESB мы можем вести 2 типа разработки: развитие сервисов и поддержка интеграции. На самом деле, по п.1 следует, что скорей всего изменения процессов будут создавать стимулы для изменений Domain — таким образом, на момент, когда нужно будет внести изменение в Domain процессы уже будут готовые к изменению API.
4. События — очень важны и являются частью API