Skip to content

Кейс о том, что паттерн fsm не желательно использовать в связке с ddd

Notifications You must be signed in to change notification settings

froozer/fsm_in_ddd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 

Repository files navigation

fsm_in_ddd

Многим знаком паттерн 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, так как это вносит искажения смысла моделируемой предметной области. Заказ, заявка или документ не имеют свойства "статус" в реальном мире.

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

Аргументы против FSM

  1. Все возможные состояния агрегата не всегда возможно выстроить в какую-то цепочку состояний. Например, изначально у нас есть статусы Created, Paid, Delivered. Потом бизнес-логика может измениться: оплату теперь можно производить и после доставки с отсрочкой. В таком случае статус оплаты становится самостоятельным свойством, а спустя еще 2 итерации та же судьба ждет остальные статусы.
  2. Вводится некий класс (в зависимости от реализации - несколько классов) для описания состояний объекта и логики переходов между ними, что нарушает инкапсуляцию этого объекта.
  3. Для каждого свойства State требуется свой справочник (в DDD вообще есть справочники?), который придется включить в API. Это накладывает ограничение на изменение этого справочника и логики, которая от него зависит.

Аргументы за FSM

  1. Сама конструкция FSM проще и легко маппится на представление. На сайте клиенту требуется отобразить статус заказа - демонстрируем ему статус из БД.
  2. Позволяет в одном месте описать (и прочесть) все возможные переходы и ограничения на эти переходы.
  3. Исходя из пункта 2, можно построить визуализацию переходов (в виде графа, например) с помощью готовых инструментов вроде XState Visualizer

About

Кейс о том, что паттерн fsm не желательно использовать в связке с ddd

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published