Aggregating the Behaviour
The combine
is a binary operation over the decider
, view
and saga
, satisfying associativity and having an
identity/empty element.
Associativity facilitates parallelization by giving us the freedom to break problems into chunks that can be computed in parallel.
Functional paradigm and category theory define this algebra as a Monoid
.
Stated tersely, a monoid
is a type together with a binary operation (combine
) over that type, satisfying
associativity
and having an identity element (zero/empty).
combine
operation is also commutative / commutative monoid
- Decider
- View
- Saga
associative: (decider1 + decider2) + decider3 = decider1 + (decider2 + decider3)
commutative: decider1 + decider2 = decider2 + decider1
zero: decider1 + decider0 = decider1
By combining two or more deciders you get the new decider.
This is a formal signature of the combine
function defined on the decider
:
combine<C2, S2, E2>(decider2: Decider<C2, S2, E2>): Decider<C | C2, S & S2, E | E2>
Example:
const restaurantDecider: Decider<RestaurantCommand, Restaurant | null, RestaurantEvent>
const orderDecider: Decider<OrderCommand, Order | null, OrderEvent>
// Combining two deciders into one big decider that can handle all commands of the system.
const decider: Decider<RestaurantCommand | OrderCommand, (Order & Restaurant) | null, RestaurantEvent | OrderEvent> =
restaurantDecider.combine(orderDecider);
Mappable
Additionally, Decider<C, S, E>
provides map functions:
mapContraOnCommand<Cn>(f: (cn: Cn) => C): Decider<Cn, S, E>
dimapOnEvent<En>(fl: (en: En) => E, fr: (e: E) => En): Decider<C, S, En>
dimapOnState<Sn>(fl: (sn: Sn) => S, fr: (s: S) => Sn): Decider<C, Sn, E>
associative: (view1 + view2) + view3 = view1 + (view2 + view3)
commutative: view1 + view2 = view2 + view1
zero: view1 + view0 = view1
By combining two or more views you get the new view.
This is a formal signature of the combine
function defined on the view
:
combine<S2, E2>(view2: View<S2, E2>): View<S & S2, E | E2>
Example:
const restaurantView: View<RestaurantView | null, RestaurantEvent>
const orderView: View<OrderView | null, OrderEvent>
// Combining two views into one big view that can handle all events of the system.
const view: View<(RestaurantView & OrderView) | null, OrderEvent | RestaurantEvent> = restaurantView.combine(orderView);
Mappable
Additionally, View<S, E>
provides map functions:
mapContraOnEvent<En>(f: (en: En) => E): View<S, En>
dimapOnState<Sn>(fl: (sn: Sn) => S, fr: (s: S) => Sn): View<Sn, E>
associative: (saga1 + saga2) + saga3 = saga1 + (saga2 + saga3)
commutative: saga1 + saga2 = saga2 + saga1
zero: saga1 + saga0 = saga1
By combining two or more sagas you get the new saga.
This is a formal signature of the combine
function defined on the saga
:
combine<AR2, A2>(saga2: Saga<AR2, A2>): Saga<AR | AR2, A | A2>
Example:
const restaurantSaga: Saga<OrderEvent, RestaurantCommand>
const orderSaga: Saga<RestaurantEvent, OrderCommand>
// Combining two choreography sagas into one big system orchestrating saga.
const saga: Saga<RestaurantEvent | OrderEvent, RestaurantCommand | OrderCommand> = restaurantSaga.combine(orderSaga);
If the constraints are not met, the combine
function will not be available for usage!
Mappable
Additionally, Saga<AR, A>
provides map functions:
mapContraOnActionResult<ARn>(f: (arn: ARn) => AR): Saga<ARn, A>
mapOnAction<An>(f: (a: A) => An): Saga<AR, An>