3

My question here is quite straight as mentioned in the subject. However, please allow me to give some brief explanation here about my innocent thoughts. I've been using Axon for approximately 10 months now. I used to design my project structure based on the Hexagonal architecture with two top level packages respectively for domain and infrastructure. Furthermore, domain package will contain different domain objects (as explained in the DDD concept) such as follow:

  1. Aggregate (this will be an Axon aggregate class).
  2. Repository (in my case, this will be a Spring Data Repository interface).
  3. Entity (in my case, this contains any lookup entity that i used for set-based consistency validation as written here).
  4. Service Port (collection of Input and Ouput port interfaces).
  5. Commands (representing Axon Command object).

As for Events, I used to put them on a different module that I compiled as a jar file, so I can share it to other developers whom going to use the same event in their project.

I've noticed recently that all of my commands and events were basically anemic models (an anti pattern that we should avoid). Is there any good practice on this ? Or, Is it something that intentionally used by design ?

I've been thinking to put my Command classes within my Aggregate class (as an inner classes). At least by using this approach I won't end-up with having so many anemic models scattered outside. Any thoughts ?

yauritux
  • 62
  • 7

2 Answers2

3

Commands are designed to be behavior and input structures mirroring the external world. They don't necessarily mirror an aggregate's structure.

They are not even connected clearly to one single aggregate, at times. Enclosing them within aggregates can be a code smell because you are then thinking in terms of resources and UI organization, instead of transaction boundaries and entity groups.

You are also violating the open-closed principle. Changes in volatile layers like user interface and request structures will make you edit the Aggregate class, and that is not good design.

On a more general note...

At times, this debate of anemic vs. non-anemic (or dry vs. non-dry) can push you in the direction of premature - and incorrect - optimization. Try avoiding this trap because you will end up optimising at the code level, but your domain will suffer.

DDD and CQRS guidelines align with principles that help you keep complexity at bay over the long term. Things kept distinct and separate help you achieve this.

Subhash
  • 3,121
  • 1
  • 19
  • 25
-1

First of all, in DDD, your domain had to be free of any frameworks, just use pure language library.

Then, mixing Commands and Aggregates cannot be a good solution. I think Commands belongs to Port while Aggregates belongs to the Hexagone.

Finally, DDD highlights the discovery of the domain thanks to the experts. Did you do that ? If not, if you're only using the Tacticts pattern, you'll miss one of the most important part of DDD.

Julien Gavard
  • 613
  • 1
  • 6
  • 20
  • 1
    Yes Julien..I'm also aware one of that main principle. Our domain should be just pure language library which is free from any framework/infrastructure stuff. Such architecture like hexagonal, clean code, and onion taught us on how to protect our business rule inside our domain, and any framework/infrastructure stuff should be moved to outside layer. However, since I'm using Axon... my Aggregate definitely contains some Axon stuff such as `@Aggregate`, `@CommandHandler`, and `@EventSourcing` annotations which seems like violate that main principle :-/. – yauritux Aug 02 '21 at 10:17
  • Nothing in DDD says that the domain model has to be free of ‘frameworks’. What you need to ensure, ut that you maintain the ability to model the domain with the least possible restrictions imposed by technical choices. Sometimes, frameworks actually help you achieve this. With Axon, we help you be expressive (hence the CommandHandler/EventSourcinfHandler) annotations. Try modelling without. Big chance it doesn’t get any better… – Allard Aug 03 '21 at 20:25