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

Можно было бы смоделировать это, используя поле статуса в заказе, где значение этого поля статуса будет одним из «Неоплачено», «Оплачено» или «Отправлено». Должна быть ясна опасность, связанная с предоставлением кому-либо возможности напрямую редактировать поле статуса. Например:

  • Если вручную переместить заказ из «Неоплаченного» в «Оплаченный», это приведет к подготовке и отправке неоплаченного товара.
  • Если вручную переместить заказ из статуса «Неоплаченный» в «Отправленный», покупателю может показаться, что его товар находится в пути, а это не так.

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

Грязные машины

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

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

Суть этой проблемы в том, что один конечный автомат представляет смешанные задачи. Я видел системы, которые пытались объединить воедино представление нескольких различных независимых рабочих процессов, каждый из которых легко представлен конечным автоматом с двумя –4 состояния - в одно поле статуса, что приводит к десяткам непонятных значений статуса. При таком моделировании это единое поле состояния затем начинает представлять несколько частей информации. Конечный автомат накапливает ненужную сложность. Разрешенными переходами между этим большим набором состояний управлять гораздо труднее, особенно при внесении изменений в рабочий процесс. Рассмотрим моделирование нашего примера сценария оплаты и доставки заказа как двух независимых рабочих процессов:

В этом сценарии мы называем отгрузку, готовую к подготовке, «Готовой»; например, «это готово к работе». Сравните это с объединением обоих рабочих процессов вместе:

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

При объединении рабочий процесс становится более сложным:

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

Опять же, изолированные рабочие процессы:

А теперь разрозненные рабочие процессы ...

Хорошо, и что теперь?

Если внимательно посмотреть на это, можно сделать две ошибки:

Ошибка №1: «Меня это не волнует, это должны заботить только программисты».

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

Ошибка №2: «Разбивая это на части, мы делаем более простую систему».

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

Считается вредным?

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

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