Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CQRS How to avoid repeating fields between command and event?

I'm implementing a project using CQRS and Event Sourcing. I realized that my commands and my events are nearly always the same.

Let's say I have a command CreatePost :

public class CreatePost implements Command {
    private final String title;
    private final String content;
}

The event fired from this command is the same :

public class PostCreated implements Event {
    private final String title;
    private final String content;
}

How do you handle that in your applications ?

EDIT : Of course I'm aware of basic OOP technics. I could create an abstraction having the common fields, but this question needs to be taken in the CQRS/ES context.

like image 883
c4k Avatar asked Jul 27 '17 13:07

c4k


4 Answers

How to avoid repeating fields between command and event?

I wouldn't -- not until I absolutely can't stand it.

Fundamentally, commands and events aren't objects, they are messages - representations of state that cross boundaries. I think it's important that your in memory representation not lose sight of that.

One of the characteristics of message schemas is that they evolve over time, so you need to be aware of compatibility. And here's the kicker: events and commands evolve on different time scales.

Command messages are how your domain model communicates with other processes; changes to that part of the API are driven by exposing/deprecating functionality.

But in an event sourced world, events are messages from previous versions of the domain to the current version. They are part of the support we need to deploy new models that resume work from where the old model left off.

So I would keep commands and events separate from one another - they are different things.

If you are seeing a lot of duplication in the fields, that may be a hint that there's some value type that you haven't yet made explicit.

CreatePost 
    { Post 
        { Title
        , Contents
        }
    }

PostCreated
    { Post 
        { Title
        , Contents
        }
    }
like image 176
VoiceOfUnreason Avatar answered Sep 23 '22 20:09

VoiceOfUnreason


Simply implement a model for your Post, i.e.:

public class PostModel {
    private String title;
    private String content;

    // Add get/set methods
}

Then re-use this in both your events and commands.

like image 28
MarioDS Avatar answered Sep 26 '22 20:09

MarioDS


Just compiling this answer from the discussion we had in comments.

Compose, don't inherit

I would definitely not use inheritance in a situation like this because it will just add unnecessary complexity, also there is no behavior to inherit there.

Another option is to have a well-defined contract for your commands and events. That is to have two interfaces — IPost and IEvent — and implement those in the commands and events.

Regarding naming: we all know that naming is hard, so you should choose names wisely, according to your business or technical language/vocabulary requirements.

Why split into two interfaces?

Because a command usually carries more information required for its handler than an event carries for its event handler, event handlers should be kept as thin as possible. It's better to carry only the needed payload.

Closing words

Separating commands and events is a must, since commands are representing an operation that's happening now, whereas events are representing actions that happened in the past. They might usually be an outcome of a command, indicating to the outside world — from the viewpoint of a bounded context — that something happened inside your current BC.

like image 23
kayess Avatar answered Sep 22 '22 20:09

kayess


How to avoid repeating fields between command and event?

Just don't. The cost of dependency + risk of wrongful mutualization are higher than the maintenance gain. You can live with that duplication, just like you probably live with duplication between your domain model, view model, query model, etc. today.

like image 21
guillaume31 Avatar answered Sep 22 '22 20:09

guillaume31