Многим знаком паттерн finite state machine (далее fsm). Один из примеров его реализации - [https://github.com/ardalis/StatePattern]. Применение его можно часто увидеть в приложениях для ритейла (статус заказа: создан, оплачен, собран, отправлен...), банкинга (кредитный конвеер) и многих других сфер бизнеса.
Однако, в приложениях, реализованных по принципам DDD, всегда можно реализовать эквивалент State иначе.
application.State == "Underwriting"
можно заменить на
// нет решения андеррайтера
application.UnderwritingRequest.Decision == null
// требуется как минимум 2 согласия андеррайтера
application.UnderwritingRequest.Decisions.Count(x => x.Approved) < 2
а
order.State == "Delivered"
можно заменить на
// заказ доставлен, если получено согласие покупателя
order.Delivery.Accepted()
// заказ доставлен, если покупатель не воспользовался правом вернуть его в течение 14 дней
order.Delivery.Date < _twoWeeksAgo && order.RefundRequest == null
Таким образом можно сделать вывод, что при использовании DDD не нужно использовать FSM, так как это вносит искажения смысла моделируемой предметной области. Заказ, заявка или документ не имеют свойства "статус" в реальном мире.
С другой стороны, при моделировании мы не обязаны достичь полного совпадения и иногда имеем право упрощать какие-то вещи.
- Все возможные состояния агрегата не всегда возможно выстроить в какую-то цепочку состояний. Например, изначально у нас есть статусы
Created, Paid, Delivered
. Потом бизнес-логика может измениться: оплату теперь можно производить и после доставки с отсрочкой. В таком случае статус оплаты становится самостоятельным свойством, а спустя еще 2 итерации та же судьба ждет остальные статусы. - Вводится некий класс (в зависимости от реализации - несколько классов) для описания состояний объекта и логики переходов между ними, что нарушает инкапсуляцию этого объекта.
- Для каждого свойства State требуется свой справочник (в DDD вообще есть справочники?), который придется включить в API. Это накладывает ограничение на изменение этого справочника и логики, которая от него зависит.
- Сама конструкция FSM проще и легко маппится на представление. На сайте клиенту требуется отобразить статус заказа - демонстрируем ему статус из БД.
- Позволяет в одном месте описать (и прочесть) все возможные переходы и ограничения на эти переходы.
- Исходя из пункта 2, можно построить визуализацию переходов (в виде графа, например) с помощью готовых инструментов вроде XState Visualizer