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.

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
        }
    }

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.

You can use whatever you want as long as it is just an implementation detail.

In PHP I use a lot traits for this kind of reusability. You can use even inheritance but the clients (the code that uses those classes) should not depend on the base class; it would be best if they even don’t find out that your event and command class share something but I don’t have enough Java experience to tell you how to do it.

P.S. I would not go with creating interfaces, as I specified above, this should be just an implementation detail.

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.

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.