Создаем неструктурированный процесс в Camunda
или – как выжить без Ad Hoc и CMMN?
CBOK определяет понятие "бизнес-процесс" как "набор функций, выполняемых в определенной последовательности для создания потребительской ценности".
"A collection of related, structured activities or tasks performed by people or equipment to achieve a specific organizational goal".
Предполагается, что модель процесса (Process definition) имеет четко определенную структуру, которой следуют все экземпляры процесса (Process instances). Такие линейные процессы можно встретить, например, в банках, страховых компаниях, ритейле и маркетплейсах.
Но как быть, если экземпляры процесса не имеют одинаковой структуры? Как быть, когда решения в процессе выполняются ситуативно, на основе экспертного опыта, а задачи могут быть выполнены разное число раз и в любой последовательности?
Примеры неструктурированных процессов:
-
Медицина (Healthcare Case Management). Лечение пациента редко следует заранее известному процессу. В зависимости от диагноза, реакции на лечение и других факторов, процесс может изменяться.
-
Юриспруденция (Legal Case Management). В правовых процессах многие задачи зависят от того, как будет развиваться дело, какие доказательства будут предоставлены и каков будет ответ другой стороны.
-
Обслуживание клиентов (Customer Service). В случае обработки запросов клиентов задачи могут варьироваться в зависимости от типа проблемы, её срочности и ответных действий клиента.
-
Управление проектами (Project Management). Для проектов с гибкой методикой может потребоваться корректировка в зависимости от уже достигнутых целей и результатов.
Ad Hoc и CMMN
Первое, что приходит на ум аналитику, владеющему BPMN – подпроцесс по требованию (Ad Hoc Subprocess).

(Ad Hoc, он же подпроцесс по требованию)
Однако, в Camunda поддержка Ad Hoc отсутствует, о чем нам любезно (и очень давно) сообщает Найл на форуме Camunda, рекомендуя использовать CMMN или "иные символы BPMN".

(Camunda не поддерживает Ad Hoc)
При попытке загрузить процесс с Ad Hoc в камунду, система выведет ошибку, выругавшись на некорректное назначение (или источник) последовательности выполнения:
* Invalid destination 'Activity_1xvqljd' of sequence flow 'Flow_0cma5xm'
Попробуем воспользоваться советом Найла и обратимся к CMMN (Case Management Model and Notation). Эта нотация была разработана Object Management Group для для более гибких сценариев, где задачи могут быть непредсказуемы, а их выполнение зависит от динамически меняющихся обстоятельств.
Но разочарование ждет нас и здесь. По словам основателей Camunda, CMMN не оправдала возложенных на неё ожиданий. В сравнении с BPMN, CMMN слишком сложная и запутанная, а ценность применения её в проектах оказалась слишком низкой. Подробнее почитать об этом можно в блоге Camunda.
В Camunda Modeler CMMN по-умолчанию отключена (как включить CMMN в Camunda Modeler). А Camunda 8 эту нотацию вообще не поддерживает.
Что же делать?
TMTOWTDI (There's More Than One Way To Do It)
К счастью, многое из того, что позволяют сделать Ad Hoc или CMMN, может быть реализовано при помощи комбинации DMN + BPMN.
Наглядный пример из жизни – документарное сопровождение проектной деятельности.
Каждый проект автоматизации процессов по-своему уникален. У каждого заказчика свои условия контрактования и оплаты. Одни могут авансировать работы, другие – нет. Кто-то готов подписать акты и до фактического их завершения, а кто-то – строго после завершения всех доработок. С одними заказчиками мы обмениваемся документами через ЭДО, а другие – хотят иметь бумажные оригиналы.
Соответственно, набор задач и последовательность их выполнения в таком процессе отличаются от заказчика к заказчику, от проекта к проекту.

(типичный набор задач в процессе сопровождения проекта)
Неизменно только одно – для завершения процесса должны быть завершены следующие его этапы:
-
Получена оплата,
-
Получены подписанные оригиналы документов,
-
Завершены работы.
Для того, чтобы реализовать такую неструктурированную магию, нам понадобится 3 ингредиента:
-
DMN (Business Rule Task);
-
Activity (Task, Call Activity, Subprocess) с маркером Multi-instance;
-
Язык выражений (FEEL – для Camunda 7 и 8, FEEL + JUEL для Camunda 7).

(магический процесс)
Здесь и далее, в целях наглядности, задачи процесса будут представлены как User Tasks, а процесс смоделирован для Camunda 7.
DMN и Business Rule Task
Создадим таблицу решений contract, входом которой будет переменная процесса contract, представляющая собой объект, содержащий параметры контракта.
{
"contract":
{
"value":
{
"edi": true,
"prepayment": false
}
}
}
На выходе таблицы будет переменная tasks – массив или коллекция строк (List<String>), представляющая собой список наименований пользовательских задач.
В качестве Hit Policy подойдет Collect или (если важен порядок выполнения активностей) – Rule Order.

(DMN, которая будет управлять структурой процесса)
Не забудьте указать наименование выходной переменной процесса и метод сбора данных – CollectEntries (в Camunda 8 указывать тип не нужно, там все в JSON).

(выходная переменная)
Настройки задачи (Activity Properties)
Перейдем к настройкам задачи. Важное преимущество Camunda – возможность использования языка выражений (Expression Language). В Camunda 7 это JUEL (Java Unified Expression Language), а в Camunda 8 – FEEL (Friendly Enough Expression Language).
С помощью выражения вы можете определить:
-
Имя задачи (Activity Name);
-
Топик (Topic) для External Task;
-
Вызываемый элемент (Called Element) для Call Activity.
Таким, образом, DMN таблица определяет набор и порядок выполнения активностей, а язык выражений, путем подстановки значения, обеспечивает выбор нужной реализации.
Зададим маркер активности задачи. Если задачи могут быть выполнены в любом порядке, подойдет Parallel multi-instance. Если важен порядок выполнения задач – необходимо выбрать Sequential multi-instance (в этом случае не забываем также использовать Hit Policy Rule Order в DMN-таблице).

(маркер активности)
Число экземпляров активности = числу элементов в массиве tasks. Его необходимо указать в поле Collection. Содержимое элемента, который будет подставляться в имя задачи, поместим в локальную переменную с именем task. Её же укажем в качестве имени задачи при помощи языка выражений: ${task}.

(настройки задачи)
Развернем полученные артефакты в Camunda и запустим процесс, подав на вход переменную contract:

(входные данные)
Найдя в Cockpit экземпляр процесса, мы видим следующую картину:

(параллельно выполняемые задачи)
Появилось семь экземпляров задач, получивших нужные наименования, которые пользователь может увидеть в списке задач (Tasklist):

(список задач)
Поскольку задачи выполняются параллельно, они могут быть выполнены в любом порядке.
Приведенный выше пример является упрощенным. Однако, эти же принципы могут быть применены и при проектировании более сложных процессов, где часть этапов может выполнятся последовательно, а часть – параллельно. Пользовательские задачи могут быть заменены на сервисные (External Task). Сложная логика может быть вынесена в вызываемые активности (Call Activity). А дополнительной "событийности" могут добавить подпроцессы по событию (Event Subprocess).
Доводилось ли вам решать похожие задачи? Предлагаю обсудить концепцию на нашем форуме.
другие статьи
Смотреть всёНачальные события в BPMN
Краткий ликбез по начальным (стартовым) событиям BPMN