Большинство вычислительных систем построено по схеме «команда — контроль исполнения»: один метод вызывает другой и дает ему инструкции по выполнению каких-либо действий или получению нужной информации.

В реальном мире часто бывает по-другому. Компания получает новый заказ; Web-сервер получает запрос на доступ к странице, переднее правое колесо вашего автомобиля полностью затормаживается. Ни в одном из перечисленных случаев система (система обработки заказов, Web-сервер, тормозная система автомобиля) не планировала и не запрашивала соответствующее действие. Вместо этого событие, вызванное воздействием извне, повлекло за собой изменения в реальном мире или в работе компьютера. Можно ли изменить архитектуру вычислительной системы так, чтобы она не требовала постоянного контроля, а реагировала на события по мере того, как они происходят? Как будет выглядеть такая система?

События повсюду

Реальный мир переполнен событиями. Будильник выключается; телефон звонит; на приборной панели автомобиля загорается лампочка, предупреждающая о снижении уровня бензина. Многие компьютерные системы, особенно встраиваемые, изначально реагируют на определенные события. Компьютер, управляющий двигателем вашего автомобиля, получает сигнал каждый раз, когда коленчатый вал проходит нулевую отметку, и включает таймер при каждом повороте ключа зажигания. Сегодня многие системы, в основе работы которых лежит реакция на внешние события, существуют на уровне, скрытом от человеческого восприятия.

Однако, поскольку компьютерные системы становятся все более взаимосвязанными, возрастает количество публикуемых и воспринимаемых ими событий. Система обработки заказов может получать их с сайта в Internet или с помощью специального клиентского приложения и оповещать об этом другие системы. Система, ожидающая прихода нового заказа, может быть как финансовой системой, следящей за тем, оформлен заказ в кредит или оплачен с помощью кредитной карты, так и складской программой, проверяющей наличие заказанного товара в своем каталоге (рис. 1). Каждая из этих систем впоследствии может опубликовать любое другое событие для любой заинтересованной стороны. Наконец, система управления доставкой может ожидать сообщений типа: «Имеется в наличии» или «Оплачено», чтобы подготовить товар к отправке. Такой стиль взаимодействия, основанный на событиях, значительно отличается от традиционного командно-контролирующего стиля, при котором система обработки заказов должна сначала запросить складскую программу о наличии товара на складе, дождаться ее ответа, а затем послать финансовой системе запрос на проведение платежа. И только после того, как будет получен положительный ответ, она сможет дать системе доставки команду «отправить товар».

Рис. 1. Система обработки заказов

Но на этом история события не заканчивается. Складская программа может обнаружить, что на складе не хватает товаров, и оповестить об этом другие системы, например систему обеспечения поставок. Если срок действия кредитной карты покупателя подходит к концу, нас могут известить об этом, и мы должны будем послать покупателю по электронной почте письмо с просьбой прислать номер новой кредитной карты. Список интересных событий становится все длиннее. Для описания такого явления — массового обмена сообщениями между многими системами — Дэвид Лукхэм [1] ввел термин «туча сообщений» (Event Cloud, рис. 2).

Рис. 2. «Туча сообщений»

Событийно-управляемые архитектуры

Так что же определяет шаг, отделяющий простой информационный обмен сообщениями от вполне сложившейся архитектуры, управляемой событиями (Event-Driven Architecture, EDA)? Такую архитектуру отличает набором ключевых характеристик.

  • Широковещательные сообщения. Системы-участники оповещают о событиях все заинтересованные стороны. Сразу несколько сторон могут получить и обработать сообщение о событии.
  • Своевременность. Системы публикуют события по мере их возникновения, а не локально сохраняют данные и дожидаются завершения цикла обработки, как это происходит, например, при ночной пакетной обработке.
  • Асинхронность. Система, рассылающая сообщения о событии, не дожидается получения и обработки этих сообщений другими системами.
  • «Мелкозернистость» событий. Приложения обычно сообщают о нескольких отдельных событиях, а не об одном событии, состоящем из нескольких более мелких. (Чем сильнее разделены взаимодействующие стороны, тем больше может быть физических ограничений, определяющих степень «мелкозернистости» участвующих в обмене сообщений.)
  • Онтология. Система в целом классифицирует и определяет наименования событий, обычно в виде иерархии. Системы-получатели часто ожидают только конкретных событий или событий определенного типа.
  • Обработка сложных событий. Система распознает и отслеживает связи между событиями, например их агрегирование (событие более высокого уровня состоит из событий более низкого уровня) или причинно-следственную связь между ними (одно событие вызвано другим).

EDA-архитектуры стремятся к элегантности и простоте, поскольку создаются по образу и подобию событий реального мира. Столь яркие преимущества уже заставили нескольких поставщиков средств интеграции приложений предприятия (Enterprise Application Integration, EAI) объявить, что EDA — следующий шаг в развитии сервис-ориентированных архитектур (Service-Oriented Architecture, SOA).

Прощай, стек вызовов!

Элегантная простота EDA иногда обманчива. Создание такой системы в действительности может оказаться более трудной задачей, чем это представляется вначале. Одним из ключевых свойств событийно-управляемых систем является упрощенное взаимодействие между компонентами, ограниченное обменом сообщениями. Поэтому для понимания конкретных реализаций EDA следует смотреть не на то, что нового несет она в себе, а на то, что из использованного ранее становится ненужным благодаря ей. Архитектура, основанная на обработке событий, приводит к отказу от одной из самых распространенных и высокоценимых структур в программировании — стека вызовов.

Рис. 3. Пример взаимодействия объектов

При взаимодействии, построенном на стеке вызовов (рис. 3), один метод вызывается другим, затем система дожидается результата и продолжает работу согласно дальнейшим инструкциям. Такое поведение системы можно охарактеризовать тремя главными особенностями: согласованность, непрерывность и сохранение контекста. Согласованность обеспечивает синхронизацию выполнения программы, т.е. вызывающий метод должен дождаться результатов вызова и только затем продолжить работу. Непрерывность гарантирует, что по завершении работы вызываемого метода выполнение программы продолжится со строки, следующей за сделанным вызовом. И наконец, стек вызовов хранит локальные переменные как часть контекста выполнения: как только заканчивается вызов метода, исходный контекст вызывающего метода восстанавливается.

Взаимодействие между компонентами EDA не обеспечивает этих функций: оно ограничено тем, что компонент публикует событие, которое может быть воспринято (обычно с некоторой задержкой) одним или несколькими другими компонентами. Никакого изначально присущего согласования, непрерывности или сохранения контекста здесь нет. Так почему стоит отказаться от этих в высшей степени полезных вещей, ценность которых понятна каждому разработчику? Ответ заключается в том, что использование стека вызовов требует некоторых допущений. Сами по себе допущения — вещь неплохая, важно до конца понимать, соответствуют ли им реальные условия выполнения. Давайте вкратце рассмотрим основные допущения, которые всегда сопутствуют стеку вызовов.

Во-первых, стек вызовов наиболее удобен в окружении, где события происходят одно за другим. Факт, что один адрес возврата, помещенный в стек, соответствует единственному способу выполнения: выполнение вызывающего метода не продолжается по окончании работы вызываемого метода. Явное преимущество здесь в том, что вызываемый метод не должен заботиться о проблемах синхронизации или согласованности. Поскольку стек вызовов предполагает построчное выполнение программы, считается, что вызов и выполнение методов происходят так же, как выполнение первичного кода. Это приводит к тому, что вызывающий метод должен дождаться результатов работы вызванного метода, и только после этого продолжить работу. Если вызываемый метод выполняется медленно или требует больших ресурсов, это допущение может стать помехой. Например, именно по этой причине системы, основанные на Web-сервисах, меняют стиль взаимодействия, переходя с удаленного вызова процедур (Remote Procedure Call, RPC) на обмен сообщениями.

Столь же важно допущение, что системы «знают», в каком порядке и что именно должно происходить. Поскольку один метод обращается к другому путем прямого вызова, вызывающий метод должен ясно представлять, что произойдет дальше. Предполагается, что вызывающий метод знает не только о том, что случится, но и о том, какой метод должен это обеспечить. На первый взгляд это может показаться странным — отделять знание того, что должно быть сделано, от того, какой метод следует для этого использовать. Поэтому названия методов стали содержать (или, по крайней мере, должны содержать) указание на функции, которые они выполняют. Но прямой вызов одного метода другим по-прежнему означает привязку исполнения определенных функций к вызову соответствующего метода. Часто эта прямая связь должна устанавливаться в процессе компиляции, и впоследствии ее трудно изменить. Во многих случаях такая связь проблемой не является. Это выглядит в высшей степени удобным — устанавливать имя покупателя вызовом метода customer.SetName(). При необходимости полиморфизм позволит реализовать косвенную связь между вызывающим методом и методом-исполнителем, так что дочерний класс customer не будет участвовать в другой реализации SetName.

И последнее, но не менее важное: стек вызовов процветает в окружении, где вызывающий и вызываемый методы делят одну область памяти. Это позволяет компилятору и сборщику вставлять прямые ссылки на методы и экономить ресурсы, используемые при вызове. Также, если в системе используется одно пространство памяти и один процессор, она обречена на последовательное выполнение программ, что опять-таки как нельзя лучше соответствует идеологии стека вызовов.

В центре внимания — взаимодействие

Стек вызовов задает особый способ взаимодействия между компонентами, популярный и понятный всем. Поскольку стек вызовов рассматривается как стандартный механизм взаимодействия, при объектно-ориентированном программировании структурным аспектам решения уделяется больше внимания, чем вопросам, связанным с взаимодействием. Это, вообще говоря, правильно для большинства объектно-ориентированных систем, каждая из которых существует в едином пространстве памяти и находится под контролем одной команды разработчиков, т.е. для систем, соответствующих основным допущениям стека вызовов.

Традиционный объектно-ориентированный подход игнорирует не все взаимодействия. Некоторые классические образцы, представленные в [2], предполагают определенный способ взаимодействия объектов. Например, класс Mediator «инкапсулирует способ взаимодействия ряда объектов», в то время как класс Observer «регистрирует все объекты, на которые повлияло изменение состояния». Оба образца выводят взаимодействие объектов из тени и поднимают его до уровня первых ролей в объектной модели. Приведенные примеры указывают на то, что изучение способа взаимодействия объектов может быть более интересным, чем кажется на первый взгляд.

В распределенных системах ценность взаимодействия существенно увеличивается, а важность самого факта взаимодействия резко возрастает. В то же время структурные аспекты могут отодвинуться на задний план, поскольку распределенные системы, как правило, не имеют в этой области сложных механизмов, таких как наследование, полиморфизм и т.п. Этот перенос внимания со структуры на взаимодействие является центральной темой многих споров о сервис-ориентированном программировании. Сервис-ориентированные архитектуры строятся по более простым правилам, но уделяют много внимания слабосвязанному взаимодействию между системами.

Связывать или не связывать?

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

Способ взаимодействия компонентов отражается и на связи объектов. Чем больше правил и допущений содержится в протоколе взаимодействия, тем больше связей между объектами в нем представлено. Более простые правила взаимодействия подразумевают более слабую связь, т.к. на объекты-участники накладывается меньше ограничений.

Существуют две главные стратегии, направленные на ослабление связи между взаимодействующими объектами.

  1. Добавление уровня косвенности, или изоляции.
  2. Упрощение правил взаимодействия.

Есть постулат, что любая проблема в программировании может быть решена путем создания дополнительного уровня косвенности. Конечно, такой подход допустим и при решении проблемы связывания объектов. Если мы хотим обеспечить косвенное взаимодействие двух компонентов, мы можем вставить между ними третий компонент (посредник), чтобы изолировать их друг от друга. Применительно к объектно-ориентированному программированию это показано на примере объекта Mediator [2]: один объект вызывает объект-посредника, который, в свою очередь, и определяет объект вызова.

Рис. 4. Взаимодействие на основе механизма каналов

Этот подход позволяет повысить многократность использования объектов, т.к. взаимодействие выделено в такой элемент, который можно настроить или изменить, не затрагивая исходных компонентов. Он лежит и в основе архитектур, ориентированных на сообщения [3]: вместо прямого взаимодействия компоненты посылают сообщения по каналам событий.

Второй аспект связывания относится к правилам взаимодействия. Взаимодействие посредством стека вызовов осуществляется по строгим правилам: один метод вызывает другой и ожидает результатов вызова. Затем выполнение продолжается с того места, где оно было прервано. Один из способов борьбы со связыванием взаимодействующих сторон заключается в упрощении правил взаимодействия. Если мы устраним такие аспекты взаимодействия, как непрерывность и согласованность, останется только факт посылки данных от одного компонента к другому. И тогда нам будет совершенно необходимо найти форму обмена данными, которая даже проще, но не хуже, чем взаимодействие посредством имен.

Что в имени?

Взаимодействие, основанное на механизме каналов, представляет два новых элемента: канал и сообщение. Несмотря на простоту, эти новые элементы открывают дополнительные возможности и дают толчок новым решениям. Вопрос «как назвать канал» обманчиво прост. Когда один метод непосредственно вызывал другой, между ними не было элемента-посредника, а значит, не было и необходимости принимать подобное решение.

При простейшем подходе для каждого компонента отводится отдельный канал. Например, компонент, отвечающий за подтверждение подлинности кредитных карт, можно назвать CreditService и заставить реагировать на сообщения, приходящие по каналу с тем же названием. Если какому-либо компоненту понадобится что-либо, связанное с кредитом, он может отправить сообщение по этому каналу. В то время как канал обеспечивает нам некоторую изоляцию на уровне реализации (можно заменить одну реализацию кредитного сервиса на другую без предупреждения, совершенно незаметно), семантика взаимодействия не сильно меняется. Вызывающий метод по-прежнему должен знать, какой компонент обеспечивает требуемую функциональность, что весьма напоминает сценарий действий при использовании стека вызовов.

Рис. 5. Система «запросов-команда»

Для ослабления зависимости от конкретного сервиса можно было бы дать каналу имя, соответствующее имени метода. Например, если сервис выполняет операцию проверки кредитной карты покупателя, мы могли бы назвать канал просто VerifyCreditCard (рис. 5). Это отчасти повысит уровень абстракции, поскольку избавит вызывающий метод от необходимости знать, какой компонент способен обслуживать запросы такого типа. Сервис-ориентированные системы в целом следуют такому подходу.

Несмотря на изменения в представлении канала, семантика взаимодействия по-прежнему отдает стеком вызовов. Один компонент посылает запрос («проверьте эту кредитную карту») и ожидает ответа («хорошая карта» или «плохая карта»). Но творческие возможности семантики каналов этим не исчерпываются. Приведенные примеры предполагают, что компонент знает о необходимости проверки кредитной карты. Можно ли совсем снять с вызывающего метода эту нагрузку, так, чтобы компоненты вообще не были связаны? Можно пойти еще дальше, заменив имя канала (и связанную с ним семантику) на OrderReceived. Это простое изменение имени знаменует существенный сдвиг ответственности. Сообщение, передаваемое по каналу, — больше не инструкция, а событие, извещение о том, что что-то произошло. Мы больше не предполагаем, что существует единственный объект—получатель сообщения о событии. Опять-таки число взаимных допущений для сторон обмена данными уменьшилось. Благодаря этому EDA часто считается более слабосвязанной архитектурой, чем SOA.

Передача ответственности

Преход от обмена командами к обмену событиями представляет небольшой, но важный сдвиг ответственности. Она позволяет ослабить связь между компонентами до такой степени, что вызывающий объект больше не осведомлен о том, какая функция будет выполнена дальше или какой компонент ее выполнит. Другой столь же важный сдвиг ответственности между вызывающим и вызываемым объектом связан с сохранением состояния.

В системе, основанной на выполнении запросов и команд, состояние обычно сохраняется в одном приложении, которое считается «главным» (master) при хранении данных. Когда другому приложению нужно обратиться к этим данным, оно посылает запрос приложению, хранящему данные, и дожидается ответа, чтобы продолжить работу. Например, когда системе обработки заказов требуется оформить заказ, она запрашивает системы хранения данных о покупателях, чтобы получить адрес заказчика и дать системе управления доставкой команду отправить заказ на этот адрес (рис. 6).

Рис. 6. Структурная модель системы

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

Принцип, лежащий в основе передачи ответственности, еще раз примыкает к понятию связи объектов. При слабосвязанном взаимодействии от источника данных не требуется сохранять состояние, соответствующее требованиям его партнеров по информационному обмену. Перенеся нагрузку по сохранению состояния на получателя, компонент может стать полностью безразличным к нуждам других компонентов—получателей данных, а это ключевая составляющая слабосвязанности. Переход от модели ответов на запросы к модели взаимодействия означает, что многие компоненты должны действовать как «комбинаторы событий» [3]: они отслеживают события, публикуемые различными источниками, сохраняют соответствующее состояние и комбинируют информацию о различных событиях, создавая таким образом новые. Например, система управления доставкой эффективно комбинирует события, связанные с изменением адресов, и формирует из них запрос на доставку заказа по конкретному адресу.

Комплексные события

Из EDA можно извлечь больше выгоды, чем из слабосвязанности и независимой изменчивости. Система, компоненты которой взаимодействуют только посредством событий, позволяет легко отследить и проанализировать все взаимодействия. Вокруг анализа последовательностей событий и понимания их иерархии возникло целое научное направление. Например, частые повторения серий похожих друг на друга событий-запросов, поступающих на Web-сервер, означают, что сервер подвергается распределенной атаке, направленной на остановку его работы. То, что эта последовательность событий-запросов сама по себе является значительным событием, о котором следует сообщить, факт. Описанный тип иерархии событий является предметом обработки сложных событий (Complex Event Processing, CEP) [1].

Быстрая прокрутка

Системы, основанные на событиях, имеют и другие преимущества. В системах, все компоненты которых взаимодействуют посредством событий, можно полностью воссоздать состояние, заново проиграв все события. К этой категории относится большинство финансовых систем. Финансовая система не только сохраняет текущее состояние банковского счета (баланс), но и регистрирует все события, происходящие с этим счетом (внесение или снятие средств). Мартин Фулер назвал такой подход «порождением событий» (Event Sourcing) [4].

Приложения, порождающие события, имеют два ценных качества. Первое — состояние системы может быть воссоздано даже после потери отдельного компонента. Проигрывание заново всех событий, произошедших с компонентами, позволяет каждому компоненту последовательно восстановить состояние, в котором он был, не прибегая к другим механизмам восстановления. Возможность переиграть события, внося изменения, представляется даже более интересной. Можно сказать, что мы можем переписать историю, внеся изменения в поток прошедших событий и затем переиграв измененный поток. Это качество может стать неоценимым в реальной жизни. К примеру, покупатель, который в течение года заказывает определенное количество товаров, в конце года может рассчитывать на скидку. Если сумма заказов данного покупателя превышает некоторое значение, но в новом году покупатель возвращает товар, скидка ему не полагается. Традиционные системы используют специальную логику для проверки того, отодвигает ли сумма возвратов данного покупателя ниже определенного порога, и дебетования счета покупателя на сумму ранее полученной им скидки. Система, порождающая события, может разрешить эту ситуацию более элегантно. Возвращенный товар обнуляет событие «покупка». Впоследствии мы можем переиграть измененную серию событий, связанных с покупками, пропустив обнуленное событие. Связанная с этим бизнес-логика вычислит окончательный баланс счета покупателя без учета скидки. Затем мы можем сравнить измененный сценарий с исходным и вычислить поправку, без необходимости понимания изначальных принципов бизнес-логики (например, когда скидка заменяется выплатой). Легко заметить, что для сложных бизнес-правил переигрывание событий может оказаться возможностью, которую трудно будет переоценить.

Комбинирование событий

Итак, что мы имеем в результате? Очевидно, что у EDA имеется множество желанных свойств. Но гибкость, которую обеспечивает слабосвязанность, достигается ценой сокращения проверки при сборке; слабосвязанность также может привести к тому, что система высокой сложности может быть собрана многими способами, а это не имеет смысла или не соответствует нашей цели. Например, источник и получатель события могут быть случайным образом настроены на другой тип событий или канал (возможный результат обычной опечатки при вводе имени). В результате до получателя не дойдет вообще ни одного сообщения. Но мы не обнаружим этого, пока не запустим систему, и даже тогда будет трудно определить истинную причину проблемы. Получатель ожидает не тех сообщений? Отправитель посылает неверные сообщения? А были ли вообще разосланы сообщения о событиях? Не произошел ли разрыв канала связи? Удобство настройки может внезапно обернуться необходимостью отладки. Именно об этом предупреждал Мартин Фаулер словами: «Мечта архитектора — это кошмар разработчика».

Гибкость и восприимчивость к изменениям могут обернуться неопределенностью. Если архитектура системы допускает развитие отдельных компонентов, уже завтра система может выглядеть иначе, чем вчера. Поэтому крайне необходимо создавать инструменты для настройки и анализа таких систем. Составление из отдельных компонентов связного, событийно-управляемого приложения должно рассматриваться как дополнительный уровень архитектуры системы в целом. Этот уровень следует принимать так же серьезно, как и уровень кода ядра. Слишком часто информация о строении системы (т.е. имена опубликованных каналов или каналов, открываемых по подписке) скрыта в зашифрованных файлах конфигурации, которые разбросаны по разным компьютерам. Вместо этого следует определить специальный язык, который будет использоваться разработчиками для сборки системы. Этот язык мог бы включать правила проверки заданных конфигураций флагов. Например, конфигурация, предусматривающая подписку на события, не соответствующую ни одной публикации, может быть признана недействительной. Циклические ссылки в графе событий также нежелательны и должны быть выявлены на этапе разработки.

Визуализация

В отличающихся высоким уровнем распределенности и слабосвязанных системах определение реального состояния может представлять трудность, т.к. они непрерывно развиваются. Еще серьезнее, что важнейшая информация часто рассредоточена по многим компьютерам. В таких ситуациях неоценимую помощь может оказать генерация модели из работающей системы. Это может быть выполнено путем оснащения системы своего рода датчиками, отслеживающими посылку и получение сообщений. Датчики направляют собранную информацию в центр, где она проецируется на абстрактную модель системы, например, направленный граф.

Такой граф затем можно выполнить с помощью алгоритма представления графов, например AT&T GraphViz (www.graphviz.org). В результате будет получена удобная для чтения и точная структурная модель системы. Такая модель и диаграмма могут оказаться бесценными для отладки и анализа.

Выводы

Системы, управляемые событиями, могут представлять интересную конструкцию, отличную от традиционной, «командно-контролирующей». EDA позволяют создавать слабосвязанные системы с большими композиционными возможностями, которые часто сильно схожи с событиями реальной жизни. Последовательное применение сообщений как механизма взаимодействия компонентов позволяет использовать такие технологии, как переигрывание событий, которое почти недоступно для традиционных систем. Однако, за все эти преимущества приходится платить. Системы, переходящие от хорошо известных принципов стека вызовов к слабосвязанному взаимодействию, по природе более сложны для разработки и отладки. Следовательно, для создания динамической, но упорядоченной системы необходимо использовать инструменты управления и визуализации.

Литература
  1. David Luckham, The Power of Events. Addison-Wesley, 2002; www.complexevents.com.
  2. Erich Gamma et al., Design Patterns. Addison-Wesley.
  3. Gregor Hohpe, Bobby Woolf, Enterprise Integration Patterns. Addison-Wesley, 2003; www.eaipatterns.com.
  4. Martin Fowler, Further Patterns of Enterprise Application Architecture; Addison-Wesley, 2002.

Грегор Хоуп (info@enterpriseintegrationpatterns.com) — архитектор программного обеспечения компании Google.


Ключевые характеристики EDA

  • Широковещательный обмен данными
  • Своевременность
  • Асинхронность
  • «Мелкозернистость» событий
  • Онтология
  • Обработка сложных событий

Допущения стека вызовов

Основные допущения, которые всегда сопутствуют стеку вызовов:

  • события обрабатываются однократно;
  • мы знаем, что и в каком порядке должно произойти;
  • мы знаем, кто может обеспечить выполнение нужной функции;
  • выполнение осуществляется на единственной виртуальной машине.

Gregor Hohpe, Programming Without a Call Stack— Event-driven Architectures, www.eaipatterns.com, 2006. Copyright by Gregor Hohpe. All rights reserved. Reprinted with permission.