Использование конечных автоматов для управления фоновыми заданиями — платежами и отгрузками, предоставлением серверов и даже уведомлениями — идея стара как мир, поэтому ей действительно нужно следовать.

Но внедрить конечный автомат для нашей работы сложно из-за двойной проблемы настойчивости и аудита. Сохраняем ли мы нашу конечную машину? Или мы сохраняем наши события? И если мы сохраняем наши события, что нам делать, чтобы получить (тот же) конечный автомат?

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

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

  • Оплата отражена в вашем приложении.
  • Вы выходите из продуктового магазина с продуктами.

Or:

  • Вы выходите из продуктового магазина с продуктами.
  • Оплата отражена в вашем приложении.

На самом деле это нормально, в каком бы порядке ни происходили эти события: конечным состоянием является наличие продуктов и оплата. В этом смысле они коммутативны. Если присутствует только одно или другое событие, то мы имеем состояния, указывающие на необходимость другого.

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

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

Есть только одна проблема: объединение (или встреча) вычисляет элемент множества, который больше (или меньше) заданной пары, но состояние не является элементом множества событий.