It seems odd to me that the command that will create a new instance of an aggregate are processed in instance methods or the constructor of the aggregate. In my head, the constructor should receive an event to set up a proper instance with initial invariants like aggregate Id is mandatory and final. Calling the constructor with a command will create and aggregate with all the fields null, 0 or false, that could be and invalid state of the aggregate and also contradicts the rule of do not mutate the aggregate in the command handlers, just in the event handlers.
Also, if you rebuild a new system, the event or events that create the command aggregates, with the current approach, need the aggregate is already created, do not create new ones.
Are there any technical limitations?
Maybe the command could be processed in a static method? (event factory method)
I normally encounter that the aggregate creation is the result of the execution of a domain service, several aggregates are involved: external services, clocks, random sources… but I see so many code that end up injecting all the dependencies in the constructor of the aggregate. It does not seem right to me. It creates so many dependencies between the aggregate and other parts of the system. Is that a common practice?
I asked similar questions 7 years ago in the old Google Groups channel. Now that I would like to use Axon again in a big project, It seems a good time to ask it once more.
I second this. In particular, the need to make attributes like the aggregate ID nullable (using Kotlin here) when they clearly shouldn’t be from a domain perspective has been bugging me, too.
@sebastian.hans thank you. The same happens to Spring Framework some years ago. When they decide to use the constructor properly to create instances and avoid injecting using fields or methods. We end up with a proper instances with all the mandatory fields set up in the constructor. And almost every field is final now. Objects do not require being in an invalid state anymore.
Another problem with the constructor processing a command is that forces Axon static event dispatcher method into event aggregate classes. A static factory method could just return an event or a list. I do not see the actual point of that static call. And maybe breaks the SRP, coupling the command aggregate with the framework and add another reason to change the class.
these are very valid points that you have brought up. In Axon 5, for which we have recently released the first milestone, we will thoroughly revise how constructors work.
In fact, the approach we have right now is that it is the first event that is passed as the constructor parameter, rather than a command.
I recently got a demo from one of the Framework team members that showed how a different approach works much more nicely with immutable objects and doesn’t require any nullable fields.
On the other hand, Axon is open source software. If there is something you think should improve, feel free to submit a PR for it.
Oh, and additionally, you don’t have to use a Constructor command handler. You can also use a statis method declared on the Aggregate class that returns an instance of a constructed aggregate. You can then choose how you want to construct your object.
Thanks for your answers @allardbz. What are your thoughts on returning the events instead of calling a static dispatcher in the command handlers.
About the PR, I would like to contribute, but the time constrains and my lack of current knowledge about Axon makes me unfit for the task. Maybe in 6 months, after using it again, I will be more active in the community.