Hey,

I've been playing a bit with commands and events, and what should do what, and so on, and here's the current state of the experiment.

The domain is building up organizational structure. I have a root Organization entity, which then has a tree of OrganizationalUnits. The Organization and OU's implement "OrganizationalUnits" which is a collection-interface for managing the structure. Here is the complete example, with comments inline marked with "/* */":
@Mixins(OrganizationalUnits.OrganizationsMixin.class)
public interface OrganizationalUnits
{
/* This method is a command, and hence is of the "please do this for me" form. Validation of input handles in the command method, and ONLY in the command method. Properties may not have validation settings, and event methods may not do validation, since events are "after the fact". If the domain comes up in an inconsistent state (e.g. names over 50 chars), then compensating commands have to be issued to fix this rather than fail to load entirely. */
    @Command
OrganizationalUnit createOrganizationalUnit(@MaxLength(50) String name);

/* This is an event method. It is an "after the fact" method, and the tense used in the name follows this. It takes only one argument, which is an event object that is a subtype of DomainEvent which is a subtype of ValueComposite and Identity, signifying that it is immutable and identifiable. DomainEvent ALWAYS contains properties for date of firing and the user who fired it. Custom mandatory data can be added in subclasses. Event methods may NOT throw exceptions, and may NOT perform input data checking, since they are not allowed to say no. It *does* return the created OU, but this is for convenience of the calling command method only. @Event methods will have a SideEffect that creates a persistent event to be put on disk and distributed to whoever is interested in what is happening in the domain. */
    @Event
    OrganizationalUnit organizationalUnitCreated(CreatedEvent event);

    interface OrganizationalUnitsState
    {
        @Aggregated
        ManyAssociation<OrganizationalUnit> organizationalUnits();

    }

    class OrganizationsMixin
            implements OrganizationalUnits
    {
/* The EBF delegates to ValueBuilderFactory and sets the mandatory fields before return the builder to client code */
        @Service
        EventBuilderFactory ebf;

/* Since the command is in charge of creating the id it is now vital to inject the id-generator explicitly rather than having the UoW create id's on the fly */
        @Service
        IdentityGenerator idGenerator;

        @This
        OrganizationalUnit.OrganizationalUnitState ouState;

        @This
        OrganizationalUnitsState state;

        @Structure
        UnitOfWorkFactory uowf;

/* Create a OU with a given name. This is implemented as two events: creation of OU and then changing its name, which in turn is done as a command. So, one command may lead to several other commands being triggered, which may lead to several events being fired. Command code MAY do validation, but it MAY NOT change any state. That is only done in event methods. */
        public OrganizationalUnit createOrganizationalUnit(String name)
        {
ValueBuilder<CreatedEvent> valueBuilder = ebf.buildEvent(CreatedEvent.class);

valueBuilder.prototype().createdId().set(idGenerator.generate(OrganizationalUnitEntity.class));
OrganizationalUnitEntity ou = organizationalUnitCreated(valueBuilder.newInstance());
            ou.describe(name);
            return ou;
        }

/* This is the event that creates the OU. It is deterministic in that if we later start with an empty database and replays the events, i.e. invoke this method again with the same event, it should have the same result. The model MAY have changed though, so that the new state is different from what was created the first time. That is ok. The event method may NOT do validation or throw any exceptions. */ public OrganizationalUnitEntity organizationalUnitCreated(CreatedEvent event)
        {
EntityBuilder<OrganizationalUnitEntity> ouBuilder = uowf.currentUnitOfWork().newEntityBuilder(OrganizationalUnitEntity.class, event.createdId().get());

ouBuilder.prototype().organization().set(ouState.organization().get());
            OrganizationalUnitEntity ou = ouBuilder.newInstance();

state.organizationalUnits().add(state.organizationalUnits().count(), ou);
            return ou;
        }
    }
}
---
That's how far I've gotten right now in my thinking about commands and events, and how to implement them in a domain model.

The gains from this approach is that all state changes are explicit, making it easy to do refactoring/schema migration, since all it takes is an event replay. This can cope with quite a lot of changes in the data structure, if done properly. Also, this approach ensures that ALL data changes is done by entities, i.e. services or client code may NEVER change anything, including creating entities. The logical conclusion of this is that when you start the system you have to create a root object from which you start creating other objects. Alternatively you can auto-create entities on the fly (see Udi Dahans blog on aggregate roots for example of this). In my own case I will create a root entity with id "1" at first startup, which will not require any event. After that, all changes will be events on that entity or entities created from that entity. These events will be subscribable to from other bounded contexts, which may use them as they please.

Thoughts and comments on this?

/Rickard

_______________________________________________
qi4j-dev mailing list
[email protected]
http://lists.ops4j.org/mailman/listinfo/qi4j-dev

Reply via email to