xmolecules / jmolecules

Libraries to help developers express architectural abstractions in Java code
http://jmolecules.org
Apache License 2.0
1.25k stars 104 forks source link

Introduce annotations and types for CQRS / Event Sourcing #18

Closed odrotbohm closed 3 years ago

odrotbohm commented 4 years ago

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:

Axon also provides annotations for querying:

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 3 years ago

@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 commented 3 years ago

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:

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

abuijze commented 3 years ago

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 commented 3 years ago

That's available now.