CQRS commands and events as generic classes?

In most of the examples I've seen, commands and events are represented as classes. This means that you need to write a CorrectNameCommand class named name and a NameCorrectedEvent class with a name property. Given that in most cases both commands and events are serialized and deserialized and dispatched to other parties (compile-time type safety occurs), what is the advantage of these explicit classes over the more general class?

Example:

A command class with a name (representing the command type), an ag key that should handle the command, and an array of objects or name / value pairs for any other parameters.

The event class is essentially the same (perhaps we can put the common parts in the CommandEventBase class).

Command (and event) handlers must now check the command name (event) instead of their class type and must rely on the correct parameters in the list (for example, the deserializer must rely on the serialized format to be correct).

Is this a good approach? If so, why isn't it used in samples and tutorials? If not, what are the problems?

+3


source to share


1 answer


Duplication

It's fair that when commands and events are serialized, compile-time safety is lost, but in a statically typed language, I still prefer strongly typed command and event types.

The reason for this is that it gives you one part of the codebase that is responsible for interpreting message elements. Serialization tends to be quite (type) safe; deserialization is where you might run into problems.

However, I would prefer to deal with such problems in one place rather than spreading across the entire code base.

This is especially true for events, because you can have multiple event handlers handling the same type of events. If you think of events as loosely typed dictionaries, you need to duplicate the Tolerant Reader implementation in each event handler.

On the other hand, if you are handling events and commands as strong types, your deserializer may be the only tolerant reader you need to support.

Types



All that said, I can understand why you in languages ​​like C # or Java find that defining immutable DTOs for each post seems like a lot of overhead:

public sealed class CorrectNameCommand
{
    private readonly string userId;
    private readonly string newName;

    public CorrectNameCommand(string userId, string newName)
    {
        this.userId = userId;
        this.newName = newName;
    }

    public string UserId
    {
        get { return this.userId; }
    }

    public string NewName
    {
        get { return this.newName; }
    }

    public override bool Equals(object obj)
    {
        var other = obj as UserName;
        if (other == null)
            return base.Equals(obj);

        return object.Equals(this.userId, other.userId)
            && object.Equals(this.newName, other.newName);
    }

    public override int GetHashCode()
    {
        return this.userId.GetHashCode() ^ this.newName.GetHashCode();
    }
}

      

It really seems like a lot of work .

This is why I prefer other languages ​​to implement CQRS these days. In .NET, F # is perfect because all of the above codes boil down to this one line :

type CorrectNameCommand = { UserId : string; NewName : string }

      

This is what I would do instead of skipping loosely typed dictionaries. The last time I heard Greg Young talk about CQRS (NDC Oslo 2015), he seems to have "converted" to F #.

+6


source







All Articles