Code Duplication between Aggregates, Command Classes and Event Classes

Hello,

I’m a first-time poster that’s evaluating Axon for a large scale deployment. I don’t pretend to be an expert in DDD, Event Sourcing or CQRS, so please excuse my ignorance.

I find myself duplicating code when writing Aggregates, Commands and Events. The bounded context I’m implementing is very complex, with many Entities and nested Value Objects. I can imagine keeping all of these classes in sync will be a nightmare as we iterate on the system. The Axon example project clearly demonstrates the problem:

data class IssueCmd(@TargetAggregateIdentifier val id: String, val amount: Int)
data class IssuedEvt(val id: String, val amount: Int)

public class GiftCard {

@AggregateIdentifier
private String id;
private int remainingValue;


}

In basic cases where the aggregate only has a few members, this isn’t so bad, but I’m not fortunate enough to work in that problem space. Has anyone found a way to share models and still achieve the benefits of ES/CQRS?

Jayson,

I’m new to all of this, having only installed and modified the demo. However, I don’t see a need to keep a complete list of properties sync’ed between the Aggregate, and associated Commands/Events. The Aggregate will, of course, have the big list of properties. However, the Commands and Events only need to worry about the properties involved in state change.

For example, suppose one were to modify the giftcard demo to add properties to the Giftcard such as “currency”, “issuingRetailer”, and “color”. The CommandHandler, EventSourcingHandler, and EventHandler for RedeemEvt would not necessarily need to change. The related commands and events wouldn’t need to be aware of currency, the issuing retailer, or the color of the card. They just address the items involved in the state change for the type of command/event.

Yes, and if you have a REST api, you will also very likely replicate the model objects. And if you persist your projections you will also replicate in perhaps JPA entities.
All more or less the same, with slight variances on the format and properties. like additional annotations (JPA, Jackson). On top you will need mappers/converters between these objects.
It’s very much a topic, which concerns me as well, but to be fair, if the application was non-Axon, it would be very much the same situation, perhaps except the
Aggregate. This is the price you pay for a de-coupled, multi-tier application with a typed language like Java…

The solution, I tend to lean on, is to generate model objects from schema’s like using the OpenApi specification, and generating at least the REST side of things.
This could be taken further, by also code generating all the Axon Artifacts, purely driven from REST API design… but we are not there yet.

If you are interested we could explore further. One caveat is that the code templates from Open Api Spec, are based on mustache templates, which is a great format,
but very limited IDE support, hence a nightmare to edit. Having said that, I can easily imagine a mustache template which generates, commands, queries, events and JPA entities for
CRUD like operations…all kept in sync. by domain specifications.

HTH, Christophe

Thanks for the suggestions, Jonathan and Christophe.

However, the Commands and Events only need to worry about the properties involved in state change.

This is certainly true for alterations to an existing aggregate, but for first-time aggregate creation and hydration, the commands/events can be quite large for more complex bounded contexts. I suppose I could artificially break initial creation up by introducing a Saga to generate many commands against the aggregate, but this doesn’t pass my sniff test.

This is the price you pay for a de-coupled, multi-tier application with a typed language like Java

I’ve come to the same realization, Christophe. I thought about generating a ton of abstract classes and then using variable hiding in the concrete class so that the annotations can be placed on the appropriate data members. I think this would work, but will sacrifice code readability/maintainability.

The solution, I tend to lean on, is to generate model objects from schema’s like using the OpenApi specification, and generating at least the REST side of things.

I’m not sure I’m following you 100%, but I’ve definitely used Jackson plenty to serialize/deserialize JSON, and I think it would be a good mapping solution from class to class, if I were always willing to serialize to JSON first, and then deserialize to a different class type.

Here’s what I’ve come up with as a mitigation (not a solution):

  1. I noticed the Axon developers obviously recognize this problem, and are using Kotlin to cut down on boilerplate code in these POJOs. I plan to start doing the same, or leveraging Lambok more.

  2. Similar to your OpenAPI recommendation, if I understand your suggestion correctly, I’m using the MapStruct library to easily map an object to a different class. By configuring it properly, you can have it ignore members that don’t map across classes, giving me similar characteristics to JSON that protect the code in case some of these classes evolve independently of each other. I like this library because it generates code using the annotations and interface you define for the mapping, so you can see what it’s doing at build time instead of getting surprised in production.
    Luckily I’m just evaluating Axon right now, so I can always refactor this code, if I can find a better way before it gets into production.

Hi Jayson,

I might save you some time, I’ve got a couple of links saved
regarding “domain objects on the wire” and similar topics.
From the ddd/cqrs mailing list:

https://groups.google.com/forum/#!topic/dddcqrs/LNNIDqT7Kvc
https://groups.google.com/forum/#!topic/dddcqrs/rHIek-5myx0
https://groups.google.com/forum/#!searchin/dddcqrs/dto$20types|sort:date/dddcqrs/S-7aVu2BNl4
https://groups.google.com/forum/#!searchin/dddcqrs/value$20object$20in$20projection|sort:date/dddcqrs/izABxRdgPv4/ewblkoBTMxIJ
https://buildplease.com/pages/vos-in-events/
https://seabites.wordpress.com/2012/06/18/value-objects-in-an-eventsourced-domain-model/

Also from this mailing list some older discussion:
https://groups.google.com/forum/#!searchin/axonframework/coupling|sort:date/axonframework/j9z5nR6rIUM/N4ULU0CdEQAJ

Hi everybody,

I’d like to point out this is a very worthwhile, well grounded discussion which is being had here.

The duplication is a very obvious pain point for every programmer; we’re always told that duplication is bad, so of course this approach feels off.
This duplication is, as has been pointed out earlier as well, the mechanism to decouple the components within your application.

Strictly following this pattern will in the end allow you to segregate each component in your application into it’s own (micro)service.
This notion is, I think, the strong suit of taking this route.
Yes, it comes with duplication, but it also provides a lot of flexibility to perform major restructuring later on.

That’s my two cents to the situation.

Cheers,

Steven van Beelen

Axon Framework Lead Developer

AxonIQ