[#4060] Align completeness between old Aggregate and new Entity description#4562
[#4060] Align completeness between old Aggregate and new Entity description#4562laura-devriendt-lemon wants to merge 25 commits into
Conversation
smcvb
left a comment
There was a problem hiding this comment.
Thanks for picking up this task, @laura-devriendt-lemon! I do have quite some comments to address, though. Arguable quite some I could've clarified on the original issue...so my apologies for that. So, please bare with me here! 🙏
Co-authored-by: Steven van Beelen <steven.vanbeelen@axoniq.io>
hatzlj
left a comment
There was a problem hiding this comment.
I have one concern regarding the handling of sealed types for polymorphic models and some minor improvement suggestions. Overall it reads great and easy to follow.
smcvb
left a comment
There was a problem hiding this comment.
Sorry, bunch of comments to cover again. I think we need to do a bit more restructuring of the command-handlers.adoc and event-sourced-entity.adoc pages mostly.
Co-authored-by: Jakob Hatzl <hatzlj@users.noreply.github.com>
Co-authored-by: Jakob Hatzl <hatzlj@users.noreply.github.com>
Co-authored-by: Jakob Hatzl <hatzlj@users.noreply.github.com>
…rced-entity.adoc Co-authored-by: Jakob Hatzl <hatzlj@users.noreply.github.com>
hatzlj
left a comment
There was a problem hiding this comment.
I gave it another pass with further findings after the page split (which was a good move btw)
|
|
||
| This page explains how to define command handlers, handle commands, and work with the key concepts like `ProcessingContext`, `EventAppender`, and message types. | ||
|
|
||
| [TIP] | ||
| .Annotating command messages | ||
| ==== | ||
| It's recommended to annotate all command message classes with `@Command`. This allows you to: | ||
|
|
||
| * Define an explicit message type independent of the Java class name. | ||
| * Version your queries for evolution over time. | ||
| * Organize queries by bounded context using namespaces. | ||
| * Leverage payload conversion at handling time for different representations. | ||
|
|
||
| If the `@Command` annotation is omitted, Axon will default to using the fully qualified class name as the command name, which tightly couples your message identity to your Java package structure. | ||
| ==== | ||
|
|
||
| == Stateless vs stateful command handlers | ||
|
|
||
| Command handlers in Axon Framework fall into two categories: | ||
|
|
||
| * **Stateless command handlers**: Regular components (registered objects or beans) that don't maintain state in the handler itself between command invocations. | ||
| Each command is processed independently. | ||
| State may be accessed through injected services or repositories, but the handler itself doesn't manage state. | ||
|
|
||
| * **Stateful command handlers**: Components that maintain state in the handler itself across command invocations. | ||
| These are typically event-sourced entities where state is built up from events and stored in the handler instance. | ||
|
|
||
| [NOTE] | ||
| ==== | ||
| With recent versions of Axon Framework, the emphasis has shifted from modeling-centric (read: aggregate focus) to command-centric. | ||
| Entities are now understood as one implementation pattern for stateful command handling, not a core framework concept. | ||
| The focus is on handling commands effectively, with various patterns available to achieve that goal. | ||
| ==== | ||
|
|
||
| == Stateless command handlers | ||
|
|
||
| Stateless command handlers are regular components with command handling methods that don't maintain state in the handler itself. An example of command handling methods are methods annotated with `@CommandHandler` | ||
| They may access state through injected services or repositories, but the handler instance itself is stateless. | ||
| [#stateless-command-handlers] |
There was a problem hiding this comment.
Since this is the general page about Command Handlers users would land on this page when using the navigation to look for command handlers. Although i'ts a bit redundant with the information in index.adoc, I think it makes sense to put a second paragraph on the intro section here reiterating stateless and stateful, but just briefly stating that stateful handlers are covered in event-sourced-entity.adoc and command-handler-components.adoc and referencing there.
Then I would also still keep the h2 heading to introduce stateless command handlers.
| This page explains how to define command handlers, handle commands, and work with the key concepts like `ProcessingContext`, `EventAppender`, and message types. | |
| [TIP] | |
| .Annotating command messages | |
| ==== | |
| It's recommended to annotate all command message classes with `@Command`. This allows you to: | |
| * Define an explicit message type independent of the Java class name. | |
| * Version your queries for evolution over time. | |
| * Organize queries by bounded context using namespaces. | |
| * Leverage payload conversion at handling time for different representations. | |
| If the `@Command` annotation is omitted, Axon will default to using the fully qualified class name as the command name, which tightly couples your message identity to your Java package structure. | |
| ==== | |
| == Stateless vs stateful command handlers | |
| Command handlers in Axon Framework fall into two categories: | |
| * **Stateless command handlers**: Regular components (registered objects or beans) that don't maintain state in the handler itself between command invocations. | |
| Each command is processed independently. | |
| State may be accessed through injected services or repositories, but the handler itself doesn't manage state. | |
| * **Stateful command handlers**: Components that maintain state in the handler itself across command invocations. | |
| These are typically event-sourced entities where state is built up from events and stored in the handler instance. | |
| [NOTE] | |
| ==== | |
| With recent versions of Axon Framework, the emphasis has shifted from modeling-centric (read: aggregate focus) to command-centric. | |
| Entities are now understood as one implementation pattern for stateful command handling, not a core framework concept. | |
| The focus is on handling commands effectively, with various patterns available to achieve that goal. | |
| ==== | |
| == Stateless command handlers | |
| Stateless command handlers are regular components with command handling methods that don't maintain state in the handler itself. An example of command handling methods are methods annotated with `@CommandHandler` | |
| They may access state through injected services or repositories, but the handler instance itself is stateless. | |
| [#stateless-command-handlers] | |
| As explained before, command handlers can be **stateless** (not requiring any prior state) or **stateful** (depending on prior state to enforce business rules). For an explanation on stateless command handlers, consult xref:#stateless-command-handlers[the section below]. The different patterns for implementing stateful command handlers are covered in more detail in xref:entities/event-sourced-entity.adoc[Event-Sourced Entities] and xref:entities/command-handler-components.adoc[Command Handler Components]. | |
| [#stateless-command-handlers] | |
| == Stateless command handler |
|
|
||
| The `@EntityCreator` annotation tells Axon how to construct the initial entity instance before replaying its events. | ||
| It is mandatory for annotation-based entities (autodetected and Spring Boot approaches). | ||
| In the declarative approach, entity construction is handled by the factory passed to `EventSourcedEntityModule.declarative()` instead—see xref:commands:entities/event-sourced-entity.adoc#_declarative[Declarative]. |
There was a problem hiding this comment.
the #_declarative anchor should be defined explicitly on the heading
| The examples below use `@EventSourcedEntity(tagKey = "courseId")Entity`, which is the non-Spring annotation. | ||
| In Spring Boot, replace `@EventSourcedEntity(tagKey = "courseId")Entity` with `@EventSourcedEntity(tagKey = "courseId")`—the `@EntityCreator` patterns are identical. |
There was a problem hiding this comment.
The examples below use `@EventSourcedEntity(tagKey = "courseId")`, which is the non-Spring annotation.
In Spring Boot, replace `@EventSourcedEntity(tagKey = "courseId")` with `@EventSourcedEntity(tagKey = "courseId")`—the `@EntityCreator` patterns are identical.
| * xref:commands:command-handlers.adoc[Command handlers] | ||
| * xref:commands:entities/command-handler-components.adoc[Command handler components] | ||
| * xref:commands:entities/entity-hierarchies.adoc[Entity hierarchies] | ||
| * xref:commands:entities/entity-polymorphism.adoc[Polymorphic entities] | ||
| * xref:events:event-handlers.adoc[Event handlers] | ||
| * xref:events:event-publishing.adoc#_appending_events_with_metadata[Appending events with metadata]—to append metadata alongside an event, pass a `Metadata` instance as the second argument to `eventAppender.append()` | ||
| * xref:tuning:snapshotting.adoc[Snapshotting]—available as a performance optimization for entities with large event streams | ||
| * xref:testing:index.adoc[Test fixtures]—the test fixture guards against unintentional state changes in command handlers and is strongly recommended for stateful entity testing |
There was a problem hiding this comment.
to me that looks rather extensive, especially those items without an additional explanation as to why the further reading might make sense (which only the last 3 items have)
| EntityMetamodel<EnrollmentEntity> enrollmentMetamodel = ConcreteEntityMetamodel | ||
| .forEntityClass(EnrollmentEntity.class) | ||
| .instanceCommandHandler( | ||
| new QualifiedName(DropEnrollment.class), |
There was a problem hiding this comment.
Also switch to MessageTypeResolver.resolveOrThrow() here to be consistent with the declarative examples in event-sourced-entity.adoc and entity-polymorphism.adoc
Co-authored-by: Jakob Hatzl <hatzlj@users.noreply.github.com>
…rced-entity.adoc Co-authored-by: Jakob Hatzl <hatzlj@users.noreply.github.com>
This PR resolves #4060.