Hi,
I have question about how to implement custom aggregate lifecycle. My scenarion looks like this:
- I have library where is PlayerAggregate which represents a player which can play some game for example
- In another project I want to use that PlayerAggregate, but I want to add/change some its behaviour.
- I know that player can be in states PLAYING, DEAD
- depends on what state player is, I want to react on events from PlayerAggregate which are
about to apply. For example, lets say that there is command MovePlayer(…) (which is in the same library as
PlayerAggregate) and before event PlayerMoved is applied I want to react on that: if player is in state DEAD I throw
exception like PlayerCannotMoveWhenDead. - I also want to listen for evens which happened in that aggregate and change player state and maybe generate other
domain events
I hope you get a point what I want to do. I have some library with predefined aggregates, commands and events. I’m going
to used that library in my own applications and I want to customize aggregates behaviour.
I have two ideas how ti implement this:
- I can create class Lifecycle extends AbstractAnnotatedEntity, so it will
be basically part of aggregate.
- I can send command like CreatePlayer(…, MyCustomPlayerLifecycle.class) and new instance is created in
PlayerAggregate constructor.
pros
- I can listen for domain events by @EventHandler and make state transitions
- Before I create and apply events I can pass it to the lifecycle to check them if they are valid in
current state
cons
- how can I call methods on PlayerAggregate? I cannot simply call apply(new SomeEvent()) without aggregate
validation. I can get reference on PlayerAggregate and call its methods but there is another problem
that if I call two methods which are dependend, it does not work because event are queued and applied after
end of unit of work.
- Another way is to implement lifecycle as a Saga. When PlayerAggregate with some lifecycle is created, new instance
of Saga is created for that aggregate which will manage its lifecycle.
pros
- I can listen for domain events by @EventHandler and make state transitions
cons
- If I want to make some actions on PlayerAggregate from the saga lifecycle, I can simply send commands,
but I want to make sure that all commands are successfull or all are rollbacked, so I have same problem as in 1) - When PlayerAggregate want to change its state it must send an request event, saga can accept or reject that,
depends on its current state and then send commands to PlayerAggregate. I don’t like this communication.
I want to know if anyone has experience with this scenario and how should I solve that. It will be cool to have some predefined aggregates, with
an API (events, commands and exceptions) with possibility to change/add some custom behaviour instead of creating new aggregate of subclassing.