Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce annotations and types for CQRS / Event Sourcing #18

Closed
odrotbohm opened this issue Sep 23, 2020 · 8 comments
Closed

Introduce annotations and types for CQRS / Event Sourcing #18

odrotbohm opened this issue Sep 23, 2020 · 8 comments
Assignees
Labels
module: cqrs / es CQRS and Event Sourcing support type: enhancement New feature or request
Milestone

Comments

@odrotbohm
Copy link
Member

I just spoke to @abuijze of Axon Framework and we wondered whether it'd make sense to introduce annotations and types to declare CQRS / Event Sourcing building blocks:

  • @Command – type annotation
  • @CommandHandler – method annotation
  • @(Domain)EventHandler – method annotation
  • @ViewModel / @Projection – type annotation

Axon also provides annotations for querying:

  • @Query
  • @QueryHandler

but they seem to be a little more specific to Axon rather than a CQRS / ES concept that is to be mapped to types and packages in general.

Open questions

  1. Should this be a dedicated artifact (jddd-cqrs) or a part of the already existing jddd-architecture artifact. As using CQRS / ES as implementation is a pretty significant decision, I personally tend to vote for the former as I wouldn't want to impose the types on the classpath of someone who just pulled in the jddd-architecture artifact on the classpath to e.g. demarcate layers.
  2. Axon currently provides @EventHandler but we have chosen @DomainEvent in the jddd-events module. Thus, I'd vote to name the corresponding handler annotation @DomainEventHandler for consistency.
  3. @ViewModel or @Projection? I tend to vote for the former.
@StephanPirnbaum
Copy link
Collaborator

StephanPirnbaum commented Oct 2, 2020

Just a few thoughts on this:

  1. The developer wouldn't pull jddd-architecture into the project, but rather jddd-architecture-layered or, as with cqrs, jddd-achitecture-cqrs. So IMHO it'd be fine from this perspective. As implementing CQRS or ES in the system is an architectural decision and it has a direct effect on the implementation, putting it into jddd-architecture looks at least to me not wrong. One could argue that then also the core DDD annotations should be inside jddd-architecture. However, using CQRS and ES are additions when using DDD (could even be used without DDD), the same holds for the technical architecture style. I'd like to raise the question whether jddd is still the correct base when we start introducing additional patterns, since it suggests a string DDD focus.

  2. We should stay consistent and thus I prefer @DomainEventHandler.

  3. '@viewmodel' also for me

@odrotbohm
Copy link
Member Author

The developer wouldn't pull jddd-architecture into the project, but rather jddd-architecture-layered or, as with cqrs, jddd-achitecture-cqrs. So IMHO it'd be fine from this perspective. As implementing CQRS or ES in the system is an architectural decision and it has a direct effect on the implementation, putting it into jddd-architecture looks at least to me not wrong. One could argue that then also the core DDD annotations should be inside jddd-architecture. However, using CQRS and ES are additions when using DDD (could even be used without DDD), the same holds for the technical architecture style. I'd like to raise the question whether jddd is still the correct base when we start introducing additional patterns, since it suggests a string DDD focus.

Good points. I'll try to approach them one by one:

  1. The artifact naming discussion – I oversaw that we're planning with artifacts by architectural style. A jddd-architecture-cqrs would thus fit nicely.
  2. Is CQRS / ES an "architecture" – I think the CQRS part pretty clearly is as it has implications on the overall structure of the codebase, kind of splitting it into two different worlds. For the ES part, I'm not so sure as it's essentially an implementation strategy for repositories: "We reestablish state based on the reapplication of events we have stored". I.e. a repository client shouldn't necessarily have to know about it being implemented via ES or destructive persistence.
  3. The architecture artifact arrangement in general – I've seen the 'architecture' artifacts as "Stereotypes that help describing architectures commonly used in DDD context". While I agree that you can use those architectures without doing DDD, that is sort of expressed by the fact that these artifacts do not depend on jddd-core. I think it's fine to then ask whether these annotations should be part of either this project or something named jddd in the first place but it feels like that's getting into very detailed discussion, esp. as the project already is nothing more than an implementation of commonly used patterns in code. Happy to think about a rename / restructuring at some point, but I would like to get more feedback on whether the core idea ("Does a meta model separated from frameworks?") provide real benefit to both users and framework implementors first.

In summary, I wonder if a slightly different arrangement of annotations and artifacts makes sense and matches the observations a bit better:

  1. Add @DomainEventHandler to jddd-events instead of the artifact. It would colocate everything related to handling events in the artifact designed to contain those. Would @ViewModel go here then as well? It nudges the jddd-events artifact towards event source quite a bit but at the same time it feels a bit overly complex to introduce a separate artifact just for that.
  2. Let the CQRS architecture artifact contain all command and query annotations (do we actually want to add the latter in the first pass?).

@DomainEventHandler

👍

@ViewModel

👍

@OLibutzki
Copy link

OLibutzki commented Oct 29, 2020

As I build a CQRS based system I just would like to share which building blocks we use. The naming evolved incrementally over months as we refactored constantly.

This is the current state:
Command - The command itself
CommandHandler - The component handling a given command
Local event - Events which are not supposed to be propagated to the outside world. They are used for EventSourcing an Aggregate.
Global event - Propagated to the outside world. "Domain event" might be more appropriate.
Event Handler - The component handling events
Projection - That's the term we refactored most often. It started with Read Model and ended it with Projection. We don't use ViewModel because the term is linked to the UI world closely. A projection can feed an UI, but it doesn't have to. We use projections a lot to build views on data which is exposed by other bounded context in order to decouple the BCs.
Projector - A projector is responsible for performing CRUD operations against the projection. It's more or less an Event Handler. As it handles all the events which are relevant for keeping the projection up to date.

We also use Queries and Query handlers, but most of the time we don't need them. Querying the projection repository is fine without having a dedicated building block.

Hope this helps...

@odrotbohm
Copy link
Member Author

Sounds like we're in line to a large degree. I guess that for your global events you could got with jMolecules @DomainEvent as they're likely to be picked up by downstream tools for documentation.

I like the suggestion to move to @ReadModel over @ViewModel for exactly the arguments brought up.

@odrotbohm
Copy link
Member Author

@abuijze and team – I wouldn't mind your feed back on this and what's been suggested in #39 to make sure we're not fundamentally at odds with what you have in Axxon. Of course, still assuming that developers might want/need to fall back onto Axxon specific annotations for more advanced use case. I hate to bring up this comparison but see this here as the "JPA" compared to "Hibernate" of CQRS / ES building block definitions. 😉

@abuijze
Copy link

abuijze commented Dec 18, 2020

Hi @odrotbohm and others here. Sorry for being late to the game.
Actually, the JPA/Hibernate comparison isn't too far off. I have been discussing different forms of standardization already with other suppliers of "CQRS tooling", but those discussions were too much into defining what frameworks must do, instead of stereotyping components, like this module seems to focus on.

I agree with many of the conclusions taken here. Just for completeness, here my 2ct on them:

  • Artifact naming -> don't have too strong an opinion on this one. CQRS is often referred to as an architectural style, rather than an architecture, but I don't think that is relevant for the naming discussion. If one intends to use CQRS as a "component" in an application's architecture, it makes sense to include a jddd-architecture-cqrs module to annotate the relevant components.
  • ViewModel/Projection/ReadModel -> my preference goes strongly to ReadModel, or alternatively QueryModel. ViewModel implies that it's used to feed a View, which in turn implies that an external actor is using this for information. That doesn't need to be the case. Projection implies that is has been projected from a (generally) stream of information. Strictly speaking in CQRS, this also doesn't need to be the case. ReadModel implies that the model is focused on Reading, which seems the most accurate. However, CQRS is not called Write-Read Responsibility Segregation. Therefore, I believe QueryModel is even more accurate.
  • DomainEvent/Event and DomainEventHandler/EventHandler -> Event can mean many things. I agree with using DomainEvent for this. Regarding (Domain)EventHandler, while consistency is important, I'm not too sure about naming it DomainEventHandler. An Event Handler can handle Events, whether they are considered Domain Events, Application Events, or System Events. While I've seen the latter pop up more in discussions than in real code bases, Application Events are very common (Spring uses them to notify applications of the ApplicationContext lifecycle changes, for example). Some Projectors may want to use these Events too in their logic. My vote would go for EventHandler.

I just wanted to provide a little context here before I dive into the PR (#39) that's already open for this.

@abuijze
Copy link

abuijze commented Dec 18, 2020

Almost forgot the last one: Query / Query Handler.

I think it's important to include these. While Axon is quite opinionated and suggests using explicit Query objects, I think the concepts are more generally beneficial. A QueryHandler doesn't have to be a handler for these explicit query objects. It could simply mark an endpoint that is used to expose the query model to other components. Whether that's through explicit message objects (themselves marked with @Query), or just an HTTP endpoint, is irrelevant.

Maybe just a fun fact, but explicit Query objects have only been added relatively recently to Axon Framework. I didn't see the need for them for a long time. It is under "community pressure" that we decided to add the QueryBus and Query Messages. And I have to admit: they were right!

odrotbohm pushed a commit that referenced this issue Jan 8, 2021
We no provide annotations to express CQRS concepts like commands, command handlers, dispatchers and query models in application code. See the Javadoc of the introduced annotations for details.

Also @domainevent was extended to carry new, optional attributes for symmetry with what's available for commands.
@odrotbohm
Copy link
Member Author

That's available now.

@odrotbohm odrotbohm added module: cqrs / es CQRS and Event Sourcing support type: enhancement New feature or request labels Jan 11, 2021
odrotbohm added a commit that referenced this issue Feb 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
module: cqrs / es CQRS and Event Sourcing support type: enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants