Rinat Abdullin:  Bliki | Journal | About Me | Subscribe

Event Centric: Commands and Events

In Event-sourcing series we’ve talked a bit about commands and events. Let’s expand on this material.

Commands

There are two types of commands. There are ones that are directed to the specific entity, and there are ones that do not have a defined recipient.

Obviously, commands that are directed to the specific entity (which is identified by an identity) are interested in the state of this entity.

Entity commands:

The other type of commands is directed to the stateless services that operate in purely functional approach. They don’t have a state and usually perform an operation or a calculation.

Stateless commands:

NB: obviously there are commands that seem to be falling somewhere between these two categories (i.e. when we are sending them to stateful 3rd party services). These are to be discussed later.

Events

Like commands, events can be grouped between two generic types:

Code definitions

Having said all that, here’s how we can define a command for an entity:

[DataContract]
public partial class CreateStore : ICommand<StoreId>
{
    [DataMember(Order = 1)] public StoreId Id;
    [DataMember(Order = 2)] public string Name;
    [DataMember(Order = 3)] public IntegrationId IntegrationId;
 }

Note, that this is a command directed to Store which is identified by StoreId. It also holds a reference to some integration entity, which is identified by IntegrationId.

Such a command, could probably cause an event like this:

[DataContract]
public partial class StoreCreated : IEvent<StoreId>
{
    [DataMember(Order = 1)] public StoreId Id;
    [DataMember(Order = 2)] public string Name;
    [DataMember(Order = 3)] public IntegrationId IntegrationId;
    [DataMember(Order = 4)] public DateTime CreatedUtc;
}        

Where IEvent[TIdentity] and ICommand[TIdentity] interfaces are defined as:

public interface ICommand<out TIdentity> : IProjectCommand
    where TIdentity : IIdentity
{
    TIdentity Id { get; }
}


public interface IEvent<out TIdentity> : IProjectEvent
    where TIdentity : IIdentity
{
    TIdentity Id { get; }
}

Strong-typing

Such strong typing has an important effect. It allows to limit number of messages available within a given scope (making code more error prone and readable).

// TODO: expand on strongly-typed interfaces

Code Generation

In event sourcing section we’ve talked a bit about code generation approach that would work in any language and would allow us to quickly define our commands and messages.

Basic syntax could be expanded with a few more constructs for better expressiveness. For instance, message constructs above could be expressed as:

entity Store (StoreId Id);

using ? = ICommand<StoreId>;
using ! = IEvent<StoreId>;

CreateStore?(string name, IntegrationId integration)
StoreCreated!(string name, IntegrationId integration, DateTime createdUtc)

// all messages declared below will have Id member
// and one of two base interfaces 

Duality

// TODO: talk about logical duality between entity messages and stateless messages. How they could be used to build distributed systems (mixing rich behavior logic with elastically scalable big data processing in purely functional style)